Thumbnail

rani/games.git

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

Viewing file on branch master

1#include <string.h>
2#include <ncurses.h>
3#include <stdbool.h>
4
5
6/* BEGIN CONFIG */
7#ifndef Y
8#define Y 16
9#endif /* Y */
10
11#ifndef X
12#define X 16
13#endif /* X */
14
15#ifndef DELAY
16#define DELAY 250
17#endif /* DELAY */
18
19#ifndef LIVE_C
20#define LIVE_C '#'
21#endif /* LIVE_C */
22
23#ifndef DEAD_C
24#define DEAD_C ' '
25#endif /* DEAD_C */
26/* END CONFIG */
27
28
29#define ARRLEN(a) (sizeof(a)/sizeof(*a))
30
31#define LIVE 1<<0
32#define DEAD 1<<1
33#define TODIE 1<<2
34#define TOLIVE 1<<3
35
36
37enum {
38 GREEN = 1,
39};
40
41
42struct {
43 int x, y;
44} around[8] = {
45 {.x = -1, .y = -1}, {.x = 0, .y = -1}, {.x = +1, .y = -1},
46 {.x = -1, .y = 0}, {.x = +1, .y = 0},
47 {.x = -1, .y = +1}, {.x = 0, .y = +1}, {.x = +1, .y = +1}
48};
49
50
51void display(const char grid[X][Y], bool edit) {
52 for (int x = 0; x < X; x++) addstr("+ - ");
53 addstr("+\n");
54 for (int y = 0; y < Y; y++) {
55 for (int x = 0; x < X; x++) {
56 addstr("| ");
57 char c = grid[x][y];
58 int cp = 0;
59 if (edit) cp = COLOR_PAIR(GREEN);
60 attron(cp);
61 addch(c & LIVE ? LIVE_C : DEAD_C);
62 attroff(cp);
63 addch(' ');
64 }
65 addstr("|\n");
66 for (int x = 0; x < X; x++) addstr("+ - ");
67 addstr("+\n");
68 }
69}
70
71
72int main() {
73 initscr();
74 noecho();
75 curs_set(0);
76 keypad(stdscr, TRUE);
77
78 mousemask(BUTTON1_CLICKED, NULL);
79
80 use_default_colors();
81 start_color();
82 init_pair(GREEN, COLOR_GREEN, -1);
83
84 char grid[X][Y];
85 memset(grid, DEAD, sizeof(grid));
86 char initial_grid[X][Y];
87 memset(initial_grid, DEAD, sizeof(grid));
88
89 clear();
90
91 bool edit_initial = true;
92 while (true) {
93 // initialize the board
94 while (true) {
95 erase();
96 display(grid, true);
97
98 move(0, (X*4+2)/2 - 5);
99 attron(A_REVERSE);
100 addstr("BOARD EDIT");
101 move(Y*2, (X*4+2)/2 - 21);
102 addstr("Enter to start | r to restart | q to quit");
103 attroff(A_REVERSE);
104 refresh();
105
106 int c = getch();
107 if (c == KEY_ENTER || c == '\n') break;
108 if (c == 'q') goto terminate;
109 if (c == 'r') {
110 memset(grid, DEAD, sizeof(grid));
111 continue;
112 }
113 if (c != KEY_MOUSE) continue;
114 MEVENT e;
115 if (getmouse(&e) != OK) continue;
116
117 if (e.x % 4 == 0 || e.y % 2 == 0) continue;
118 int x = (e.x - 2) / 4;
119 int y = (e.y - 1) / 2;
120 if ((e.x - 1) % 4 == 0) x++;
121 if (x > X || y > Y) continue;
122
123 if (grid[x][y] == LIVE) grid[x][y] = DEAD;
124 else grid[x][y] = LIVE;
125 }
126
127 if (edit_initial) memcpy(initial_grid, grid, sizeof(grid));
128
129 timeout(0);
130
131 while (true) {
132 // determine new cell states
133 for (int x = 0; x < X; x++) {
134 for (int y = 0; y < Y; y++) {
135 int neighbors = 0;
136 for (int i = 0; i < ARRLEN(around); i++) {
137 int nx = x + around[i].x;
138 int ny = y + around[i].y;
139 if (nx < 0 || ny < 0 || nx >= X || ny >= Y) continue;
140 if (grid[nx][ny] & LIVE) neighbors++;
141 }
142
143 if (neighbors == 3) grid[x][y] |= TOLIVE;
144 else if (neighbors == 2 && grid[x][y] & LIVE) grid[x][y] |= TOLIVE;
145 else grid[x][y] |= TODIE;
146 }
147 }
148
149 // update all cells
150 for (int x = 0; x < X; x++) {
151 for (int y = 0; y < Y; y++) {
152 if (grid[x][y] & TOLIVE) grid[x][y] = LIVE;
153 else grid[x][y] = DEAD;
154 }
155 }
156
157 erase();
158 display(grid, false);
159
160 move(Y*2, (X*4+2)/2 - 23);
161 attron(A_REVERSE);
162 addstr("q to quit | i to edit initial | e to edit now");
163 attroff(A_REVERSE);
164 refresh();
165
166 int c = getch();
167 if (c != ERR) {
168 if (c == 'q') goto terminate;
169 if (c == 'i') {
170 edit_initial = true;
171 break;
172 }
173 if (c == 'e') {
174 edit_initial = false;
175 break;
176 }
177 }
178
179 napms(DELAY);
180 }
181
182 timeout(-1);
183 if (edit_initial) memcpy(grid, initial_grid, sizeof(grid));
184 }
185
186 terminate:
187 echo();
188 curs_set(1);
189 endwin();
190}
191