diff options
| -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; +} | 
