diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/all.c | 427 | ||||
-rw-r--r-- | src/levels.c | 37 | ||||
-rw-r--r-- | src/tick.c | 335 | ||||
-rw-r--r-- | src/types.c | 90 |
4 files changed, 484 insertions, 405 deletions
@@ -1,103 +1,12 @@ +#ifndef INCLUDE_ALL_C +#define INCLUDE_ALL_C + #include <stddef.h> #include <stdint.h> -#define MEM_SIZE (1<<24) -#define GRIDWIDTH 16 -#define GRIDHEIGHT 16 -#define TICK_LENGTH 200 - -typedef struct { - unsigned char r, g, b, a; -} Color; - -typedef struct { - int x, y, w, h; - Color fill; - Color border; -} DrawElement; - -typedef struct { - int len; - DrawElement els[2 * GRIDWIDTH * GRIDHEIGHT * 4]; -} DrawList; - -typedef struct { - char *start; - char *end; -} Arena; - -#define new(a, c, t) ((t *) alloc(a, c, sizeof(t), _Alignof(t))) -#define affirm(c) while (!(c)) *(volatile int *)0 = 0 - -static void xmemcpy(void *dst, void *src, ptrdiff_t size) { - for (ptrdiff_t i = 0; i < size; i++) { - ((char *) dst)[i] = ((char *) src)[i]; - } -} - -static void *alloc(Arena *a, ptrdiff_t count, ptrdiff_t size, ptrdiff_t align) { - ptrdiff_t pad = -(size_t) a->start & (align - 1); - affirm(count < (a->end - a->start - pad) / size); - char *r = a->start + pad; - a->start += pad + size * count; - for (ptrdiff_t i = 0; i < count * size; i++) { - r[i] = 0; - } - - return r; -} - -typedef struct { - int width, height; -} UI; - -typedef struct { - uint64_t lastTick; - char playing; - int grid[GRIDWIDTH * GRIDHEIGHT]; -} State; - -// Mirror these in src/index.html.in -enum { - INPUT_NONE, - INPUT_CLICK, - INPUT_RCLICK, - INPUT_PAUSE_PLAY, -}; - -typedef struct { - State state; - UI ui; - int input; - int mousex, mousey; -} Game; - -enum { - EMPTY, - BLACK, - RED, - YELLOW, - RED_UP, - RED_DOWN, - RED_LEFT, - RED_RIGHT, - BLUE, - BLUE_UP, - BLUE_DOWN, - BLUE_LEFT, - BLUE_RIGHT, - N_COLORS, -}; - -static int isRed(int cell) { - return ( - cell == RED || - cell == RED_LEFT || - cell == RED_RIGHT || - cell == RED_UP || - cell == RED_DOWN - ); -} +#include "types.c" +#include "levels.c" +#include "tick.c" static const Color colors[N_COLORS][4] = { { @@ -213,6 +122,15 @@ static DrawList *render(State *state, UI *ui, Arena *a) { } } + drawList->els[drawList->len++] = (DrawElement) { + .x = cellWidth * state->goalx, + .y = cellHeight * state->goaly, + .w = cellWidth, + .h = cellHeight, + .fill = {255, 0, 0, 63}, + .border = {255, 0, 0, 255}, + }; + return drawList; } @@ -238,313 +156,8 @@ static void update(Game *game, uint64_t now, Arena a) { if (game->state.playing && game->state.lastTick + TICK_LENGTH <= now) { game->state.lastTick = now; - State *lastState = new(&a, 1, State); - xmemcpy(lastState, game, sizeof(State)); - - for (int x = 0; x < GRIDWIDTH; x++) { - for (int y = 0; y < GRIDHEIGHT; y++) { - switch (lastState->grid[x + y * GRIDWIDTH]) { - int reds, red; - int blues, blue; - case BLACK: - reds = 0; - if ( - x < GRIDWIDTH - 1 && ( - lastState->grid[x + 1 + y * GRIDWIDTH] == RED_LEFT || - lastState->grid[x + 1 + y * GRIDWIDTH] == RED - ) - ) { - reds++; - if ( - x < GRIDWIDTH - 2 && - y > 0 && - y < GRIDHEIGHT - 1 && - lastState->grid[x + 2 + y * GRIDWIDTH] == YELLOW && - lastState->grid[x + 1 + (y - 1) * GRIDWIDTH] == YELLOW && - lastState->grid[x + 1 + (y + 1) * GRIDWIDTH] == YELLOW - ) { - red = RED_LEFT; - } else { - red = lastState->grid[x + 1 + y * GRIDWIDTH]; - } - } - - if ( - x > 0 && ( - lastState->grid[x - 1 + y * GRIDWIDTH] == RED_RIGHT || - lastState->grid[x - 1 + y * GRIDWIDTH] == RED - ) - ) { - reds++; - if ( - x > 1 && - y > 0 && - y < GRIDHEIGHT - 1 && - lastState->grid[x - 2 + y * GRIDWIDTH] == YELLOW && - lastState->grid[x - 1 + (y - 1) * GRIDWIDTH] == YELLOW && - lastState->grid[x - 1 + (y + 1) * GRIDWIDTH] == YELLOW - ) { - red = RED_RIGHT; - } else { - red = lastState->grid[x - 1 + y * GRIDWIDTH]; - } - } - - if ( - y > 0 && ( - lastState->grid[x + (y - 1) * GRIDWIDTH] == RED_DOWN || - lastState->grid[x + (y - 1) * GRIDWIDTH] == RED - ) - ) { - reds++; - if ( - x > 0 && - x < GRIDWIDTH - 1 && - y > 1 && - lastState->grid[x + (y - 2) * GRIDWIDTH] == YELLOW && - lastState->grid[x - 1 + (y - 1) * GRIDWIDTH] == YELLOW && - lastState->grid[x + 1 + (y - 1) * GRIDWIDTH] == YELLOW - ) { - red = RED_DOWN; - } else { - red = lastState->grid[x + (y - 1) * GRIDWIDTH]; - } - } - - if ( - y < GRIDHEIGHT - 1 && ( - lastState->grid[x + (y + 1) * GRIDWIDTH] == RED_UP || - lastState->grid[x + (y + 1) * GRIDWIDTH] == RED - ) - ) { - reds++; - if ( - x > 0 && - x < GRIDWIDTH - 1 && - y < GRIDHEIGHT - 2 && - lastState->grid[x + (y + 2) * GRIDWIDTH] == YELLOW && - lastState->grid[x - 1 + (y + 1) * GRIDWIDTH] == YELLOW && - lastState->grid[x + 1 + (y + 1) * GRIDWIDTH] == YELLOW - ) { - red = RED_UP; - } else { - red = lastState->grid[x + (y + 1) * GRIDWIDTH]; - } - } - - if (reds == 1) { - game->state.grid[x + y * GRIDWIDTH] = red; - } else if (reds >= 2) { - game->state.grid[x + y * GRIDWIDTH] = RED; - } - break; - case RED: - game->state.grid[x + y * GRIDWIDTH] = YELLOW; - break; - case RED_LEFT: - if ( - x > 0 && - lastState->grid[x - 1 + y * GRIDWIDTH] == BLACK - ) { - game->state.grid[x + y * GRIDWIDTH] = YELLOW; - } else { - game->state.grid[x + y * GRIDWIDTH] = RED_UP; - } - break; - case RED_RIGHT: - if ( - x < GRIDWIDTH - 1 && - lastState->grid[x + 1 + y * GRIDWIDTH] == BLACK - ) { - game->state.grid[x + y * GRIDWIDTH] = YELLOW; - } else { - game->state.grid[x + y * GRIDWIDTH] = RED_DOWN; - } - break; - case RED_UP: - if ( - y > 0 && - lastState->grid[x + (y - 1) * GRIDWIDTH] == BLACK - ) { - game->state.grid[x + y * GRIDWIDTH] = YELLOW; - } else { - game->state.grid[x + y * GRIDWIDTH] = RED_RIGHT; - } - break; - case RED_DOWN: - if ( - y < GRIDHEIGHT - 1 && - lastState->grid[x + (y + 1) * GRIDWIDTH] == BLACK - ) { - game->state.grid[x + y * GRIDWIDTH] = YELLOW; - } else { - game->state.grid[x + y * GRIDWIDTH] = RED_LEFT; - } - break; - case YELLOW: - if ( - (x > 0 && lastState->grid[x - 1 + y * GRIDWIDTH] == BLUE_RIGHT) || - (x < GRIDWIDTH - 1 && lastState->grid[x + 1 + y * GRIDWIDTH] == BLUE_LEFT) || - (y > 0 && lastState->grid[x + (y - 1) * GRIDWIDTH] == BLUE_DOWN) || - (y < GRIDHEIGHT - 1 && lastState->grid[x + (y + 1) * GRIDWIDTH] == BLUE_UP) - ) { - game->state.grid[x + y * GRIDWIDTH] = RED; - } else { - game->state.grid[x + y * GRIDWIDTH] = BLACK; - } - break; - case BLUE: - blues = 0; - if ( - x > 0 && ( - lastState->grid[x - 1 + y * GRIDWIDTH] == RED || - lastState->grid[x - 1 + y * GRIDWIDTH] == RED_LEFT || - lastState->grid[x - 1 + y * GRIDWIDTH] == RED_RIGHT || - lastState->grid[x - 1 + y * GRIDWIDTH] == RED_DOWN || - lastState->grid[x - 1 + y * GRIDWIDTH] == RED_UP - ) - ) { - blues++; - blue = BLUE_RIGHT; - } - if ( - x < GRIDWIDTH - 1 && ( - lastState->grid[x + 1 + y * GRIDWIDTH] == RED || - lastState->grid[x + 1 + y * GRIDWIDTH] == RED_LEFT || - lastState->grid[x + 1 + y * GRIDWIDTH] == RED_RIGHT || - lastState->grid[x + 1 + y * GRIDWIDTH] == RED_DOWN || - lastState->grid[x + 1 + y * GRIDWIDTH] == RED_UP - ) - ) { - blues++; - blue = BLUE_LEFT; - } - if ( - y > 0 && ( - lastState->grid[x + (y - 1) * GRIDWIDTH] == RED || - lastState->grid[x + (y - 1) * GRIDWIDTH] == RED_LEFT || - lastState->grid[x + (y - 1) * GRIDWIDTH] == RED_RIGHT || - lastState->grid[x + (y - 1) * GRIDWIDTH] == RED_DOWN || - lastState->grid[x + (y - 1) * GRIDWIDTH] == RED_UP - ) - ) { - blues++; - blue = BLUE_DOWN; - } - if ( - y < GRIDHEIGHT - 1 && ( - lastState->grid[x + (y + 1) * GRIDWIDTH] == RED || - lastState->grid[x + (y + 1) * GRIDWIDTH] == RED_LEFT || - lastState->grid[x + (y + 1) * GRIDWIDTH] == RED_RIGHT || - lastState->grid[x + (y + 1) * GRIDWIDTH] == RED_DOWN || - lastState->grid[x + (y + 1) * GRIDWIDTH] == RED_UP - ) - ) { - blues++; - blue = BLUE_UP; - } - if (blues == 1) { - game->state.grid[x + y * GRIDWIDTH] = blue; - } - break; - case BLUE_LEFT: - if ( - (x > 0 && isRed(lastState->grid[x - 1 + y * GRIDWIDTH])) || - (x < GRIDWIDTH - 1 && isRed(lastState->grid[x + 1 + y * GRIDWIDTH])) || - (y > 0 && isRed(lastState->grid[x + (y - 1) * GRIDWIDTH])) || - (y < GRIDHEIGHT - 1 && isRed(lastState->grid[x + (y + 1) * GRIDWIDTH])) - ) { - game->state.grid[x + y * GRIDWIDTH] = BLUE; - } else if ( - x > 0 && - lastState->grid[x - 1 + y * GRIDWIDTH] == EMPTY - ) { - game->state.grid[x + y * GRIDWIDTH] = EMPTY; - } else { - game->state.grid[x + y * GRIDWIDTH] = BLUE; - } - break; - case BLUE_RIGHT: - if ( - (x > 0 && isRed(lastState->grid[x - 1 + y * GRIDWIDTH])) || - (x < GRIDWIDTH - 1 && isRed(lastState->grid[x + 1 + y * GRIDWIDTH])) || - (y > 0 && isRed(lastState->grid[x + (y - 1) * GRIDWIDTH])) || - (y < GRIDHEIGHT - 1 && isRed(lastState->grid[x + (y + 1) * GRIDWIDTH])) - ) { - game->state.grid[x + y * GRIDWIDTH] = BLUE; - } else if ( - x < GRIDWIDTH - 1 && - lastState->grid[x + 1 + y * GRIDWIDTH] == EMPTY - ) { - game->state.grid[x + y * GRIDWIDTH] = EMPTY; - } else { - game->state.grid[x + y * GRIDWIDTH] = BLUE; - } - break; - case BLUE_UP: - if ( - (x > 0 && isRed(lastState->grid[x - 1 + y * GRIDWIDTH])) || - (x < GRIDWIDTH - 1 && isRed(lastState->grid[x + 1 + y * GRIDWIDTH])) || - (y > 0 && isRed(lastState->grid[x + (y - 1) * GRIDWIDTH])) || - (y < GRIDHEIGHT - 1 && isRed(lastState->grid[x + (y + 1) * GRIDWIDTH])) - ) { - game->state.grid[x + y * GRIDWIDTH] = BLUE; - } else if ( - y > 0 && - lastState->grid[x + (y - 1) * GRIDWIDTH] == EMPTY - ) { - game->state.grid[x + y * GRIDWIDTH] = EMPTY; - } else { - game->state.grid[x + y * GRIDWIDTH] = BLUE; - } - break; - case BLUE_DOWN: - if ( - (x > 0 && isRed(lastState->grid[x - 1 + y * GRIDWIDTH])) || - (x < GRIDWIDTH - 1 && isRed(lastState->grid[x + 1 + y * GRIDWIDTH])) || - (y > 0 && isRed(lastState->grid[x + (y - 1) * GRIDWIDTH])) || - (y < GRIDHEIGHT - 1 && isRed(lastState->grid[x + (y + 1) * GRIDWIDTH])) - ) { - game->state.grid[x + y * GRIDWIDTH] = BLUE; - } else if ( - y < GRIDHEIGHT - 1 && - lastState->grid[x + (y + 1) * GRIDWIDTH] == EMPTY - ) { - game->state.grid[x + y * GRIDWIDTH] = EMPTY; - } else { - game->state.grid[x + y * GRIDWIDTH] = BLUE; - } - break; - case EMPTY: - // TODO: same as multiple reds - if ( - x > 0 && - lastState->grid[x - 1 + y * GRIDWIDTH] == BLUE_RIGHT - ) { - game->state.grid[x + y * GRIDWIDTH] = BLUE_RIGHT; - } - if ( - x < GRIDWIDTH - 1 && - lastState->grid[x + 1 + y * GRIDWIDTH] == BLUE_LEFT - ) { - game->state.grid[x + y * GRIDWIDTH] = BLUE_LEFT; - } - if ( - y > 0 && - lastState->grid[x + (y - 1) * GRIDWIDTH] == BLUE_DOWN - ) { - game->state.grid[x + y * GRIDWIDTH] = BLUE_DOWN; - } - if ( - y < GRIDHEIGHT - 1 && - lastState->grid[x + (y + 1) * GRIDWIDTH] == BLUE_UP - ) { - game->state.grid[x + y * GRIDWIDTH] = BLUE_UP; - } - break; - } - } - } + + tick(game, a); } } @@ -563,7 +176,9 @@ int main(int argc, char **argv) { }; Game *game = new(&a, 1, Game); - game->state.grid[0] = 0; + xmemcpy(&game->state.grid, &levels[0].grid, sizeof(game->state.grid)); + game->state.goalx = levels[0].goalx; + game->state.goaly = levels[0].goaly; game->state.playing = 0; game->ui = (UI) { .width = 640, @@ -685,3 +300,5 @@ void game_update(int input, int mousex, int mousey, int now) { } #endif + +#endif diff --git a/src/levels.c b/src/levels.c new file mode 100644 index 0000000..22ad76a --- /dev/null +++ b/src/levels.c @@ -0,0 +1,37 @@ +#include "all.c" + +typedef struct { + int grid[GRIDWIDTH * GRIDHEIGHT]; + int goalx, goaly; +} Level; + +#define _ EMPTY, +#define B BLACK, +#define O BLUE, +static Level levels[] = { + { + .grid = { + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ B O _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + }, + .goalx = 18, + .goaly = 7, + }, +}; +#undef _ +#undef B +#undef O diff --git a/src/tick.c b/src/tick.c new file mode 100644 index 0000000..8b8f731 --- /dev/null +++ b/src/tick.c @@ -0,0 +1,335 @@ +#include "all.c" + +static int isRed(int cell) { + return ( + cell == RED || + cell == RED_LEFT || + cell == RED_RIGHT || + cell == RED_UP || + cell == RED_DOWN + ); +} + +static int isBlue(int cell) { + return ( + cell == BLUE || + cell == BLUE_LEFT || + cell == BLUE_RIGHT || + cell == BLUE_UP || + cell == BLUE_DOWN + ); +} + +static void tick(Game *game, Arena a) { + State *lastState = new(&a, 1, State); + xmemcpy(lastState, game, sizeof(State)); + + for (int x = 0; x < GRIDWIDTH; x++) { + for (int y = 0; y < GRIDHEIGHT; y++) { + switch (lastState->grid[x + y * GRIDWIDTH]) { + int reds, red; + int blues, blue; + case BLACK: + reds = 0; + if ( + x < GRIDWIDTH - 1 && ( + lastState->grid[x + 1 + y * GRIDWIDTH] == RED_LEFT || + lastState->grid[x + 1 + y * GRIDWIDTH] == RED + ) + ) { + reds++; + if ( + x < GRIDWIDTH - 2 && + y > 0 && + y < GRIDHEIGHT - 1 && + lastState->grid[x + 2 + y * GRIDWIDTH] == YELLOW && + lastState->grid[x + 1 + (y - 1) * GRIDWIDTH] == YELLOW && + lastState->grid[x + 1 + (y + 1) * GRIDWIDTH] == YELLOW + ) { + red = RED_LEFT; + } else { + red = lastState->grid[x + 1 + y * GRIDWIDTH]; + } + } + + if ( + x > 0 && ( + lastState->grid[x - 1 + y * GRIDWIDTH] == RED_RIGHT || + lastState->grid[x - 1 + y * GRIDWIDTH] == RED + ) + ) { + reds++; + if ( + x > 1 && + y > 0 && + y < GRIDHEIGHT - 1 && + lastState->grid[x - 2 + y * GRIDWIDTH] == YELLOW && + lastState->grid[x - 1 + (y - 1) * GRIDWIDTH] == YELLOW && + lastState->grid[x - 1 + (y + 1) * GRIDWIDTH] == YELLOW + ) { + red = RED_RIGHT; + } else { + red = lastState->grid[x - 1 + y * GRIDWIDTH]; + } + } + + if ( + y > 0 && ( + lastState->grid[x + (y - 1) * GRIDWIDTH] == RED_DOWN || + lastState->grid[x + (y - 1) * GRIDWIDTH] == RED + ) + ) { + reds++; + if ( + x > 0 && + x < GRIDWIDTH - 1 && + y > 1 && + lastState->grid[x + (y - 2) * GRIDWIDTH] == YELLOW && + lastState->grid[x - 1 + (y - 1) * GRIDWIDTH] == YELLOW && + lastState->grid[x + 1 + (y - 1) * GRIDWIDTH] == YELLOW + ) { + red = RED_DOWN; + } else { + red = lastState->grid[x + (y - 1) * GRIDWIDTH]; + } + } + + if ( + y < GRIDHEIGHT - 1 && ( + lastState->grid[x + (y + 1) * GRIDWIDTH] == RED_UP || + lastState->grid[x + (y + 1) * GRIDWIDTH] == RED + ) + ) { + reds++; + if ( + x > 0 && + x < GRIDWIDTH - 1 && + y < GRIDHEIGHT - 2 && + lastState->grid[x + (y + 2) * GRIDWIDTH] == YELLOW && + lastState->grid[x - 1 + (y + 1) * GRIDWIDTH] == YELLOW && + lastState->grid[x + 1 + (y + 1) * GRIDWIDTH] == YELLOW + ) { + red = RED_UP; + } else { + red = lastState->grid[x + (y + 1) * GRIDWIDTH]; + } + } + + if (reds == 1) { + game->state.grid[x + y * GRIDWIDTH] = red; + } else if (reds >= 2) { + game->state.grid[x + y * GRIDWIDTH] = RED; + } + break; + case RED: + game->state.grid[x + y * GRIDWIDTH] = YELLOW; + break; + case RED_LEFT: + if ( + x > 0 && + lastState->grid[x - 1 + y * GRIDWIDTH] == BLACK + ) { + game->state.grid[x + y * GRIDWIDTH] = YELLOW; + } else { + game->state.grid[x + y * GRIDWIDTH] = RED_UP; + } + break; + case RED_RIGHT: + if ( + x < GRIDWIDTH - 1 && + lastState->grid[x + 1 + y * GRIDWIDTH] == BLACK + ) { + game->state.grid[x + y * GRIDWIDTH] = YELLOW; + } else { + game->state.grid[x + y * GRIDWIDTH] = RED_DOWN; + } + break; + case RED_UP: + if ( + y > 0 && + lastState->grid[x + (y - 1) * GRIDWIDTH] == BLACK + ) { + game->state.grid[x + y * GRIDWIDTH] = YELLOW; + } else { + game->state.grid[x + y * GRIDWIDTH] = RED_RIGHT; + } + break; + case RED_DOWN: + if ( + y < GRIDHEIGHT - 1 && + lastState->grid[x + (y + 1) * GRIDWIDTH] == BLACK + ) { + game->state.grid[x + y * GRIDWIDTH] = YELLOW; + } else { + game->state.grid[x + y * GRIDWIDTH] = RED_LEFT; + } + break; + case YELLOW: + if ( + (x > 0 && lastState->grid[x - 1 + y * GRIDWIDTH] == BLUE_RIGHT) || + (x < GRIDWIDTH - 1 && lastState->grid[x + 1 + y * GRIDWIDTH] == BLUE_LEFT) || + (y > 0 && lastState->grid[x + (y - 1) * GRIDWIDTH] == BLUE_DOWN) || + (y < GRIDHEIGHT - 1 && lastState->grid[x + (y + 1) * GRIDWIDTH] == BLUE_UP) + ) { + game->state.grid[x + y * GRIDWIDTH] = RED; + } else { + game->state.grid[x + y * GRIDWIDTH] = BLACK; + } + break; + case BLUE: + blues = 0; + if ( + x > 0 && ( + lastState->grid[x - 1 + y * GRIDWIDTH] == RED || + lastState->grid[x - 1 + y * GRIDWIDTH] == RED_LEFT || + lastState->grid[x - 1 + y * GRIDWIDTH] == RED_RIGHT || + lastState->grid[x - 1 + y * GRIDWIDTH] == RED_DOWN || + lastState->grid[x - 1 + y * GRIDWIDTH] == RED_UP + ) + ) { + blues++; + blue = BLUE_RIGHT; + } + if ( + x < GRIDWIDTH - 1 && ( + lastState->grid[x + 1 + y * GRIDWIDTH] == RED || + lastState->grid[x + 1 + y * GRIDWIDTH] == RED_LEFT || + lastState->grid[x + 1 + y * GRIDWIDTH] == RED_RIGHT || + lastState->grid[x + 1 + y * GRIDWIDTH] == RED_DOWN || + lastState->grid[x + 1 + y * GRIDWIDTH] == RED_UP + ) + ) { + blues++; + blue = BLUE_LEFT; + } + if ( + y > 0 && ( + lastState->grid[x + (y - 1) * GRIDWIDTH] == RED || + lastState->grid[x + (y - 1) * GRIDWIDTH] == RED_LEFT || + lastState->grid[x + (y - 1) * GRIDWIDTH] == RED_RIGHT || + lastState->grid[x + (y - 1) * GRIDWIDTH] == RED_DOWN || + lastState->grid[x + (y - 1) * GRIDWIDTH] == RED_UP + ) + ) { + blues++; + blue = BLUE_DOWN; + } + if ( + y < GRIDHEIGHT - 1 && ( + lastState->grid[x + (y + 1) * GRIDWIDTH] == RED || + lastState->grid[x + (y + 1) * GRIDWIDTH] == RED_LEFT || + lastState->grid[x + (y + 1) * GRIDWIDTH] == RED_RIGHT || + lastState->grid[x + (y + 1) * GRIDWIDTH] == RED_DOWN || + lastState->grid[x + (y + 1) * GRIDWIDTH] == RED_UP + ) + ) { + blues++; + blue = BLUE_UP; + } + if (blues == 1) { + game->state.grid[x + y * GRIDWIDTH] = blue; + } + break; + case BLUE_LEFT: + if ( + (x > 0 && isRed(lastState->grid[x - 1 + y * GRIDWIDTH])) || + (x < GRIDWIDTH - 1 && isRed(lastState->grid[x + 1 + y * GRIDWIDTH])) || + (y > 0 && isRed(lastState->grid[x + (y - 1) * GRIDWIDTH])) || + (y < GRIDHEIGHT - 1 && isRed(lastState->grid[x + (y + 1) * GRIDWIDTH])) + ) { + game->state.grid[x + y * GRIDWIDTH] = BLUE; + } else if ( + x > 0 && + lastState->grid[x - 1 + y * GRIDWIDTH] == EMPTY + ) { + game->state.grid[x + y * GRIDWIDTH] = EMPTY; + } else { + game->state.grid[x + y * GRIDWIDTH] = BLUE; + } + break; + case BLUE_RIGHT: + if ( + (x > 0 && isRed(lastState->grid[x - 1 + y * GRIDWIDTH])) || + (x < GRIDWIDTH - 1 && isRed(lastState->grid[x + 1 + y * GRIDWIDTH])) || + (y > 0 && isRed(lastState->grid[x + (y - 1) * GRIDWIDTH])) || + (y < GRIDHEIGHT - 1 && isRed(lastState->grid[x + (y + 1) * GRIDWIDTH])) + ) { + game->state.grid[x + y * GRIDWIDTH] = BLUE; + } else if ( + x < GRIDWIDTH - 1 && + lastState->grid[x + 1 + y * GRIDWIDTH] == EMPTY + ) { + game->state.grid[x + y * GRIDWIDTH] = EMPTY; + } else { + game->state.grid[x + y * GRIDWIDTH] = BLUE; + } + break; + case BLUE_UP: + if ( + (x > 0 && isRed(lastState->grid[x - 1 + y * GRIDWIDTH])) || + (x < GRIDWIDTH - 1 && isRed(lastState->grid[x + 1 + y * GRIDWIDTH])) || + (y > 0 && isRed(lastState->grid[x + (y - 1) * GRIDWIDTH])) || + (y < GRIDHEIGHT - 1 && isRed(lastState->grid[x + (y + 1) * GRIDWIDTH])) + ) { + game->state.grid[x + y * GRIDWIDTH] = BLUE; + } else if ( + y > 0 && + lastState->grid[x + (y - 1) * GRIDWIDTH] == EMPTY + ) { + game->state.grid[x + y * GRIDWIDTH] = EMPTY; + } else { + game->state.grid[x + y * GRIDWIDTH] = BLUE; + } + break; + case BLUE_DOWN: + if ( + (x > 0 && isRed(lastState->grid[x - 1 + y * GRIDWIDTH])) || + (x < GRIDWIDTH - 1 && isRed(lastState->grid[x + 1 + y * GRIDWIDTH])) || + (y > 0 && isRed(lastState->grid[x + (y - 1) * GRIDWIDTH])) || + (y < GRIDHEIGHT - 1 && isRed(lastState->grid[x + (y + 1) * GRIDWIDTH])) + ) { + game->state.grid[x + y * GRIDWIDTH] = BLUE; + } else if ( + y < GRIDHEIGHT - 1 && + lastState->grid[x + (y + 1) * GRIDWIDTH] == EMPTY + ) { + game->state.grid[x + y * GRIDWIDTH] = EMPTY; + } else { + game->state.grid[x + y * GRIDWIDTH] = BLUE; + } + break; + case EMPTY: + // TODO: same as multiple reds + if ( + x > 0 && + lastState->grid[x - 1 + y * GRIDWIDTH] == BLUE_RIGHT + ) { + game->state.grid[x + y * GRIDWIDTH] = BLUE_RIGHT; + } + if ( + x < GRIDWIDTH - 1 && + lastState->grid[x + 1 + y * GRIDWIDTH] == BLUE_LEFT + ) { + game->state.grid[x + y * GRIDWIDTH] = BLUE_LEFT; + } + if ( + y > 0 && + lastState->grid[x + (y - 1) * GRIDWIDTH] == BLUE_DOWN + ) { + game->state.grid[x + y * GRIDWIDTH] = BLUE_DOWN; + } + if ( + y < GRIDHEIGHT - 1 && + lastState->grid[x + (y + 1) * GRIDWIDTH] == BLUE_UP + ) { + game->state.grid[x + y * GRIDWIDTH] = BLUE_UP; + } + break; + } + } + } + + if (isBlue(game->state.grid[game->state.goalx + game->state.goaly * GRIDWIDTH])) { + // TODO: Win conditions + } +} diff --git a/src/types.c b/src/types.c new file mode 100644 index 0000000..fe72e13 --- /dev/null +++ b/src/types.c @@ -0,0 +1,90 @@ +#include "all.c" + +#define MEM_SIZE (1<<24) +#define GRIDWIDTH 20 +#define GRIDHEIGHT 16 +#define TICK_LENGTH 200 + +typedef struct { + unsigned char r, g, b, a; +} Color; + +typedef struct { + int x, y, w, h; + Color fill; + Color border; +} DrawElement; + +typedef struct { + int len; + DrawElement els[2 * GRIDWIDTH * GRIDHEIGHT * 4]; +} DrawList; + +typedef struct { + char *start; + char *end; +} Arena; + +enum { + EMPTY, + BLACK, + RED, + YELLOW, + RED_UP, + RED_DOWN, + RED_LEFT, + RED_RIGHT, + BLUE, + BLUE_UP, + BLUE_DOWN, + BLUE_LEFT, + BLUE_RIGHT, + N_COLORS, +}; + +typedef struct { + int width, height; +} UI; + +typedef struct { + uint64_t lastTick; + char playing; + int grid[GRIDWIDTH * GRIDHEIGHT]; + int goalx, goaly; +} State; + +// Mirror these in src/index.html.in +enum { + INPUT_NONE, + INPUT_CLICK, + INPUT_RCLICK, + INPUT_PAUSE_PLAY, +}; + +typedef struct { + State state; + UI ui; + int input; + int mousex, mousey; +} Game; + +#define new(a, c, t) ((t *) alloc(a, c, sizeof(t), _Alignof(t))) +#define affirm(c) while (!(c)) *(volatile int *)0 = 0 + +static void xmemcpy(void *dst, void *src, ptrdiff_t size) { + for (ptrdiff_t i = 0; i < size; i++) { + ((char *) dst)[i] = ((char *) src)[i]; + } +} + +static void *alloc(Arena *a, ptrdiff_t count, ptrdiff_t size, ptrdiff_t align) { + ptrdiff_t pad = -(size_t) a->start & (align - 1); + affirm(count < (a->end - a->start - pad) / size); + char *r = a->start + pad; + a->start += pad + size * count; + for (ptrdiff_t i = 0; i < count * size; i++) { + r[i] = 0; + } + + return r; +} |