#include "ktkProgram.h" #include int ktk_current_depth = 0; const struct ktkProgram ktk_PROGRAM_DEFAULT = { NULL, // *structures NULL, // **char of structure names 0 // count of above fields }; int ktk_freeProgram(struct ktkProgram *program) { int i; if (program->structure_count < 1) return 1; for (i = 0; i < program->structure_count; i++) { //ktk_deleteStructure(program->structures[i]); free(program->structure_name[i]); } free(program->structures); free(program->structure_name); return 0; } int ktk_runProgram(struct ktkProgram *program, struct ktkMap *map) { int i, j; for (i = 0; i < program->structure_count; i++) { printf("%d: %s\n", i, program->structure_name[i]); printf("x(%d-%d): %d\n", program->structures[i].x.a, program->structures[i].x.b, ktk_rollNumber(program->structures[i].x)); printf(" rel: "); for (j = 0; j < program->structures[i].relation_count; j++) { printf(" %d: %s\n", j, program->structures[i].relations[j].name); } printf("\n"); } return 0; } struct ktkStructure *ktk_getStructure(struct ktkProgram *program, const char *structure_name) { int i; for (i = 0; i < program->structure_count; i++) { if (strcmp(program->structure_name[i], structure_name) == 0) { return &program->structures[i]; } } return NULL; } struct ktkMap *ktk_buildStructure(struct ktkProgram *program, struct ktkStructure *structure, struct ktkMap *orig_map) { // limit our depth to avoid endless processing / seg fault ktk_current_depth++; if (ktk_current_depth >= ktk_LIMIT_DEPTH) { printf("WARNING, depth limit %d exceeded, trashing structure %s\n", ktk_LIMIT_DEPTH, structure->name); return orig_map; } int retry_limit = 64; int retry_count = 0; // retry is used if the structure is not allowed to overlap/replace/etc. while (retry_count < retry_limit) { retry_count++; int x, y; // outcome structure position int w, h; // outcome structure size int id_1, id_2; // outcome structure ids // roll our position x = ktk_rollNumber(structure->x); y = ktk_rollNumber(structure->y); // resize according to parent's size if we're using percentages if (structure->x.type & ktk_PERCENT) { x = x * orig_map->w / 100; } if (structure->y.type & ktk_PERCENT) { y = y * orig_map->h / 100; } // roll our size w = ktk_rollNumber(structure->size_x); h = ktk_rollNumber(structure->size_y); // reposition according to parent's size if we're using percentages if (structure->size_x.type & ktk_PERCENT) { w = w * orig_map->w / 100; } if (structure->size_y.type & ktk_PERCENT) { h = h * orig_map->h / 100; } // *** step 1: create basic shape // generate the shape map struct ktkMap shape_map = ktk_MAP_DEFAULT; ktk_resizeMap(&shape_map, w, h); // now we generate the basic "shape map" we want if (structure->flags & ktk_STRUCTURE_CIRCLE) { ktk_fillEllipse(&shape_map, 0, 0, w-1, h-1); } else if (structure->flags & ktk_STRUCTURE_RECT) { ktk_fillRect(&shape_map, 0, 0, w, h); } // *** step 2: manipulate basic shape // apply post-processing to the shape map for borders, etc. if (structure->flags & ktk_STRUCTURE_BORDER) { struct ktkMap temp_map = ktk_MAP_DEFAULT; temp_map.flags |= ktk_MAP_RESIZE; // use the shape's cells to generate a border to temp ktk_borderCells(&shape_map, &temp_map); // delete shape map and replace with the temp ktk_deleteMap(&shape_map); ktk_resizeMap(&shape_map, w, h); ktk_copyMap(&temp_map, &shape_map); // delete temp ktk_deleteMap(&temp_map); } // *** step 3: create map from shape map, rolling IDs as we do struct ktkMap structure_map = ktk_MAP_DEFAULT; ktk_resizeMap(&structure_map, w, h); int px, py; for (px = 0; px < w; px++) { for (py = 0; py < h; py++) { if (shape_map.cell[px][py].flags & ktk_CELL_EMPTY) continue; structure_map.cell[px][py].id_1 = ktk_rollNumberSet(structure->id_1); structure_map.cell[px][py].id_2 = ktk_rollNumberSet(structure->id_2); structure_map.cell[px][py].flags &= ~ktk_CELL_EMPTY; } } ktk_deleteMap(&shape_map); // *** step 4: recursively create sub-structures int i; for (i = 0; i < structure->relation_count; i++) { struct ktkRelation *relation = &structure->relations[i]; int roll_count = ktk_rollNumber(relation->count); int r; for (r = 0; r < roll_count; r++) { struct ktkStructure *get_structure = ktk_getStructure(program, relation->name); if (get_structure == NULL) continue; // TODO: add error struct ktkStructure rel_structure = *get_structure; // inherit structure flags from relation rel_structure.flags |= relation->flags; if (relation->x.type & ktk_ISSET) { rel_structure.x = relation->x; } if (relation->y.type & ktk_ISSET) { rel_structure.y = relation->y; } //rel_structure.size_x = relation->size_x; //rel_structure.size_y = relation->size_y; ktk_buildStructure(program, &rel_structure, &structure_map); //ktk_buildStructure(program, &rel_structure, &structure_map); } } // *** step 5: retry if we've overlapped when we're not supposed to // set offset x,y for later merge structure_map.x = x; structure_map.y = y; if (structure->flags & ktk_STRUCTURE_ORIGIN) { structure_map.x -= w/2; structure_map.y -= h/2; } if (structure->replace_id_1.count > 0) { // TEMP int px, py; for (px = 0; px < structure_map.w; px++) { if (x+px >= orig_map->w) continue; for (py = 0; py < structure_map.h; py++) { if (y+py >= orig_map->h) continue; int r_i; for (r_i = 0; r_i < structure->replace_id_1.count; r_i++) { int r_s = structure->replace_id_1.sets[r_i].a; int r_e = structure->replace_id_1.sets[r_i].b; int r_id; for (r_id = r_s; r_id <= r_e; r_id++) { if (orig_map->cell[x+px][y+py].id_1 == r_id) { orig_map->cell[x+px][y+py].id_1 = structure_map.cell[px][py].id_1; } } } } } } else if (structure->flags & ktk_STRUCTURE_OVERLAP) { ktk_mergeMaps(orig_map, &structure_map); ktk_deleteMap(&structure_map); break; } else if (ktk_checkMapOverlap(orig_map, &structure_map) == 0) { ktk_mergeMaps(orig_map, &structure_map); ktk_deleteMap(&structure_map); break; } // if we reached here, that means we could not find a spot to draw ktk_deleteMap(&structure_map); } ktk_current_depth--; return orig_map; } /* struct ktkMap *ktk_buildStructure(struct ktkProgram *program, struct ktkStructure *structure, struct ktkMap *orig_map) { if (ktk_current_depth >= ktk_LIMIT_DEPTH) return orig_map; ktk_current_depth++; struct ktkMap map = ktk_MAP_DEFAULT; map.flags |= ktk_MAP_RESIZE; if (structure == NULL) { return orig_map; } // If a structure does not have a placement flag, it will be attempted to be placed multiple times. int retry_limit = 8; int retry = 0; while(retry < retry_limit) { int x, y, size_x, size_y; // positioning logic x = ktk_rollNumber(structure->x); if (structure->x.type & ktk_PERCENT) { x = x * orig_map->w / 100; } y = ktk_rollNumber(structure->y); if (structure->y.type & ktk_PERCENT) { y = y * orig_map->h / 100; } map.x = x; map.y = y; size_x = ktk_rollNumber(structure->size_x); printf("prex: %d * %d / 100\n", size_x, orig_map->w); if (structure->size_x.type & ktk_PERCENT) { size_x = size_x * orig_map->w / 100; } size_y = ktk_rollNumber(structure->size_y); printf("prey: %d * %d / 100\n", size_y, orig_map->h); if (structure->size_y.type & ktk_PERCENT) { size_y = size_y * orig_map->h / 100; } printf("creating: %dx%d\n", size_x, size_y); // begin generation ktk_resizeMap(&map, size_x, size_y); // position logic if (structure->flags & ktk_STRUCTURE_ORIGIN) { map.x += size_x/2; map.y += size_y/2; } // shape logic // we use a separate shape map to get the workable area before drawing //struct ktkMap shape_map = ktk_MAP_DEFAULT; //ktk_resizeMap(&shape_map, size_x+1, size_y+1); if (structure->flags & ktk_STRUCTURE_CIRCLE) { ktk_fillEllipse(&map, 0, 0, size_x-1, size_y-1); } else if (structure->flags & ktk_STRUCTURE_RECT) { ktk_fillRect(&map, 0, 0, size_x, size_y); } if (structure->flags & ktk_STRUCTURE_BORDER) { struct ktkMap border_map = ktk_MAP_DEFAULT; border_map.flags |= ktk_MAP_RESIZE; ktk_borderCells(&map, &border_map); ktk_deleteMap(&map); ktk_resizeMap(&map, size_x, size_y); //map->flags &= ~ktk_MAP_RESIZE; ktk_mergeMaps(&map, &border_map); //map->flags |= ktk_MAP_RESIZE; ktk_deleteMap(&border_map); } // fill logic // if (structure->flags & ktk_STRUCTURE_FILL) { int px, py; for (px = 0; px < size_x; px++) { for (py = 0; py < size_y; py++) { if (map.cell[px][py].flags & ktk_CELL_EMPTY) continue; map.cell[px][py].id_1 = ktk_rollNumberSet(structure->id_1); map.cell[px][py].id_2 = ktk_rollNumberSet(structure->id_2); map.cell[px][py].flags &= ~ktk_CELL_EMPTY; } } // relations int i; int r_x, r_y; // relation x, y int r_size_x, r_size_y; // relation size struct ktkMap snapshot = ktk_MAP_DEFAULT; ktk_resizeMap(&snapshot, map.w, map.h); printf("snapshot wxh: %dx%d\n", snapshot.w, snapshot.h); ktk_mergeMaps(&snapshot, &map); snapshot.flags |= ktk_MAP_RESIZE; for (i = 0; i < structure->relation_count; i++) { struct ktkRelation *relation = &structure->relations[i]; printf("running relation: %d:%s\n", i, relation->name); // we tack on relation's flags to a new structure based on the target struct ktkStructure *get_structure = ktk_getStructure(program, relation->name); if (get_structure == NULL) continue; // TODO: add error struct ktkStructure rel_structure = *get_structure; rel_structure.flags |= relation->flags; rel_structure.x = relation->x; rel_structure.y = relation->y; printf("--dump--\n"); ktk_dumpStructure(&rel_structure); int roll_count = ktk_rollNumber(relation->count); int r; for (r = 0; r < roll_count; r++) { int retry_limit = 8; struct ktkMap temp = ktk_MAP_DEFAULT; ktk_resizeMap(&temp, snapshot.w, snapshot.h); ktk_mergeMaps(&temp, &snapshot); //temp.flags |= ktk_MAP_RESIZE; printf("temp wxh: %dx%d\n", temp.w, temp.h); //temp.x = snapshot.x; //temp.y = snapshot.y; ktk_buildStructure(program, &rel_structure, &temp); if (rel_structure.flags & ktk_STRUCTURE_CONSTRAIN) { map.flags &= ~ktk_MAP_RESIZE; } if (rel_structure.flags & ktk_STRUCTURE_OVERLAP || ktk_checkMapOverlap(&map, &temp) == 0) { ktk_mergeMaps(&map, &temp); } if (rel_structure.flags & ktk_STRUCTURE_CONSTRAIN) { map.flags |= ktk_MAP_RESIZE; } ktk_deleteMap(&temp); } } ktk_deleteMap(&snapshot); if (structure->flags & ktk_STRUCTURE_OVERLAP || ktk_checkMapOverlap(orig_map, &map) == 0) { ktk_mergeMaps(orig_map, &map); printf("no overlap found or flag is set\n"); break; } else { printf("overlap found\n"); retry++; ktk_deleteMap(&map); } } ktk_deleteMap(&map); ktk_current_depth--; return orig_map; }*/