Initial commit of the procedural generation syntax library - possesses majority of the basic structure generation codebase, but is lacking the pathing portion (keep posted)

master
kts 2014-11-17 00:12:37 -08:00
commit 00b4a72fd8
16 changed files with 1858 additions and 0 deletions

2
.gitignore vendored 100644
View File

@ -0,0 +1,2 @@
.DS_Store
*.swp

26
Makefile 100644
View File

@ -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

467
ktkMap.c 100644
View File

@ -0,0 +1,467 @@
#include "ktkMap.h"
#include <stdlib.h> // malloc
#include <stdio.h> // printf, remove
#include <math.h> // 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;
}

89
ktkMap.h 100644
View File

@ -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

324
ktkProgram.c 100644
View File

@ -0,0 +1,324 @@
#include "ktkProgram.h"
#include <stdlib.h>
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;
}*/

31
ktkProgram.h 100644
View File

@ -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

134
ktkStructure.c 100644
View File

@ -0,0 +1,134 @@
#include "ktkStructure.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h> // 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;
}

104
ktkStructure.h 100644
View File

@ -0,0 +1,104 @@
#ifndef KTK_STRUCTURE_H
#define KTK_STRUCTURE_H
#include <stddef.h> // 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

290
ktk_parse.c 100644
View File

@ -0,0 +1,290 @@
#include "ktk_parse.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
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;
}

31
ktk_parse.h 100644
View File

@ -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);

66
logic.txt 100644
View File

@ -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)

38
main.c 100644
View File

@ -0,0 +1,38 @@
#include "ktkMap.h"
#include "ktk_parse.h"
#include "ktkProgram.h"
#include <time.h>
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;
}

127
notes.txt 100644
View File

@ -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
}
}
}

3
parse.c 100644
View File

@ -0,0 +1,3 @@
#include "ktkStructure.h"
#include "ktkMap.h"

100
test.txt 100644
View File

@ -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
}
}
}

26
todo.txt 100644
View File

@ -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