From 00b4a72fd839de33e545795696fd8c71236a589a Mon Sep 17 00:00:00 2001 From: kts Date: Mon, 17 Nov 2014 00:12:37 -0800 Subject: [PATCH] Initial commit of the procedural generation syntax library - possesses majority of the basic structure generation codebase, but is lacking the pathing portion (keep posted) --- .gitignore | 2 + Makefile | 26 +++ ktkMap.c | 467 +++++++++++++++++++++++++++++++++++++++++++++++++ ktkMap.h | 89 ++++++++++ ktkProgram.c | 324 ++++++++++++++++++++++++++++++++++ ktkProgram.h | 31 ++++ ktkStructure.c | 134 ++++++++++++++ ktkStructure.h | 104 +++++++++++ ktk_parse.c | 290 ++++++++++++++++++++++++++++++ ktk_parse.h | 31 ++++ logic.txt | 66 +++++++ main.c | 38 ++++ notes.txt | 127 ++++++++++++++ parse.c | 3 + test.txt | 100 +++++++++++ todo.txt | 26 +++ 16 files changed, 1858 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 ktkMap.c create mode 100644 ktkMap.h create mode 100644 ktkProgram.c create mode 100644 ktkProgram.h create mode 100644 ktkStructure.c create mode 100644 ktkStructure.h create mode 100644 ktk_parse.c create mode 100644 ktk_parse.h create mode 100644 logic.txt create mode 100644 main.c create mode 100644 notes.txt create mode 100644 parse.c create mode 100644 test.txt create mode 100644 todo.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f31b3e2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +*.swp diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..36cec84 --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ +CC = gcc +BINARY = main +OBJS = main.o ktkMap.o ktkStructure.o ktkProgram.o ktk_parse.o +CFLAGS = -Wall -g -c +LFLAGS = -Wall + +$(BINARY): $(OBJS) + $(CC) $(OBJS) $(LFLAGS) -o $(BINARY) + +clean: + rm $(BINARY) $(OBJS) + +main.o: main.c ktkMap.c ktkMap.h ktk_parse.h + $(CC) $(CFLAGS) main.c + +ktkMap.o: ktkMap.c ktkStructure.h + $(CC) $(CFLAGS) ktkMap.c + +ktkStructure.o: ktkStructure.h ktkStructure.c + $(CC) $(CFLAGS) ktkStructure.c + +ktk_parse.o: ktk_parse.h ktk_parse.c ktkProgram.h ktkStructure.h + $(CC) $(CFLAGS) ktk_parse.c + +ktkProgram.o: ktkProgram.h ktkProgram.c ktkStructure.h + $(CC) $(CFLAGS) ktkProgram.c diff --git a/ktkMap.c b/ktkMap.c new file mode 100644 index 0000000..d50b8e0 --- /dev/null +++ b/ktkMap.c @@ -0,0 +1,467 @@ +#include "ktkMap.h" +#include // malloc +#include // printf, remove +#include // round + +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +const declarations, etc. +```````````````````````````````` */ +const struct ktkMap ktk_MAP_DEFAULT = { + 0, + 0, 0, + 0, 0, + NULL +}; +const struct ktkCell ktk_CELL_DEFAULT = { + 0, 0, // id_1, id_2 + NULL, 0, ktk_CELL_EMPTY|ktk_CELL_CELL_DELETE, // data, size, flags + NULL, 0 // contained cell(s), count of contained +}; +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Functions +```````````````````````````````` */ +/*int ktk_resizeMap(struct ktkMap *map, int w, int h) { + int x, y; + int delta_w = w - map->w; + int delta_h = h - map->h; + if (w < 0 || h < 0) return 1; + // delete out of bound cells. + if (delta_w < 0) { + for (x = map->w-1; x > w; x--) { + for (y = map->h-1; y > h; y--) { + ktk_deleteCell(&map->cell[x][y]); + } + } + } + if (delta_h < 0) { + for (y = map->h-1; y > h; y--) { + for (x = map->w-1; x > w; x--) { + ktk_deleteCell(&map->cell[x][y]); + } + } + } + // free out of bound cells + for (x = w; x < map->w; x++) { + free(map->cell[x]); + } + // resize :) + if ((map->cell = realloc(map->cell, w * sizeof(struct ktkCell*))) != NULL) { + if (delta_w > 0) { + for (x = map->w; x < w; x++) { + if ((map->cell[x] = malloc(h * sizeof(struct ktkCell))) == NULL) { + // uhoh, ran out of memory. Report error, but set width to as far as we got + w = x; + int xf = x; + for (xf = x; xf > 0; xf--) { + free(map->cell[xf]); + } + break; + } + } + } + + } else { + // major problem, couldn't realloc at all. Cancel operation. :S + // TODO: set error code? + return 2; + } + // realloc old x pointers if height has grown + if (delta_h > 0) { + for (x = 0; x < w; x++) { // laziness + if ((map->cell[x] = realloc(map->cell[x], h * sizeof(struct ktkCell))) == NULL) { + // MORE REPORTING ERRORS + } + } + } + // initialize new cells + if (delta_w > 0) { + for (x = map->w; x < w; x++) { + for (y = map->h; y < h; y++) { + map->cell[x][y] = ktk_CELL_DEFAULT; + } + } + } + if (delta_h > 0) { + for (y = map->h; y < h; y++) { + for (x = 0; x < w; x++) { + map->cell[x][y] = ktk_CELL_DEFAULT; + } + } + } + map->w = w; + map->h = h; + // okay! + return 0; +}*/ + +int ktk_resizeMap(struct ktkMap *map, int w, int h) { + if (w < map->w) { + int i; + for (i = w; i < map->w; i++) { + int j; + for (j = 0; j < map->h; j++) { + ktk_deleteCell(&(map->cell[i][j])); + } + } + } + if (h < map->h) { + int i; + for (i = 0; i < map->w; i++) { + int j; + for (j = h; j < map->h; j++) { + ktk_deleteCell(&(map->cell[i][j])); + } + } + } + map->cell = realloc(map->cell, w * sizeof(struct ktkCell*)); + int i; + for (i = map->w; i < w; i++) { + map->cell[i] = NULL; + } + for (i = 0; i < w; i++) { + map->cell[i] = realloc(map->cell[i], h * sizeof(struct ktkCell)); + int j; + for (j = 0; j < h; j++) { + //ktk_copyCell(&ktk_CELL_DEFAULT, &(map->cell[i][j])); + if (i >= map->w) { + map->cell[i][j] = ktk_CELL_DEFAULT; + } else { + if (j >= map->h) { + map->cell[i][j] = ktk_CELL_DEFAULT; + } + } + } + } + map->w = w; + map->h = h; + return 0; +} + +int ktk_copyMap(struct ktkMap *map_1, struct ktkMap *map_2) { + int x, y; + ktk_deleteMap(map_2); + map_2->flags = map_1->flags; + map_2->x = map_1->x; + map_2->y = map_1->y; + ktk_resizeMap(map_2, map_1->w, map_1->h); + for (x = 0; x < map_1->w; x++) { + for (y = 0; y< map_1->h; y++) { + ktk_copyCell(&map_1->cell[x][y], &map_2->cell[x][y]); + } + } + return 0; +} + +int ktk_mergeMaps(struct ktkMap *map_1, struct ktkMap *map_2) { + int max_x = map_2->x + map_2->w; + int max_y = map_2->y + map_2->h; + if (map_1->flags & ktk_MAP_RESIZE) { + if (max_x >= map_1->w) { + ktk_resizeMap(map_1, max_x, map_1->h); + } + if (max_y >= map_1->h) { + ktk_resizeMap(map_1, map_1->w, max_y); + } + } + int x, y; + for (x = 0; x < map_2->w; x++) { + if (map_2->x+x >= map_1->w || map_2->x+x < 0) continue; + for (y = 0; y < map_2->h; y++) { + if (map_2->y+y >= map_1->h || map_2->y+y < 0) continue; + if (map_2->cell[x][y].flags & ktk_CELL_EMPTY) continue; + // TODO: don't delete, but append + ktk_deleteCell(&(map_1->cell[map_2->x+x][map_2->y+y])); + ktk_copyCell(&(map_2->cell[x][y]), &(map_1->cell[map_2->x+x][map_2->y+y])); + } + } + return 0; +} +int ktk_deleteMap(struct ktkMap *map) { + int x, y; + for (x = 0; x < map->w; x++) { + for (y = 0; y < map->h; y++) { + ktk_deleteCell(&map->cell[x][y]); + } + free(map->cell[x]); + } + free(map->cell); + map->w = 0; + map->h = 0; + map->cell = NULL; + return 0; +} + +int ktk_checkMapOverlap(struct ktkMap *map_1, struct ktkMap *map_2) { + int x, y; + for (x = 0; x < map_2->w; x++) { + if (map_2->x+x >= map_1->w || map_2->x+x < 0) continue; + for (y = 0; y < map_2->h; y++) { + if (map_2->y+y >= map_1->h || map_2->y+y < 0) continue; + //printf("%dx%d(%d|%d) vs %dx%d(%d|%d)\n", x, y, map_2->cell[x][y].id_1, map_2->cell[x][y].flags, map_2->x+x, map_2->y+y, map_1->cell[map_2->x+x][map_2->y+y].id_1, map_1->cell[map_2->x+x][map_2->y+y].flags); + //printf("%d (%d)\n", map_2->cell[x][y].flags & ktk_CELL_EMPTY, ktk_CELL_EMPTY); + //printf("%d (%d)\n", map_1->cell[map_2->x+x][map_2->y+y].flags & ktk_CELL_EMPTY, ktk_CELL_EMPTY); + if (map_2->cell[x][y].flags & ktk_CELL_EMPTY) continue; + if (map_1->cell[map_2->x+x][map_2->y+y].flags & ktk_CELL_EMPTY) continue; + return 1; + } + } + return 0; +} + +int ktk_unsetMapCell(struct ktkMap *map, int x, int y) { + if (x < 0 || x > map->w) return 1; + if (y < 0 || y > map->h) return 1; + map->cell[x][y].flags |= ktk_CELL_EMPTY; + return 0; +} + +int ktk_setMapCell(struct ktkMap *map, int x, int y) { + if (x < 0 || x >= map->w) return 1; + if (y < 0 || y >= map->h) return 1; + map->cell[x][y].flags &= ~ktk_CELL_EMPTY; + return 0; +} + +struct ktkMap *ktk_borderCells(struct ktkMap *map, struct ktkMap *new_map) { + ktk_resizeMap(new_map, map->w, map->h); + int x = map->x, y = map->y; + for (x = 0; x < map->w; x++) { + for (y = 0; y < map->h; y++) { + if (map->cell[x][y].flags & ktk_CELL_EMPTY) continue; + // l + if (x-1 >= 0 && x < map->w) { + if (map->cell[x-1][y].flags & ktk_CELL_EMPTY) { + // new_map->cell[x-1][y].flags &= !ktk_CELL_EMPTY; + new_map->cell[x][y].flags &= !ktk_CELL_EMPTY; + } + } else { + new_map->cell[x][y].flags &= !ktk_CELL_EMPTY; + } + // r + if (x+1 < map->w) { + if (map->cell[x+1][y].flags & ktk_CELL_EMPTY) { + //new_map->cell[x+1][y].flags &= !ktk_CELL_EMPTY; + new_map->cell[x][y].flags &= !ktk_CELL_EMPTY; + } + } else { + new_map->cell[x][y].flags &= !ktk_CELL_EMPTY; + } + // u + if (y-1 >= 0) { + if (map->cell[x][y-1].flags & ktk_CELL_EMPTY) { + new_map->cell[x][y].flags &= !ktk_CELL_EMPTY; + //new_map->cell[x][y-1].flags &= !ktk_CELL_EMPTY; + } + // ul + if (x-1 >= 0) { + if (map->cell[x-1][y-1].flags & ktk_CELL_EMPTY) { + //new_map->cell[x+1][y].flags &= !ktk_CELL_EMPTY; + new_map->cell[x][y].flags &= !ktk_CELL_EMPTY; + } + } + // ur + if (x+1 < map->w) { + if (map->cell[x+1][y-1].flags & ktk_CELL_EMPTY) { + //new_map->cell[x+1][y].flags &= !ktk_CELL_EMPTY; + new_map->cell[x][y].flags &= !ktk_CELL_EMPTY; + } + } + } else { + new_map->cell[x][y].flags &= !ktk_CELL_EMPTY; + } + // d + if (y+1 < map->h) { + if (map->cell[x][y+1].flags & ktk_CELL_EMPTY) { + new_map->cell[x][y].flags &= !ktk_CELL_EMPTY; + //new_map->cell[x][y+1].flags &= !ktk_CELL_EMPTY; + } + // dl + if (x-1 >= 0) { + if (map->cell[x-1][y+1].flags & ktk_CELL_EMPTY) { + //new_map->cell[x+1][y].flags &= !ktk_CELL_EMPTY; + new_map->cell[x][y].flags &= !ktk_CELL_EMPTY; + } + } + // dr + if (x+1 < map->w) { + if (map->cell[x+1][y+1].flags & ktk_CELL_EMPTY) { + //new_map->cell[x+1][y].flags &= !ktk_CELL_EMPTY; + new_map->cell[x][y].flags &= !ktk_CELL_EMPTY; + } + } + } else { + new_map->cell[x][y].flags &= !ktk_CELL_EMPTY; + } + // ul + // ur + } + } + return new_map; +} + +int ktk_fillRect(struct ktkMap *map, int o_x, int o_y, int s_x, int s_y) { + int x, y; + for (x = 0; x < s_x; x++) { + for (y = 0; y < s_y; y++) { + ktk_setMapCell(map, o_x+x, o_y+y); + } + } + return 0; +} + +int ktk_fillEllipseBorder(struct ktkMap *map, int r_x, int r_y) { + int y = 0; + int x = 0; + float a, b; + + r_x /= 2; + r_y /= 2; + + int hw = r_x; + int hh = r_y; + + int o_x = 0; + int o_y = 0; + + a = (r_y*r_y) - (r_x * r_x * r_y) + (r_x * r_x) / 4; + while ((2.0 * r_y * r_y * x) <= (2.0 * r_x * r_x * y)) { + x++; + if (a <= 0) { + a = a + (2.0f * r_y * r_y * x) + (r_y * r_y); + } else { + y--; + a = a + (2.0f * r_y * r_y * x) - (2.0f * r_x * r_x * y) + (r_y * r_y); + } + ktk_setMapCell(map, o_x+x, o_y+y); + ktk_setMapCell(map, o_x-x, o_y+y); + ktk_setMapCell(map, o_x+x, o_y-y); + ktk_setMapCell(map, o_x-x, o_y-y); + x = -x; + ktk_setMapCell(map, o_x+x, o_y+y); + ktk_setMapCell(map, o_x-x, o_y+y); + ktk_setMapCell(map, o_x+x, o_y-y); + ktk_setMapCell(map, o_x-x, o_y-y); + x = -x; + } + x = r_x; + y = 0; + ktk_setMapCell(map, o_x+x, o_y+y); + ktk_setMapCell(map, o_x-x, o_y+y); + ktk_setMapCell(map, o_x+x, o_y-y); + ktk_setMapCell(map, o_x-x, o_y-y); + b = (r_x * r_x) + 2.0f * (r_y * r_y * r_x) + (r_y * r_y)/4; + while ((2.0f * r_y * r_y * x) > (2.0f * r_x * r_x * y)) { + y++; + if (b > 0) { + b = b + (r_x * r_x) - (2.0 * r_x * r_x * y); + } else { + x--; + b = b + (2.0f * r_y * r_y * x) - (2.0f * r_x * r_x * y) + (r_x * r_x); + } + ktk_setMapCell(map, o_x+x, o_y+y); + ktk_setMapCell(map, o_x-x, o_y+y); + ktk_setMapCell(map, o_x+x, o_y-y); + ktk_setMapCell(map, o_x-x, o_y-y); + y = -y; + ktk_setMapCell(map, o_x+x, o_y+y); + ktk_setMapCell(map, o_x-x, o_y+y); + ktk_setMapCell(map, o_x+x, o_y-y); + ktk_setMapCell(map, o_x-x, o_y-y); + y = -y; + } + + return 0; +} +int ktk_fillEllipse(struct ktkMap *map, int o_x, int o_y, int r_x, int r_y) { + int y; + int x; + int hw = r_x/2; + int hh = r_y/2; + for (y = -hh; y <= hh; y++) { + for (x = -hw; x <= hw; x++) { + double dx = (double)x / (double)hw; + double dy = (double)y / (double)hh; + if (dx*dx+dy*dy <= 1) { + //if(x < 0 || x > r_x || y < 0 || y > r_y) continue; + //printf("%dx%d\n", hw+x, hh+y); + ktk_setMapCell(map, hw+o_x+x, hh+o_y+y); + } + } + } + return 0; +} + +int ktk_fillCircle(struct ktkMap *map, int radius) { + int h = radius/2; + int x, y; + for (x = h-radius; x <= h+radius; x++) { + for(y = h-radius; y <= h+radius; y++) { + if ((x*x)+(y*y) < (radius*radius)) { + if(x < 0 || x > map->x || y < 0 || y > map->y) continue; + ktk_setMapCell(map, x, y); + } + } + } + return 0; +} + +int ktk_drawLine(struct ktkMap *map, int x1, int y1, int x2, int y2) { + int x, y; + if (y2-y1 < x2-x1) { + for (x = x1; x <= x2; x++) { + y = y1 + ((y2-y1)/(x2-x1)) * (x-x1); + ktk_setMapCell(map, x, y); + } + } else { + for (y = y1; y <= y2; y++) { + x = x1 + ((x2-x1)/(y2-y1)) * (y-y1); + ktk_setMapCell(map, x, y); + } + } + return 0; +} + +void ktk_printMap(struct ktkMap *map) { + int x, y; + for (y = 0; y < map->h; y++) { + printf("---\n"); + for (x = 0; x < map->w; x++) { + printf("%d:%d ", map->cell[x][y].id_1, map->cell[x][y].id_2); + } + printf("\n"); + } +} + +int ktk_deleteCell(struct ktkCell *cell) { + if (cell->flags & ktk_CELL_DATA_FREE && cell->data != NULL) { + free(cell->data); + cell->data_size = 0; + cell->data = NULL; + } + if (cell->flags & ktk_CELL_CELL_DELETE && cell->cell != NULL) { + int z; + for (z = 0; z < cell->cell_count; z++) { + ktk_deleteCell(&(cell->cell[z])); + } + free(cell->cell); + cell->cell = NULL; + cell->cell_count = 0; + } + cell->flags = cell->flags & ~ktk_CELL_EMPTY; + return 0; +} +int ktk_copyCell(struct ktkCell *cell_1, struct ktkCell *cell_2) { + *cell_2 = *cell_1; + if (cell_1->data != NULL) { + cell_2->data = malloc(cell_1->data_size); + memcpy(cell_2->data, cell_1->data, cell_1->data_size); + } + if (cell_1->cell != NULL) { + int i; + cell_2->cell = malloc(sizeof(struct ktkCell)*cell_1->cell_count); + for (i = 0; i < cell_1->cell_count; i++) { + ktk_copyCell(&cell_1->cell[i], &cell_2->cell[i]); + } + } + return 0; +} diff --git a/ktkMap.h b/ktkMap.h new file mode 100644 index 0000000..755bbae --- /dev/null +++ b/ktkMap.h @@ -0,0 +1,89 @@ +/* ================================================================ +This header file is for the generic "Map" data type. This data stores constructed Structures into a cell/grid map. +================================================================ */ +#ifndef KTK_MAP_H +#define KTK_MAP_H +#include "ktkStructure.h" + +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktkMap struct + +flags: + ktk_MAP_RESIZE: allow resizing of map during program manipulation +```````````````````````````````` */ +#define ktk_MAP_RESIZE 1 << 1 // resize map to fit structure or merge +#define ktk_MAP_APPEND 1 << 2 // append map to other map on merge +struct ktkMap { + int flags; // flags for behavior + int x, y; // position data, may be unused + int w, h; // width+height + struct ktkCell **cell; // dynamic 2d array of cells equal to w*h*sizeof(ktkCell) +}; extern const struct ktkMap ktk_MAP_DEFAULT; +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktk_resizeMap + params: struct ktkMap *map, int width, int height + returns: int, 0 on success, non-zero on error +---------------- +This function is used to resize the given map to target width and height. If the resize would shrink the map, cells outside of the new size are deleted as per normal ktk_deleteCell operations. +````````````````*/ +int ktk_resizeMap(struct ktkMap *map, int w, int h); +int ktk_checkMapOverlap(struct ktkMap *map_1, struct ktkMap *map_2); +int ktk_copyMap(struct ktkMap *map_1, struct ktkMap *map_2); +int ktk_mergeMaps(struct ktkMap *map_1, struct ktkMap *map_2); +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktk_deleteMap + params: struct ktkMap *map + returns: int, 0 on success +---------------- +This function deletes the given Map, calling ktk_deleteCell on each cell before freeing the *cell property. + +This function DOES NOT free the passed map. +````````````````*/ +int ktk_deleteMap(struct ktkMap *map); + +int ktk_unsetMapCell(struct ktkMap *map, int x, int y); +int ktk_setMapCell(struct ktkMap *map, int x, int y); + +struct ktkMap *ktk_borderCells(struct ktkMap *map, struct ktkMap *new_map); + +int ktk_fillRect(struct ktkMap *map, int o_x, int o_y, int s_x, int s_y); + +int ktk_drawLine(struct ktkMap *map, int x1, int y1, int x2, int y2); +int ktk_fillEllipseBorder(struct ktkMap *map, int r_x, int r_y); +int ktk_fillEllipse(struct ktkMap *map, int o_x, int o_y, int r_x, int r_y); +int ktk_fillCircle(struct ktkMap *map, int radius); + +void ktk_printMap(struct ktkMap *map); +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktkCell struct +```````````````````````````````` */ +#define ktk_CELL_DATA_FREE 1 << 1 +#define ktk_CELL_CELL_DELETE 1 << 2 +#define ktk_CELL_EMPTY 1 << 3 +struct ktkCell { + int id_1; // first id + int id_2; // second id + void *data; // user-defined data + size_t data_size; // user-defined data size + unsigned int flags; // flags for data + struct ktkCell *cell; // Cells contained in this cell + size_t cell_count; // count of above cells +}; extern const struct ktkCell ktk_CELL_DEFAULT; + +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktk_deleteCell + params: struct ktkCell *cell + returns: 0 on success +---------------- +This function deletes the given cell's data. + +Flags: + ktk_CELL_DATA_FREE - free() *data, set *data to NULL and data_size to 0 + ktk_CELL_CELL_FREE - deletes and free()s cells contained in .cell +NOT TRUE AT THE MOMENT: If the cell's flags contain ktk_CELL_DATA_FREE and *data is not-NULL, *data is free()'d and set to NULL and data_size is set to 0. + +This function DOES NOT free the cell - use ktk_freeCell for full Cell freeing operations. +```````````````` */ +int ktk_deleteCell(struct ktkCell *cell); +int ktk_copyCell(struct ktkCell *cell_1, struct ktkCell *cell_2); +#endif diff --git a/ktkProgram.c b/ktkProgram.c new file mode 100644 index 0000000..8c69435 --- /dev/null +++ b/ktkProgram.c @@ -0,0 +1,324 @@ +#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; +}*/ diff --git a/ktkProgram.h b/ktkProgram.h new file mode 100644 index 0000000..e258a8c --- /dev/null +++ b/ktkProgram.h @@ -0,0 +1,31 @@ +#ifndef KTK_PROGRAM_H +#define KTK_PROGRAM_H +#include "ktkStructure.h" +#include "ktkMap.h" + +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktkProgram + +Programs are little more than a nice container for Structures and their names. Structure definition files are read into Program(s) and actual Structures building is accomplished through Program(s) as well. +` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` */ +struct ktkProgram { + struct ktkStructure *structures; // contained structures + char **structure_name; // names for contained Structures + size_t structure_count; // count of contained structures +}; extern const struct ktkProgram ktk_PROGRAM_DEFAULT; +int ktk_freeProgram(struct ktkProgram *program); +int ktk_runProgram(struct ktkProgram *program, struct ktkMap *map); +#define ktk_LIMIT_DEPTH 16 +extern int ktk_current_depth; + +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktk_buildStructure + params: ktkProgram*, const char *structure, ktkMap *map + returns: *map + +This function finds the structure name in the given program and builds it into map. If the passed map is NULL, a new ktkMap is generated and returned. +` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` */ +struct ktkMap *ktk_buildStructure(struct ktkProgram *program, struct ktkStructure *structure, struct ktkMap *map); +struct ktkStructure *ktk_getStructure(struct ktkProgram *program, const char *structure_name); + +#endif diff --git a/ktkStructure.c b/ktkStructure.c new file mode 100644 index 0000000..7d74bf7 --- /dev/null +++ b/ktkStructure.c @@ -0,0 +1,134 @@ +#include "ktkStructure.h" +#include +#include +#include +#include // for randomizeSeed + +unsigned long ktk_RANDOM_SEED = 1; + +unsigned long ktk_randomizeSeed() { + ktk_RANDOM_SEED = (unsigned long)time(0); + srandom(ktk_RANDOM_SEED); + return ktk_RANDOM_SEED; +} + +int ktk_getRandom(int min, int max) { + int num; + if (min == 0 && max == 0) return 0; + if (min == max) return min; + // include max as a possible number (+1) + int range = (max+1) - min; + if (range >= RAND_MAX) { + printf("ktk_getRandom(%d, %d): ERROR, range beyond RAND_MAX!\n", min, max); + return 0; + } else if (range == 0) { + return min; + } + int buckets = RAND_MAX / range; + int limit = buckets * range; + for (num = random(); num >= limit; num = random()); + return min + (num / buckets); +} + +int ktk_rollNumber(struct ktkNumber number) { + int numb = ktk_getRandom(number.a, number.b); + return (ktk_getRandom(number.a, number.b)); + if (number.type == ktk_PERCENT) { + + } else if (number.type == ktk_DIGIT) { + + } +} +int ktk_rollNumberSet(struct ktkNumberSet set) { + if (set.count <= 0) return 0; + return ktk_rollNumber(set.sets[ktk_getRandom(0, set.count-1)]); +} +int ktk_deleteNumberSet(struct ktkNumberSet *set) { + if (set->sets != NULL) { + free(set->sets); + set->sets = NULL; + set->count = NULL; + } + return 0; +} +int ktk_copyNumberSet(struct ktkNumberSet *set_1, struct ktkNumberSet *set_2) { + ktk_deleteNumberSet(set_2); + if (set_1->count > 0) { + set_2->sets = realloc(set_2->sets, set_1->count*sizeof(struct ktkNumber)); + memcpy(set_2->sets, set_1->sets, set_1->count*sizeof(struct ktkNumber)); + set_2->count = set_1->count; + } else { + return 1; + } + return 0; +} +/*ktkField_t ktkStructureTable[] = { + {FIELD(flags)}, + {FIELD(x)}, {FIELD(y)}, + {FIELD(size_x)}, {FIELD(size_y)}, + {FIELD(id_1)}, {FIELD(id_2)}, + {FIELD(data)}, + {FIELD(relations)}, {FIELD(relation_count)} +}; +*/ +//int ktk_setField(ktkField_t *table, size_t table_size, + +const struct ktkStructure ktk_STRUCTURE_DEFAULT = { + 0, + NULL, + { 0, 0, 0}, { 0, 0, 0}, // x, y + { 0, 0, 0}, { 0, 0, 0}, // size_x, size_y + { NULL, 0}, // id_1 + { NULL, 0}, // id_2 + { NULL, 0}, // id_1 replace rules + { NULL, 0}, // id_2 replace rules + NULL, + NULL, 0, // relations + NULL, 0 // sub structures +}; +void ktk_dumpStructure(struct ktkStructure *structure) { + printf("flags: %d\n", structure->flags); + printf("name: %s\n", structure->name); + printf("x: %dx%d\n", structure->x.a, structure->x.b); + printf("y: %dx%d\n", structure->y.a, structure->y.b); + printf("size_x: %dx%d\n", structure->size_x.a, structure->size_x.b); + printf("size_y: %dx%d\n", structure->size_y.a, structure->size_y.b); +} + +const struct ktkRelation ktk_RELATION_DEFAULT = { + 0, + NULL, + { 0, 0, 0}, { 0, 0, 0}, + { 0, 0, 0}, { 0, 0, 0}, + { 1, 1, ktk_DIGIT}, + NULL, + NULL, + 0, + NULL, + NULL, + 0, + NULL, + NULL, + 0, +}; + +int ktk_explodeString(const char *string, char delim, int depth, char ***results) { + int words = 0, word_size = 0, word_i = 0; + int i = 0; + int len = strlen(string)+1; + // TODO: resize in 8-byte chunks or so + *results = malloc(1*sizeof(char*)); + (*results)[0] = malloc(1*sizeof(char)); + for (i = 0; i < len; i++) { + if ((string[i] == delim && words < depth) || string[i] == '\0') { + (*results)[words][word_i] = '\0'; + *results = realloc(*results, ++words*sizeof(char*)); + (*results)[words] = malloc(1*sizeof(char)); + word_i = word_size = 0; + } else { + (*results)[words] = realloc((*results)[words], ++word_size*sizeof(char)); + (*results)[words][word_i++] = string[i]; + } + } + return words; +} diff --git a/ktkStructure.h b/ktkStructure.h new file mode 100644 index 0000000..5f6d621 --- /dev/null +++ b/ktkStructure.h @@ -0,0 +1,104 @@ +#ifndef KTK_STRUCTURE_H +#define KTK_STRUCTURE_H +#include // size_t + +extern unsigned long ktk_RANDOM_SEED; +unsigned long ktk_randomizeSeed(); + +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktk_getRandom + +This function returns a random number (based on ktk_RANDOM_SEED) from min to max (including max). +` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` */ +int ktk_getRandom(int min, int max); +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktkNumber + +ktkNumbers are structures to allow for a single type of data to be used for: single integers, integer ranges, and percentages +` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` */ +#define ktk_ISSET 1 << 1 +#define ktk_RANGE 1 << 2 +#define ktk_PERCENT 1 << 3 +#define ktk_DIGIT 1 << 4 +struct ktkNumber { + int a, b; // min/max + short type; // ktk_NUMBER, ktk_NUMBER_RANGE, ktk_NUMBER_PERCENT +}; +int ktk_rollNumber(struct ktkNumber number); +struct ktkNumberSet { + struct ktkNumber *sets; // sets of numbers + size_t count; // count of sets +}; +int ktk_rollNumberSet(struct ktkNumberSet set); + +int ktk_deleteNumberSet(struct ktkNumberSet *set); +int ktk_copyNumberSet(struct ktkNumberSet *set_1, struct ktkNumberSet *set_2); + +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktkStructure + +Structures are ultimately a set of operations and relations used for building a map. Structures are stored and used via a Program. +` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` */ +#define ktk_STRUCTURE_WORLD 1 << 1 +#define ktk_STRUCTURE_CIRCLE 1 << 2 +#define ktk_STRUCTURE_RECT 1 << 3 +#define ktk_STRUCTURE_FILL 1 << 4 +#define ktk_STRUCTURE_BORDER 1 << 5 +#define ktk_STRUCTURE_REPLACE 1 << 6 +#define ktk_STRUCTURE_ORIGIN 1 << 7 +#define ktk_STRUCTURE_CONSTRAIN 1 << 8 +#define ktk_STRUCTURE_OVERLAP 1 << 9 +struct ktkStructure { + unsigned int flags; // flags for this structure + char *name; // name of this structure + struct ktkNumber x, y; + struct ktkNumber size_x, size_y; + struct ktkNumberSet id_1; // id_1 + struct ktkNumberSet id_2; // id_2 + struct ktkNumberSet replace_id_1; // id_1 replace rules + struct ktkNumberSet replace_id_2; // id_2 replace rules + void *data; // user data (?) + struct ktkRelation *relations; // behavioral relations to other Structures + size_t relation_count; // count of said relations + struct ktkStructure *live; // live sub structures + size_t live_count; // count of sub structures +}; extern const struct ktkStructure ktk_STRUCTURE_DEFAULT; +void ktk_dumpStructure(struct ktkStructure *structure); +// field table for ktkStructure +/*#define S struct ktkStructure +#define FIELD(m) #m,offsetof(S, m) +typedef struct { + const char *name; + size_t offset; +} ktkField_t; +extern ktkField_t ktkStructureTable[];*/ + +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktk_explodeString + params: search *string, char delimiter, int search depth, *** results + returns: count of search finds + +This function explodes the passed string by a delimiter up to a depth. Passed pointer to pointers of char* is used to store the words found (and is allocated accordingly). User _must_ free results manually, on results[n] and results. +` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` */ +int ktk_explodeString(const char *string, char delim, int depth, char ***results); +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktkRelation +` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` */ +struct ktkRelation { + unsigned int flags; // operating flags + char *name; + struct ktkNumber x, y; // x and y of the relation + struct ktkNumber size_x, size_y; // size of created structure (generally) + struct ktkNumber count; // count of times to run this relation + struct ktkStructure *from; // from this type of structure + char *from_name; // name of this structure + unsigned int from_flags; // from operating flags + struct ktkStructure *to; // to this type of structure + char *to_name; // name of this structure + unsigned int to_flags; // to operating flags + struct ktkStructure *path; // pathing Structure + char *path_name; // name of this structure + unsigned int path_flags; // pathing operating flags +}; extern const struct ktkRelation ktk_RELATION_DEFAULT; + +#endif diff --git a/ktk_parse.c b/ktk_parse.c new file mode 100644 index 0000000..cb87586 --- /dev/null +++ b/ktk_parse.c @@ -0,0 +1,290 @@ +#include "ktk_parse.h" +#include +#include +#include + +struct ktkNumber ktk_parseNumber(const char *text) { + struct ktkNumber number = {0, 0, 0}; + char **words = NULL; + size_t w; + size_t word_count = ktk_explodeString(text, '-', 1024, &words); + // stupidly get our type with substring search + if (strstr(text, "%") != NULL) { + number.type |= ktk_PERCENT; + } else { + number.type |= ktk_DIGIT; + } + // if we have more than one result from '-' explode, we are a range + if (word_count > 1) { + number.type |= ktk_RANGE; + } + if (word_count > 0) { + number.a = atoi(words[0]); + number.b = atoi(words[word_count-1]); + number.type |= ktk_ISSET; + } + // free words + for (w = 0; w < word_count; w++) { + free(words[w]); + } + free(words); + + return number; +} +struct ktkNumberSet *ktk_parseNumberSet(struct ktkNumberSet *set, const char *text) { + char **words = NULL; + size_t w; + size_t word_count = ktk_explodeString(text, ',', 1024, &words); + // stupidly get our type with substring search + // free words and parse at same time + set->count = word_count; + set->sets = realloc(set->sets, set->count*sizeof(struct ktkNumber)); + for (w = 0; w < word_count; w++) { + set->sets[w] = ktk_parseNumber(words[w]); + free(words[w]); + } + free(words); + + return set; +} + +int ktk_parseSFile(struct ktkProgram *program, const char *filename) { + FILE *file; // our file pointer! :) + char read_buf[16]; // file read buffer + char *current_read = NULL; // dynamic char* for storing up to \n or \0 + int current_read_size = 0; // size of current_read + int current_read_i = 0; // index position of current_read + int first_ch = 0; // used to remove beginning spaces + int n; // fread count + int i; // index for reading read_buf to current_read + int state = 0; // our current operating state + #define ktk_PARSE_NONE 0 // find a structure state + #define ktk_PARSE_STRUCTURE 1 // read vars/find relation block state + #define ktk_PARSE_RELATIONS 2 // find a relation state + #define ktk_PARSE_RELATION_STRUCTURE 3// read relation structure vars + #define ktk_PARSE_REPLACE 4 // read cell replace state + if ((file = fopen(filename, "r")) == NULL) { + // TODO: set errcode + return 1; + } + // read our file in 16-byte chunks + while((n = fread(read_buf, 1, 16, file))) { + read_buf[n] = '\0'; + // resize current_read to fit at least n + current_read_size += n; + current_read = realloc(current_read, current_read_size*sizeof(char)); + // handle newlines, read read_buf into current_read, etc. + for (i = 0; i < n; i++) { + // we found a non-space/tab, mark it as so + if (read_buf[i] != ' ' && read_buf[i] != '\t') first_ch = 1; + // skip empty spaces if we haven't found a regular char yet + if ((read_buf[i] == ' ' || read_buf[i] == '\t') && first_ch != 1) continue; + // end of line/file found, let's read it for data now + if (read_buf[i] == '\n' || read_buf[i] == '\0') { + current_read[current_read_i] = '\0'; + // use exploded strings to acquire variables and values + char **words = NULL; // exploded results + int word_count = 0; // count of words read + // **** read logic section **** + if (state == ktk_PARSE_NONE) { + word_count = ktk_explodeString(current_read, ' ', 1, &words); + // word count should be 2, for "structure {" + if (word_count > 1) { + if (words[1][0] == '{') { + // create and initialize new structure + program->structure_count++; + program->structures = realloc(program->structures, program->structure_count*(sizeof(struct ktkStructure))); + program->structures[program->structure_count-1] = ktk_STRUCTURE_DEFAULT; + program->structure_name = realloc(program->structure_name, program->structure_count*(sizeof(char*))); + // copy string over to structure_name + size_t name_size = strlen(words[0])+1; + program->structure_name[program->structure_count-1] = malloc(name_size*sizeof(char)); + memcpy(program->structure_name[program->structure_count-1], words[0], name_size); + // copy string to structure's name + program->structures[program->structure_count-1].name = malloc(name_size*sizeof(char)); + memcpy(program->structures[program->structure_count-1].name, words[0], name_size); + state = ktk_PARSE_STRUCTURE; + } else { + // it's garbage + } + } + } else if (state == ktk_PARSE_STRUCTURE) { + // ** structure reading logic + word_count = ktk_explodeString(current_read, ' ', 1, &words); + if (word_count == 1) { + if (words[0][0] == '}') { + state = ktk_PARSE_NONE; + } else { + ktk_parseSVars(&program->structures[program->structure_count-1], words, 1); + } + } else if (word_count == 2) { + if (words[1][0] == '{') { + if (strcmp(words[0], "relations") == 0) { + state = ktk_PARSE_RELATIONS; + } else if (strcmp(words[0], "replace") == 0) { + state = ktk_PARSE_REPLACE; + } + } else { + ktk_parseSVars(&program->structures[program->structure_count-1], words, 2); + } + } + // ** end structure reading logic + } else if (state == ktk_PARSE_RELATIONS) { + // ** relation reading logic + if ((word_count = ktk_explodeString(current_read, ' ', 1, &words)) >= 1) { + if (words[1][0] == '{') { + // I'm bad. :) + program->structures[program->structure_count-1].relation_count++; + program->structures[program->structure_count-1].relations = realloc(program->structures[program->structure_count-1].relations, program->structures[program->structure_count-1].relation_count*sizeof(struct ktkRelation)); + program->structures[program->structure_count-1].relations[program->structures[program->structure_count-1].relation_count-1] = ktk_RELATION_DEFAULT; + size_t name_size = strlen(words[0])+1; + program->structures[program->structure_count-1].relations[program->structures[program->structure_count-1].relation_count-1].name = malloc(name_size*sizeof(char)); + memcpy(program->structures[program->structure_count-1].relations[program->structures[program->structure_count-1].relation_count-1].name, words[0], name_size); + state = ktk_PARSE_RELATION_STRUCTURE; + } else if (words[0][0] == '}') { + state = ktk_PARSE_STRUCTURE; + } + } + // ** relation reading logic + } else if (state == ktk_PARSE_RELATION_STRUCTURE) { + word_count = ktk_explodeString(current_read, ' ', 1, &words); + if (word_count == 1) { + if (words[0][0] == '}') { + state = ktk_PARSE_RELATIONS; + } else { + ktk_parseSRelation(&(program->structures[program->structure_count-1].relations[program->structures[program->structure_count-1].relation_count-1]), words, word_count); + } + } else if (word_count == 2) { + ktk_parseSRelation(&(program->structures[program->structure_count-1].relations[program->structures[program->structure_count-1].relation_count-1]), words, word_count); + } + // ** replace reading logic + } else if (state == ktk_PARSE_REPLACE) { + word_count = ktk_explodeString(current_read, ' ', 1, &words); + if (word_count == 1) { + if (words[0][0] == '}') { + state = ktk_PARSE_STRUCTURE; + } + } else if (word_count == 2) { + if (strcmp(words[0], "id_1") == 0) { + ktk_parseNumberSet(&(program->structures[program->structure_count-1].replace_id_1), words[1]); + } else if (strcmp(words[0], "id_2") == 0) { + ktk_parseNumberSet(&(program->structures[program->structure_count-1].replace_id_2), words[1]); + } + } + } + // **** end logic section **** + // free our explode results + int w; + for (w = 0; w < word_count; w++) { + free(words[w]); + } + free(words); + // free our current read and reset to defaults + first_ch = 0; + current_read_i = 0; + free(current_read); + current_read = NULL; + current_read = realloc(current_read, current_read_size*sizeof(char)); + } else { + // normal characters are copied to current_read plainly + current_read[current_read_i++] = read_buf[i]; + } + } + } + fclose(file); + + return 0; +} + +int ktk_parseSVars(struct ktkStructure *structure, const char **vars, size_t var_count) { + if (var_count == 0) { + return 1; + } else if (var_count == 2) { + if (strcmp(vars[0], "flags") == 0) { + char **words = NULL; + int w, word_count = 0; + word_count = ktk_explodeString(vars[1], '|', 1024, &words); + for (w = 0; w < word_count; w++) { + if (strcmp(words[w], "WORLD") == 0) { + structure->flags |= ktk_STRUCTURE_WORLD; + } else if (strcmp(words[w], "FILL") == 0) { + structure->flags |= ktk_STRUCTURE_FILL; + } else if (strcmp(words[w], "BORDER") == 0) { + structure->flags |= ktk_STRUCTURE_BORDER; + } else if (strcmp(words[w], "ORIGIN") == 0) { + structure->flags |= ktk_STRUCTURE_ORIGIN; + } else if (strcmp(words[w], "CONSTRAIN") == 0) { + structure->flags |= ktk_STRUCTURE_CONSTRAIN; + } else if (strcmp(words[w], "OVERLAP") == 0) { + structure->flags |= ktk_STRUCTURE_OVERLAP; + } else if (strcmp(words[w], "CIRCLE") == 0) { + structure->flags |= ktk_STRUCTURE_CIRCLE; + } else if (strcmp(words[w], "RECT") == 0) { + structure->flags |= ktk_STRUCTURE_RECT; + } + free(words[w]); + } + free(words); + } else if (strcmp(vars[0], "x") == 0) { + structure->x = ktk_parseNumber(vars[1]); + } else if (strcmp(vars[0], "y") == 0) { + structure->y = ktk_parseNumber(vars[1]); + } else if (strcmp(vars[0], "size_x") == 0) { + structure->size_x = ktk_parseNumber(vars[1]); + } else if (strcmp(vars[0], "size_y") == 0) { + structure->size_y = ktk_parseNumber(vars[1]); + } else if (strcmp(vars[0], "id_1") == 0) { + ktk_parseNumberSet(&structure->id_1, vars[1]); + } else if (strcmp(vars[0], "id_2") == 0) { + ktk_parseNumberSet(&structure->id_2, vars[1]); + } + } + return 0; +} + +int ktk_parseSRelation(struct ktkRelation *relation, const char **vars, size_t var_count) { + if (var_count == 2) { + if (strcmp(vars[0], "flags") == 0) { + char **words = NULL; + int w, word_count = 0; + word_count = ktk_explodeString(vars[1], '|', 1024, &words); + for (w = 0; w < word_count; w++) { + if (strcmp(words[w], "WORLD") == 0) { + relation->flags |= ktk_STRUCTURE_WORLD; + } else if (strcmp(words[w], "FILL") == 0) { + relation->flags |= ktk_STRUCTURE_FILL; + } else if (strcmp(words[w], "BORDER") == 0) { + relation->flags |= ktk_STRUCTURE_BORDER; + } else if (strcmp(words[w], "ORIGIN") == 0) { + relation->flags |= ktk_STRUCTURE_ORIGIN; + } else if (strcmp(words[w], "CONSTRAIN") == 0) { + relation->flags |= ktk_STRUCTURE_CONSTRAIN; + } else if (strcmp(words[w], "OVERLAP") == 0) { + relation->flags |= ktk_STRUCTURE_OVERLAP; + } else if (strcmp(words[w], "CIRCLE") == 0) { + relation->flags |= ktk_STRUCTURE_CIRCLE; + } else if (strcmp(words[w], "RECT") == 0) { + relation->flags |= ktk_STRUCTURE_RECT; + } + free(words[w]); + } + free(words); + } else if (strcmp(vars[0], "x") == 0) { + relation->x = ktk_parseNumber(vars[1]); + } else if (strcmp(vars[0], "y") == 0) { + relation->y = ktk_parseNumber(vars[1]); + } else if (strcmp(vars[0], "size_x") == 0) { + relation->size_x = ktk_parseNumber(vars[1]); + } else if (strcmp(vars[0], "size_y") == 0) { + relation->size_y = ktk_parseNumber(vars[1]); + } else if (strcmp(vars[0], "count") == 0) { + relation->count = ktk_parseNumber(vars[1]); + } + } + return 0; +} + +int ktk_parseSPath(struct ktkRelation *relation, const char **vars, size_t var_count) { + + return 0; +} diff --git a/ktk_parse.h b/ktk_parse.h new file mode 100644 index 0000000..338a447 --- /dev/null +++ b/ktk_parse.h @@ -0,0 +1,31 @@ +#include "ktkStructure.h" +#include "ktkProgram.h" + +struct ktkNumber ktk_parseNumber(const char *text); +struct ktkNumberSet *ktk_parseNumberSet(struct ktkNumberSet *set, const char *text); +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktk_parseSFile + params: struct ktkProgram *program, const char *filename + return: 0 on success + +This function reads a Structures file into the given Program. +` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` */ +int ktk_parseSFile(struct ktkProgram *program, const char *filename); +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktk_parseSVars + params: struct ktkStructure *structure, const char **vas, size_t var_count + return: 0 on success + +This function is called by parseSFile and reads the given set of words into the Structure. +` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` */ +int ktk_parseSVars(struct ktkStructure *structure, const char **vars, size_t var_count); +/* ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +ktk_parseSRelation + params: struct ktkRelation *relation, const char **vars, size_t var_count + return: 0 on success + +This function is called by parseSFile and reads the given set of words into the Relation. +` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` */ +int ktk_parseSRelation(struct ktkRelation *relation, const char **vars, size_t var_count); + +int ktk_parseSPath(struct ktkRelation *relation, const char **vars, size_t var_count); diff --git a/logic.txt b/logic.txt new file mode 100644 index 0000000..7f0de91 --- /dev/null +++ b/logic.txt @@ -0,0 +1,66 @@ +Structure Generation Logic + +1. Start with Program structure call + This call builds a map with the structure within it + It also appends/adds to a Live Structures list + Live Structures are similar to Structures, but their position and size is absolute (not relative or percentage) + +2. Program build structure calls are _RECURSIVE_. + build method: + -- BEGIN BUILD LOGIC -- + while (retry < retry_limit) { + retry_limit++; + generate position, size, and draw in this.map + create this.live structure for this.map + -- BUILD SUB STRUCTURES -- + copy this.map to temp + for each relation + buildStructure to temp with this live structure + end + merge temp with this.map + -- CHECK IF OVERLAPPING STUFF -- + if (overlap_flag || !is_overlapping) { + -- MERGE WITH PARENT MAP AND ADD + merge this.map and parent.map (resize parent if parent map is RESIZE) + add this.live to parent.live + break; + } else { + clear this Live Structures + clear this (map) + } + } + delete this.map +3. linking + for structure in live.unlinked (limit calls somehow, so endless is avoided) + get target structure { + if target name[0] == ":" + target = getLiveStructure(getLiveStructureRoot(live), name) + else if target name[0] != ":" + target = getLiveStructure(live, name) + } + run pathing algorithm from live.x/live.y to target.x/target.y + while(!at_destination) { + create temp map + buildStructure(temp map, live) + merge temp map this.map at x, y + } + +1. first pass + Generate structure positions and size + +2. second pass + Link structures via from and to structure members + +mock program logic: + buildStruct + ( + ... buildStruct ... + ) + while (live_structures.unlinked) { + linkStruct + ( + ... buildStruct(s) from *from to *to ... + ) + } + +linking is contained in a loop limited by link_limit. This allows for linking paths to paths, up to a point (prevent endless loop) diff --git a/main.c b/main.c new file mode 100644 index 0000000..db76cdb --- /dev/null +++ b/main.c @@ -0,0 +1,38 @@ +#include "ktkMap.h" +#include "ktk_parse.h" +#include "ktkProgram.h" +#include + +int main(int argc, char *argv[]) { + ktk_randomizeSeed(); + + struct ktkProgram my_program = ktk_PROGRAM_DEFAULT; + ktk_parseSFile(&my_program, "test.txt"); + + struct ktkMap my_map = ktk_MAP_DEFAULT; + //ktk_resizeMap(&my_map, 10, 10); + my_map.flags |= ktk_MAP_RESIZE; + ktk_buildStructure(&my_program, ktk_getStructure(&my_program, "rage"), &my_map); + + //my_map.cell[2][2].id_1 = 1; + + int x, y; + for (y = 0; y < my_map.h; y++) { + for (x = 0; x < my_map.w; x++) { + if (my_map.cell[x][y].id_1 == 0) { + printf("."); +/* } else if (my_map.cell[x][y].id_1 == 1) { + printf("#");*/ + } else { + printf("%d", my_map.cell[x][y].id_1); + } + } + printf("\n"); + } + + ktk_deleteMap(&my_map); + + ktk_freeProgram(&my_program); + + return 0; +} diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000..63e1ea7 --- /dev/null +++ b/notes.txt @@ -0,0 +1,127 @@ +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +"Proclib" definition +```````````````````````````````` +This file describes our structure generation library - end-goal, wanted features, etc. + +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +End-goal +```````````````` +This library seeks to provide dynamic map generation for cell/grid based worlds. This is provided through structure-centric definition files thatare used to dynamically generate the world. + +The library is implemented in C and can be compiled into a separate library (and header) or it can be built directly into the target program by adding and referencing the appropriate C source and header files. + +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Features +```````````````` +This section provides a list of features implemented by the library. +,,,,,,,,,,,,,,,, +Structures(s), Section(s), and SectionRelation(s) +```````` +At the core of the library is the Structure struct. A Structure is, as the name suggests, a stand-alone set of data that would generally represent something such as a house, a tower, etc.. Structures are at the core of any map generation and can be used to make most any set of cells (it can be used for room generation, floor path generation, and much more). + +Code-wise, each Structure contains a dynamically sized array of pointers to other Structures(struct Structure **relations), a dynamically sized array of unsigned integers for the type of relationship(unsigned int **relation_flags), and a count of the current relationships held (size_t relation_count). + +Structures also possess two unsigned int bitflags (id_1 and id_2) which is used for general purpose grouping and identification. Structures also possess the void pointer, data, and accompanying size_t data_size that may be used to store additional data. Note that data will not be free()'d unless the FREE_DATA flag is set in the Structure's flags bitflag. + +In general, Structures are intended to be as abstract from specifics as much as possible, thereby allowing for a more flexible system. +,,,,,,,,,,,,,,,, +Structure Generation Syntax +```````` +; name is the _unique_ name of the structure ("chest", "tower", "room", etc.) +name { + ; flags may be: RELATIVE|WORLD for positioning and sizing settings + flags RELATIVE + ; position data may be: unspecified, absolute(3), or a range(1-3) + ; values may be: explicit(3), relative(-3,+3), or percentage(25%) + x 3 + y 3 + ; size data may be: unspecified, absolute(3), or a range(1-3) + ; values may be: explicit(3), relative(-3,+3), or percentage(25%) + size_x 1-8 + size_y 1-9 + ; id data may be: unspecified, absolute, range, or a set of absolutes or ranges + id_1 1 + id_2 10-11, 9, 13-14 + ; Structures + relations { + name { + ; count is how many times to run + count 2 + ; flag may be CREATE or FIND, BORDER, EXTEND + flag CREATE|BORDER + ; from/to logic is: if plain "name", it is in this context, if starting with ":name", it is in a global context. Each ":" signifies the depth to search, such as ":castle:room:door" + ; from flags: UNIQUE - from structure must not already have a from operation. + ; to flags: UNIQUE - find a structure that does not have a connection + ; from references another Structure + from :name + from_flag UNIQUE + ; to references another Structure + to :room:door + to_flag UNIQUE + ; if from/to are set and pathing is set, specify the path Structure to use + path name + } + } +} + +,,,,,,,,,,,,,,,, +Path -> House example +```````` +;; define our basic structures +dirt_path { + size_x 1-3 + size_y 1-3 + id_1 1 ; "ground" + id_2 3 ; "dirt" +} +house_floor { + id_1 2 ; "floors" + id_2 2-4 ; "house tiles" +} +house_door { + id_1 4 ; "doors" + id_2 2 ; "house door" +} +house_walls { + id_1 3 ; "walls" + id_2 2-4 ; "house walls" +} +;; define a complex structure +house { + size_x 6-10 + size_y 6-10 + relations { + house_floor { + flags CREATE|CIRCLE|FILL + } + house_walls { + flags CREATE|CIRCLE|BORDER + } + house_doors { + flags CREATE|CIRCLE|BORDER|REPLACE + count 2 + } + } +} +;; define a more complex structure! +map { + size_x 20 + size_y 20 + relations { + house { + flags CREATE + ; place house in top-left randomly + x 1-10 + y 1-10 + } + dirt_path { + flags CREATE|UNIQUE + to house:house_door + to_flags UNIQUE ; create paths to both doors + count 2 + ; place paths in bottom-right randomly + x 15-20 + y 15-20 + } + } +} diff --git a/parse.c b/parse.c new file mode 100644 index 0000000..bb55cc3 --- /dev/null +++ b/parse.c @@ -0,0 +1,3 @@ +#include "ktkStructure.h" +#include "ktkMap.h" + diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..fc1e21f --- /dev/null +++ b/test.txt @@ -0,0 +1,100 @@ +center { + size_x 14-17 + size_y 14-17 + flags CIRCLE|FILL|BORDER|ORIGIN + id_1 3 + relations { + room { + x 50% + y 50% + flags ORIGIN + } + } +} + +floor { + size_x 75% + size_y 75% + flags RECT|FILL + id_1 4 +} + +walls { + size_x 75% + size_y 75% + flags RECT|FILL|BORDER + id_1 3 +} + +room { + size_x 8-14 + size_y 8-14 + relations { + floor { + flags ORIGIN + x 50% + y 50% + } + walls { + flags OVERLAP|ORIGIN + x 50% + y 50% + } + } +} + +path { + size_x 2 + size_y 2 + relations { + floor_path { + } + door_path { + } + } +} +floor_path { + size_x 100% + size_y 100% + flags RECT|FILL|OVERLAP + id_1 2 +} +door_path { + size_x 1 + size_y 1 + flags RECT|FILL|OVERLAP + id_1 6 + replace { + id_1 2 + } +} + +rage { + size_x 64 + size_y 32 + id_1 1 + flags RECT|FILL|BORDER + relations { + center { + x 50% + y 50% + } + room { + count 6-8 + flags ORIGIN + x 10-80% + y 10-80% + } + path { + flags DUMB|ALL + from center + from_x 0%, 100% + from_y 0%, 100% + to room + to_x 25% + to_y 25% + x 0-2 + y 0-2 + } + } +} diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..e66643a --- /dev/null +++ b/todo.txt @@ -0,0 +1,26 @@ +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +TODO +` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` +,,,,,,,,,,,,,,,, +Procedural Liberry +` ` ` ` ` ` ` ` + - buildStructure generates live Structure into live structures list + - Pathing from structure to structure via live structures list + * linkStructures(), calls buildStructure from x0,y0 to x1,y1 + * has pathing rules: + * A* - uses A* to generate a path + * DUMB - attempt to dumbly walk via x/y inc/dec + * FORCE - path _must_ connect - if retries run out, forced replace occurs + * UNIQUE - only path to a specific structure once + * ALL - repeat until all unpathed to structures are connected + * from_depth - how deep to start pathing from + * to_depth - how deep to end pathing into "to" + * if a liveStructure has path_limit specified, that liveStructure will be pathed to only up to that limit. + - ktkPathing + * flags + - A*, DUMB, FORCE, ALL, UNIQUE + * from_x, from_y - start NumberSet(s) + * to_x, to_y - end Numberset(s) + * x, y - randomized placement offsets + +