Thumbnail

rani/games.git

Clone URL: https://git.buni.party/rani/games.git

commit 41897528a1c695e9c6b2c10f3c5b623e31e9aa80 Author: rani <clagv.randomgames@gmail.com> Date: Thu Jul 20 19:51:49 2023 +0000 Add game of life diff --git a/life/README.md b/life/README.md new file mode 100644 index 0000000..d86105b --- /dev/null +++ b/life/README.md @@ -00 +113 @@ +# Life + +Conway's Game of Life. The game begins in a board editor. Click on a dead cell to give it life and click on a living cell to kill it. Pressing enter begins the simulation. r clears the board. q quits the game. + +During simulation, i edits the initial board, e edits the current board, and q quits the game. + +# Config + +* `Y`: Board height +* `X`: Board width +* `DELAY`: Time between generations (ms) +* `LIVE_C`: Character for living cells +* `DEAD_C`: Character for dead cells diff --git a/life/life.c b/life/life.c new file mode 100644 index 0000000..0424d52 --- /dev/null +++ b/life/life.c @@ -00 +1178 @@ +#include <string.h> +#include <ncurses.h> +#include <stdbool.h> + + +/* BEGIN CONFIG */ +#define Y 16 +#define X 16 + +#define DELAY 250 + +#define LIVE_C '#' +#define DEAD_C ' ' +/* END CONFIG */ + + +#define ARRLEN(a) (sizeof(a)/sizeof(*a)) + +#define LIVE 1<<0 +#define DEAD 1<<1 +#define TODIE 1<<2 +#define TOLIVE 1<<3 + + +enum { + GREEN = 1, +}; + + +struct { + int x, y; +} around[8] = { + {.x = -1, .y = -1}, {.x = 0, .y = -1}, {.x = +1, .y = -1}, + {.x = -1, .y = 0}, {.x = +1, .y = 0}, + {.x = -1, .y = +1}, {.x = 0, .y = +1}, {.x = +1, .y = +1} +}; + + +void display(const char grid[X][Y], bool edit) { + for (int x = 0; x < X; x++) addstr("+ - "); + addstr("+\n"); + for (int y = 0; y < Y; y++) { + for (int x = 0; x < X; x++) { + addstr("| "); + char c = grid[x][y]; + int cp = 0; + if (edit) cp = COLOR_PAIR(GREEN); + attron(cp); + addch(c & LIVE ? LIVE_C : DEAD_C); + attroff(cp); + addch(' '); + } + addstr("|\n"); + for (int x = 0; x < X; x++) addstr("+ - "); + addstr("+\n"); + } +} + + +int main() { + initscr(); + noecho(); + curs_set(0); + keypad(stdscr, TRUE); + + mousemask(BUTTON1_CLICKED, NULL); + + use_default_colors(); + start_color(); + init_pair(GREEN, COLOR_GREEN, -1); + + char grid[X][Y]; + memset(grid, DEAD, sizeof(grid)); + char initial_grid[X][Y]; + memset(initial_grid, DEAD, sizeof(grid)); + + clear(); + + bool edit_initial = true; + while (true) { + // initialize the board + while (true) { + erase(); + display(grid, true); + + move(0, (X*4+2)/2 - 5); + attron(A_REVERSE); + addstr("BOARD EDIT"); + move(Y*2, (X*4+2)/2 - 21); + addstr("Enter to start | r to restart | q to quit"); + attroff(A_REVERSE); + refresh(); + + int c = getch(); + if (c == KEY_ENTER || c == '\n') break; + if (c == 'q') goto terminate; + if (c == 'r') { + memset(grid, DEAD, sizeof(grid)); + continue; + } + if (c != KEY_MOUSE) continue; + MEVENT e; + if (getmouse(&e) != OK) continue; + + if (e.x % 4 == 0 || e.y % 2 == 0) continue; + int x = (e.x - 2) / 4; + int y = (e.y - 1) / 2; + if ((e.x - 1) % 4 == 0) x++; + if (x > X || y > Y) continue; + + if (grid[x][y] == LIVE) grid[x][y] = DEAD; + else grid[x][y] = LIVE; + } + + if (edit_initial) memcpy(initial_grid, grid, sizeof(grid)); + + timeout(0); + + while (true) { + // determine new cell states + for (int x = 0; x < X; x++) { + for (int y = 0; y < Y; y++) { + int neighbors = 0; + for (int i = 0; i < ARRLEN(around); i++) { + int nx = x + around[i].x; + int ny = y + around[i].y; + if (nx < 0 || ny < 0 || nx >= X || ny >= Y) continue; + if (grid[nx][ny] & LIVE) neighbors++; + } + + if (neighbors == 3) grid[x][y] |= TOLIVE; + else if (neighbors == 2 && grid[x][y] & LIVE) grid[x][y] |= TOLIVE; + else grid[x][y] |= TODIE; + } + } + + // update all cells + for (int x = 0; x < X; x++) { + for (int y = 0; y < Y; y++) { + if (grid[x][y] & TOLIVE) grid[x][y] = LIVE; + else grid[x][y] = DEAD; + } + } + + erase(); + display(grid, false); + + move(Y*2, (X*4+2)/2 - 23); + attron(A_REVERSE); + addstr("q to quit | i to edit initial | e to edit now"); + attroff(A_REVERSE); + refresh(); + + int c = getch(); + if (c != ERR) { + if (c == 'q') goto terminate; + if (c == 'i') { + edit_initial = true; + break; + } + if (c == 'e') { + edit_initial = false; + break; + } + } + + napms(DELAY); + } + + timeout(-1); + if (edit_initial) memcpy(grid, initial_grid, sizeof(grid)); + } + + terminate: + echo(); + curs_set(1); + endwin(); +}