summary refs log tree commit diff stats
path: root/gamestate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gamestate.cpp')
-rw-r--r--gamestate.cpp933
1 files changed, 428 insertions, 505 deletions
diff --git a/gamestate.cpp b/gamestate.cpp index 8c2df9c..e77ff76 100644 --- a/gamestate.cpp +++ b/gamestate.cpp
@@ -1,378 +1,363 @@
1#include "gamestate.h" 1#include "gamestate.h"
2
2#include <SDL_ttf.h> 3#include <SDL_ttf.h>
3#include "util.h" 4
4#include "mazeoflife.h"
5#include "highscore.h"
6#include "titlestate.h"
7#include <fstream>
8#include "hslist.h"
9#include <set>
10#include <bitset>
11#include <tuple>
12#include <algorithm> 5#include <algorithm>
13#include <vector> 6#include <bitset>
14#include <deque> 7#include <deque>
8#include <fstream>
15#include <iostream> 9#include <iostream>
16#include <sstream>
17#include <list> 10#include <list>
11#include <set>
12#include <sstream>
13#include <tuple>
18#include <unordered_map> 14#include <unordered_map>
19#include <unordered_set> 15#include <unordered_set>
16#include <vector>
17
18#include "highscore.h"
19#include "hslist.h"
20#include "mazeoflife.h"
21#include "titlestate.h"
22#include "util.h"
20 23
21class GameBoard { 24class GameBoard {
22 public: 25 public:
23 GameBoard(int level, int playerx, int playery); 26 GameBoard(int level, int playerx, int playery);
24 void tick(int playerx, int playery); 27 void tick(int playerx, int playery);
25 void render(SDL_Renderer* renderer, int level) const; 28 void render(SDL_Renderer* renderer, int level) const;
26 bool isObstructed(int x, int y) const; 29 bool isObstructed(int x, int y) const;
27 bool operator<(const GameBoard& other) const; 30 bool operator<(const GameBoard& other) const;
28 31
29 using coord = std::tuple<int, int>; 32 using coord = std::tuple<int, int>;
30 33
31 private: 34 private:
32 void initialize(int level); 35 void initialize(int level);
33 bool solve(int playerx, int playery) const; 36 bool solve(int playerx, int playery) const;
34 std::string dump() const; 37 std::string dump() const;
35 38
36 using board_type = std::bitset<WIDTH*HEIGHT>; 39 using board_type = std::bitset<WIDTH * HEIGHT>;
37 40
38 void incrementIfNeighbor( 41 void incrementIfNeighbor(int x, int y, const board_type& temp, int playerx,
39 int x, 42 int playery, int& tick) const;
40 int y, 43
41 const board_type& temp, 44 bool applyNeighbors(int x, int y, const board_type& temp, int playerx,
42 int playerx, 45 int playery) const;
43 int playery, 46
44 int& tick) const; 47 board_type blocks;
45 48 board_type updateable;
46 bool applyNeighbors( 49 int oldx;
47 int x, 50 int oldy;
48 int y,
49 const board_type& temp,
50 int playerx,
51 int playery) const;
52
53 board_type blocks;
54 board_type updateable;
55 int oldx;
56 int oldy;
57}; 51};
58 52
59class LoadGameState : public State { 53class LoadGameState : public State {
60 public: 54 public:
61 LoadGameState(int level); 55 LoadGameState(int level);
62 State* operator() (SDL_Window* window, SDL_Renderer* renderer); 56 State* operator()(SDL_Window* window, SDL_Renderer* renderer);
63 57
64 private: 58 private:
65 int level; 59 int level;
66}; 60};
67 61
68class PlayGameState : public State { 62class PlayGameState : public State {
69 public: 63 public:
70 PlayGameState(int level, GameBoard* board, int playerx, int playery); 64 PlayGameState(int level, GameBoard* board, int playerx, int playery);
71 State* operator() (SDL_Window* window, SDL_Renderer* renderer); 65 State* operator()(SDL_Window* window, SDL_Renderer* renderer);
72 66
73 private: 67 private:
74 bool move(int x, int y); 68 bool move(int x, int y);
75 int level; 69 int level;
76 GameBoard* board; 70 GameBoard* board;
77 int playerx; 71 int playerx;
78 int playery; 72 int playery;
79}; 73};
80 74
81void setRendererAliveColor(SDL_Renderer* renderer, int level) 75void setRendererAliveColor(SDL_Renderer* renderer, int level) {
82{ 76 switch ((level / 10) % 5) {
83 switch ((level/10)%5) 77 case 0:
84 { 78 SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
85 case 0: SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); break; // Black 79 break; // Black
86 case 1: SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); break; // Red 80 case 1:
87 case 2: SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); break; // Green 81 SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
88 case 3: SDL_SetRenderDrawColor(renderer, 85, 85, 85, 255); break; // Dark Gray 82 break; // Red
89 case 4: SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255); break; // Magenta 83 case 2:
90 } 84 SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
85 break; // Green
86 case 3:
87 SDL_SetRenderDrawColor(renderer, 85, 85, 85, 255);
88 break; // Dark Gray
89 case 4:
90 SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
91 break; // Magenta
92 }
91} 93}
92 94
93void setRendererDeadColor(SDL_Renderer* renderer, int level) 95void setRendererDeadColor(SDL_Renderer* renderer, int level) {
94{ 96 switch ((level / 10) % 5) {
95 switch ((level/10)%5) 97 case 0:
96 { 98 SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
97 case 0: SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); break; // White 99 break; // White
98 case 1: SDL_SetRenderDrawColor(renderer, 255, 192, 203, 255); break; // Pink 100 case 1:
99 case 2: SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255); break; // Cyan 101 SDL_SetRenderDrawColor(renderer, 255, 192, 203, 255);
100 case 3: SDL_SetRenderDrawColor(renderer, 170, 170, 170, 255); break; // Light Gray 102 break; // Pink
101 case 4: SDL_SetRenderDrawColor(renderer, 255, 128, 0, 255); break; // Orange 103 case 2:
102 } 104 SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255);
105 break; // Cyan
106 case 3:
107 SDL_SetRenderDrawColor(renderer, 170, 170, 170, 255);
108 break; // Light Gray
109 case 4:
110 SDL_SetRenderDrawColor(renderer, 255, 128, 0, 255);
111 break; // Orange
112 }
103} 113}
104 114
105void GameBoard::incrementIfNeighbor( 115void GameBoard::incrementIfNeighbor(int x, int y, const board_type& temp,
106 int x, 116 int playerx, int playery, int& tick) const {
107 int y, 117 int nx = x;
108 const board_type& temp, 118 int ny = y;
109 int playerx, 119
110 int playery, 120 wrap(x, y);
111 int& tick) const
112{
113 int nx = x;
114 int ny = y;
115
116 wrap(x, y);
117
118 if (!((nx!=x)&&(ny!=y)))
119 {
120 if ((temp[x+y*WIDTH])||((playerx==x)&&(playery==y))||((x==15)&&(y==15)))
121 {
122 ++tick;
123 }
124 }
125}
126 121
127State* GameState::operator() (SDL_Window* window, SDL_Renderer* renderer) 122 if (!((nx != x) && (ny != y))) {
128{ 123 if ((temp[x + y * WIDTH]) || ((playerx == x) && (playery == y)) ||
129 return new LoadGameState(0); 124 ((x == 15) && (y == 15))) {
125 ++tick;
126 }
127 }
130} 128}
131 129
132LoadGameState::LoadGameState(int m_level) 130State* GameState::operator()(SDL_Window* window, SDL_Renderer* renderer) {
133{ 131 return new LoadGameState(0);
134 level = m_level;
135} 132}
136 133
137State* LoadGameState::operator() (SDL_Window* window, SDL_Renderer* renderer) 134LoadGameState::LoadGameState(int m_level) { level = m_level; }
138{ 135
139 char* wintitle = new char[50]; 136State* LoadGameState::operator()(SDL_Window* window, SDL_Renderer* renderer) {
140 sprintf(wintitle, "Maze Of Life - Level %d", level); 137 char* wintitle = new char[50];
141 SDL_SetWindowTitle(window, wintitle); 138 sprintf(wintitle, "Maze Of Life - Level %d", level);
142 139 SDL_SetWindowTitle(window, wintitle);
143 // Randomly place the player in a corner 140
144 int playerx, playery; 141 // Randomly place the player in a corner
145 switch (rand()%4) 142 int playerx, playery;
146 { 143 switch (rand() % 4) {
147 case 0: playerx = 1; playery = 1; break; 144 case 0:
148 case 1: playerx = 1; playery = HEIGHT-2; break; 145 playerx = 1;
149 case 2: playerx = WIDTH-2; playery = HEIGHT-2; break; 146 playery = 1;
150 case 3: playerx = WIDTH-2; playery = 1; break; 147 break;
151 } 148 case 1:
152 149 playerx = 1;
153 // Display the level number 150 playery = HEIGHT - 2;
154 setRendererDeadColor(renderer, level); 151 break;
155 SDL_RenderClear(renderer); 152 case 2:
156 153 playerx = WIDTH - 2;
157 TTF_Font* font = loadFont(100); 154 playery = HEIGHT - 2;
158 SDL_Color fontColor = {0, 0, 0, 0}; 155 break;
159 char levelnum[8]; 156 case 3:
160 sprintf(levelnum, "%d", level); 157 playerx = WIDTH - 2;
161 SDL_Surface* dispsurf = TTF_RenderText_Solid(font, levelnum, fontColor); 158 playery = 1;
162 SDL_Texture* disptext = SDL_CreateTextureFromSurface(renderer, dispsurf); 159 break;
163 SDL_FreeSurface(dispsurf); 160 }
164 161
165 SDL_Rect pos; 162 // Display the level number
166 SDL_QueryTexture(disptext, NULL, NULL, &pos.w, &pos.h); 163 setRendererDeadColor(renderer, level);
167 pos.x = 240-(pos.w/2); 164 SDL_RenderClear(renderer);
168 pos.y = 240-(pos.h/2); 165
169 166 TTF_Font* font = loadFont(100);
170 SDL_RenderCopy(renderer, disptext, NULL, &pos); 167 SDL_Color fontColor = {0, 0, 0, 0};
171 SDL_RenderPresent(renderer); 168 char levelnum[8];
172 169 sprintf(levelnum, "%d", level);
173 // Do 50 gens of Conway 170 SDL_Surface* dispsurf = TTF_RenderText_Solid(font, levelnum, fontColor);
174 GameBoard* board = new GameBoard(level, playerx, playery); 171 SDL_Texture* disptext = SDL_CreateTextureFromSurface(renderer, dispsurf);
175 172 SDL_FreeSurface(dispsurf);
176 // Wait a bit 173
177 SDL_Delay(500); 174 SDL_Rect pos;
178 175 SDL_QueryTexture(disptext, NULL, NULL, &pos.w, &pos.h);
179 // Start the level 176 pos.x = 240 - (pos.w / 2);
180 return new PlayGameState(level, board, playerx, playery); 177 pos.y = 240 - (pos.h / 2);
178
179 SDL_RenderCopy(renderer, disptext, NULL, &pos);
180 SDL_RenderPresent(renderer);
181
182 // Do 50 gens of Conway
183 GameBoard* board = new GameBoard(level, playerx, playery);
184
185 // Wait a bit
186 SDL_Delay(500);
187
188 // Start the level
189 return new PlayGameState(level, board, playerx, playery);
181} 190}
182 191
183PlayGameState::PlayGameState(int m_level, GameBoard* m_board, int m_playerx, int m_playery) 192PlayGameState::PlayGameState(int m_level, GameBoard* m_board, int m_playerx,
184{ 193 int m_playery) {
185 level = m_level; 194 level = m_level;
186 board = m_board; 195 board = m_board;
187 playerx = m_playerx; 196 playerx = m_playerx;
188 playery = m_playery; 197 playery = m_playery;
189} 198}
190 199
191State* PlayGameState::operator() (SDL_Window* window, SDL_Renderer* renderer) 200State* PlayGameState::operator()(SDL_Window* window, SDL_Renderer* renderer) {
192{ 201 SDL_Event e;
193 SDL_Event e; 202
194 203 for (;;) {
195 for (;;) 204 // Tick board
196 { 205 board->tick(playerx, playery);
197 // Tick board 206
198 board->tick(playerx, playery); 207 // Paint board
199 208 board->render(renderer, level);
200 // Paint board 209
201 board->render(renderer, level); 210 // Paint event
202 211 SDL_Rect block;
203 // Paint event 212 block.w = 16;
204 SDL_Rect block; 213 block.h = 16;
205 block.w = 16; 214 block.x = 15 * 16;
206 block.h = 16; 215 block.y = 15 * 16;
207 block.x = 15*16; 216 SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
208 block.y = 15*16; 217 SDL_RenderFillRect(renderer, &block);
209 SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); 218
210 SDL_RenderFillRect(renderer, &block); 219 // Paint player
211 220 block.x = playerx * 16;
212 // Paint player 221 block.y = playery * 16;
213 block.x = playerx*16; 222 SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255);
214 block.y = playery*16; 223 SDL_RenderFillRect(renderer, &block);
215 SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255); 224
216 SDL_RenderFillRect(renderer, &block); 225 SDL_RenderPresent(renderer);
217 226
218 SDL_RenderPresent(renderer); 227 while (SDL_PollEvent(&e)) {
219 228 if (e.type == SDL_QUIT) {
220 while (SDL_PollEvent(&e)) 229 return NULL;
221 { 230 } else if (e.type == SDL_KEYDOWN) {
222 if (e.type == SDL_QUIT) 231 switch (e.key.keysym.sym) {
223 { 232 case SDLK_LEFT:
224 return NULL; 233 if (move(playerx - 1, playery)) {
225 } else if (e.type == SDL_KEYDOWN) 234 return new LoadGameState(level + 1);
226 { 235 } else {
227 switch (e.key.keysym.sym) 236 break;
228 { 237 }
229 case SDLK_LEFT: 238
230 if (move(playerx-1, playery)) 239 case SDLK_RIGHT:
231 { 240 if (move(playerx + 1, playery)) {
232 return new LoadGameState(level+1); 241 return new LoadGameState(level + 1);
233 } else { 242 } else {
234 break; 243 break;
235 } 244 }
236 245
237 case SDLK_RIGHT: 246 case SDLK_UP:
238 if (move(playerx+1, playery)) 247 if (move(playerx, playery - 1)) {
239 { 248 return new LoadGameState(level + 1);
240 return new LoadGameState(level+1); 249 } else {
241 } else { 250 break;
242 break; 251 }
243 } 252
244 253 case SDLK_DOWN:
245 case SDLK_UP: 254 if (move(playerx, playery + 1)) {
246 if (move(playerx, playery-1)) 255 return new LoadGameState(level + 1);
247 { 256 } else {
248 return new LoadGameState(level+1); 257 break;
249 } else { 258 }
250 break; 259
251 } 260 case SDLK_ESCAPE:
252 261 SDL_SetWindowTitle(window, "");
253 case SDLK_DOWN: 262
254 if (move(playerx, playery+1)) 263 std::ifstream exists(getDataFile());
255 { 264 if (exists) {
256 return new LoadGameState(level+1); 265 FILE* hslist = fopen(getDataFile(), "r");
257 } else { 266 int scores;
258 break; 267 Highscore* h;
259 } 268
260 269 fscanf(hslist, "%d%*c", &scores);
261 case SDLK_ESCAPE: 270
262 SDL_SetWindowTitle(window, ""); 271 if (scores < 10) {
263 272 fclose(hslist);
264 std::ifstream exists(getDataFile()); 273
265 if (exists) 274 return new EnterHighscoreState(level);
266 { 275 } else {
267 FILE* hslist = fopen(getDataFile(), "r"); 276 for (int i = 0; i < scores; i++) {
268 int scores; 277 int namelen;
269 Highscore* h; 278 char namelens[4];
270 279 char* name = (char*)calloc(25, sizeof(char));
271 fscanf(hslist, "%d%*c", &scores); 280 int score;
272 281
273 if (scores < 10) 282 fscanf(hslist, "%d", &namelen);
274 { 283 sprintf(namelens, "%%%dc", namelen);
275 fclose(hslist); 284 fscanf(hslist, namelens, name);
276 285 fscanf(hslist, "%d%*c", &score);
277 return new EnterHighscoreState(level); 286
278 } else { 287 h = new Highscore(name, score);
279 for (int i=0; i<scores; i++) 288 }
280 { 289
281 int namelen; 290 fclose(hslist);
282 char namelens[4]; 291
283 char* name = (char*) calloc(25, sizeof(char)); 292 if (h->getLevel() < level) {
284 int score; 293 return new EnterHighscoreState(level);
285 294 } else {
286 fscanf(hslist, "%d", &namelen); 295 return new DisplayAndReturnLocalHighscoreListState();
287 sprintf(namelens, "%%%dc", namelen); 296 }
288 fscanf(hslist, namelens, name); 297 }
289 fscanf(hslist, "%d%*c", &score); 298 } else {
290 299 return new EnterHighscoreState(level);
291 h = new Highscore(name, score); 300 }
292 } 301 }
293 302 }
294 fclose(hslist); 303 }
295 304
296 if (h->getLevel() < level) 305 SDL_Delay(5);
297 { 306 }
298 return new EnterHighscoreState(level);
299 } else {
300 return new DisplayAndReturnLocalHighscoreListState();
301 }
302 }
303 } else {
304 return new EnterHighscoreState(level);
305 }
306 }
307 }
308 }
309
310 SDL_Delay(5);
311 }
312} 307}
313 308
314bool PlayGameState::move(int x, int y) 309bool PlayGameState::move(int x, int y) {
315{ 310 wrap(x, y);
316 wrap(x, y);
317 311
318 // Are we at the event? 312 // Are we at the event?
319 if ((x==15)&&(y==15)) 313 if ((x == 15) && (y == 15)) {
320 { 314 return true;
321 return true; 315 }
322 }
323 316
324 // Can we even go there? 317 // Can we even go there?
325 if (!board->isObstructed(x,y)) 318 if (!board->isObstructed(x, y)) {
326 { 319 playerx = x;
327 playerx = x; 320 playery = y;
328 playery = y; 321 }
329 }
330 322
331 return false; 323 return false;
332} 324}
333 325
334GameBoard::GameBoard(int level, int playerx, int playery) 326GameBoard::GameBoard(int level, int playerx, int playery) {
335{ 327 for (;;) {
336 for (;;)
337 {
338 initialize(level); 328 initialize(level);
339 updateable.set(); 329 updateable.set();
340 oldx = playerx; 330 oldx = playerx;
341 oldy = playery; 331 oldy = playery;
342 332
343 for (int i=0; i<50; i++) 333 for (int i = 0; i < 50; i++) {
344 {
345 tick(playerx, playery); 334 tick(playerx, playery);
346 } 335 }
347 336
348 if (solve(playerx, playery)) 337 if (solve(playerx, playery)) {
349 {
350 break; 338 break;
351 } else { 339 } else {
352 std::cout << "Impossible board: " << playerx << "," << playery << "," << dump() << std::endl; 340 std::cout << "Impossible board: " << playerx << "," << playery << ","
341 << dump() << std::endl;
353 } 342 }
354 } 343 }
355} 344}
356 345
357void GameBoard::tick(int playerx, int playery) 346void GameBoard::tick(int playerx, int playery) {
358{ 347 board_type temp{blocks};
359 board_type temp {blocks}; 348 board_type tempdateable{updateable};
360 board_type tempdateable {updateable}; 349 if ((playerx != oldx) || (playery != oldy)) {
361 if ((playerx != oldx) || (playery != oldy)) 350 for (int dy = -1; dy <= 1; dy++) {
362 { 351 for (int dx = -1; dx <= 1; dx++) {
363 for (int dy = -1; dy <= 1; dy++) 352 int tdx = oldx + dx;
364 { 353 int tdy = oldy + dy;
365 for (int dx = -1; dx <=1; dx++)
366 {
367 int tdx = oldx+dx;
368 int tdy = oldy+dy;
369 wrap(tdx, tdy); 354 wrap(tdx, tdy);
370 tempdateable.set(tdx+tdy*WIDTH); 355 tempdateable.set(tdx + tdy * WIDTH);
371 356
372 tdx = playerx+dx; 357 tdx = playerx + dx;
373 tdy = playery+dy; 358 tdy = playery + dy;
374 wrap(tdx, tdy); 359 wrap(tdx, tdy);
375 tempdateable.set(tdx+tdy*WIDTH); 360 tempdateable.set(tdx + tdy * WIDTH);
376 } 361 }
377 } 362 }
378 } 363 }
@@ -382,135 +367,108 @@ void GameBoard::tick(int playerx, int playery)
382 367
383 updateable.reset(); 368 updateable.reset();
384 369
385 for (int y=0;y<HEIGHT;y++) 370 for (int y = 0; y < HEIGHT; y++) {
386 { 371 for (int x = 0; x < WIDTH; x++) {
387 for (int x=0;x<WIDTH;x++) 372 if (((x == 15) && (y == 15)) || (!tempdateable[x + y * WIDTH])) {
388 { 373 continue;
389 if (((x==15)&&(y==15)) || (!tempdateable[x+y*WIDTH])) 374 }
390 { 375
391 continue; 376 blocks[x + y * WIDTH] = applyNeighbors(x, y, temp, playerx, playery);
392 } 377
393 378 if (temp[x + y * WIDTH] != blocks[x + y * WIDTH]) {
394 blocks[x+y*WIDTH] = applyNeighbors(x, y, temp, playerx, playery); 379 for (int dy = -1; dy <= 1; dy++) {
395 380 for (int dx = -1; dx <= 1; dx++) {
396 if (temp[x+y*WIDTH] != blocks[x+y*WIDTH]) 381 int tdx = x + dx;
397 { 382 int tdy = y + dy;
398 for (int dy = -1; dy <= 1; dy++)
399 {
400 for (int dx = -1; dx <=1; dx++)
401 {
402 int tdx = x+dx;
403 int tdy = y+dy;
404 wrap(tdx, tdy); 383 wrap(tdx, tdy);
405 updateable.set(tdx+tdy*WIDTH); 384 updateable.set(tdx + tdy * WIDTH);
406 } 385 }
407 } 386 }
408 } 387 }
409 } 388 }
410 } 389 }
411} 390}
412 391
413bool GameBoard::applyNeighbors( 392bool GameBoard::applyNeighbors(int x, int y, const board_type& temp,
414 int x, 393 int playerx, int playery) const {
415 int y, 394 int neighbors = 0;
416 const board_type& temp, 395
417 int playerx, 396 incrementIfNeighbor(x - 1, y - 1, temp, playerx, playery, neighbors);
418 int playery) const 397 incrementIfNeighbor(x - 1, y, temp, playerx, playery, neighbors);
419{ 398 incrementIfNeighbor(x - 1, y + 1, temp, playerx, playery, neighbors);
420 int neighbors = 0; 399 incrementIfNeighbor(x, y - 1, temp, playerx, playery, neighbors);
421 400 incrementIfNeighbor(x, y + 1, temp, playerx, playery, neighbors);
422 incrementIfNeighbor(x-1, y-1, temp, playerx, playery, neighbors); 401 incrementIfNeighbor(x + 1, y - 1, temp, playerx, playery, neighbors);
423 incrementIfNeighbor(x-1, y , temp, playerx, playery, neighbors); 402 incrementIfNeighbor(x + 1, y, temp, playerx, playery, neighbors);
424 incrementIfNeighbor(x-1, y+1, temp, playerx, playery, neighbors); 403 incrementIfNeighbor(x + 1, y + 1, temp, playerx, playery, neighbors);
425 incrementIfNeighbor(x , y-1, temp, playerx, playery, neighbors); 404
426 incrementIfNeighbor(x , y+1, temp, playerx, playery, neighbors); 405 if (temp[x + y * WIDTH]) {
427 incrementIfNeighbor(x+1, y-1, temp, playerx, playery, neighbors); 406 return ((neighbors >= 1) && (neighbors <= 4));
428 incrementIfNeighbor(x+1, y , temp, playerx, playery, neighbors); 407 } else {
429 incrementIfNeighbor(x+1, y+1, temp, playerx, playery, neighbors); 408 return (neighbors == 3);
430 409 }
431 if (temp[x+y*WIDTH])
432 {
433 return ((neighbors >= 1) && (neighbors <= 4));
434 } else {
435 return (neighbors == 3);
436 }
437} 410}
438 411
439void GameBoard::render(SDL_Renderer* renderer, int level) const 412void GameBoard::render(SDL_Renderer* renderer, int level) const {
440{ 413 SDL_Rect block;
441 SDL_Rect block; 414 block.w = 16;
442 block.w = 16; 415 block.h = 16;
443 block.h = 16; 416
444 417 for (int y = 0; y < HEIGHT; y++) {
445 for (int y=0; y<HEIGHT; y++) 418 for (int x = 0; x < WIDTH; x++) {
446 { 419 block.x = x * 16;
447 for (int x=0; x<WIDTH; x++) 420 block.y = y * 16;
448 { 421
449 block.x = x*16; 422 if (blocks[x + y * WIDTH]) {
450 block.y = y*16; 423 setRendererAliveColor(renderer, level);
451 424 } else {
452 if (blocks[x+y*WIDTH]) 425 setRendererDeadColor(renderer, level);
453 { 426 }
454 setRendererAliveColor(renderer, level); 427
455 } else { 428 SDL_RenderFillRect(renderer, &block);
456 setRendererDeadColor(renderer, level); 429 }
457 } 430 }
458
459 SDL_RenderFillRect(renderer, &block);
460 }
461 }
462} 431}
463 432
464bool GameBoard::isObstructed(int x, int y) const 433bool GameBoard::isObstructed(int x, int y) const {
465{ 434 return blocks[x + y * WIDTH] || (x == 15 && y == 15);
466 return blocks[x+y*WIDTH] || (x == 15 && y == 15);
467} 435}
468 436
469void GameBoard::initialize(int level) 437void GameBoard::initialize(int level) {
470{ 438 for (int y = 0; y < HEIGHT; y++) {
471 for (int y=0; y<HEIGHT; y++) 439 for (int x = 0; x < WIDTH; x++) {
472 { 440 blocks[x + y * WIDTH] = false;
473 for (int x=0; x<WIDTH; x++) 441
474 { 442 switch (level / 10 + 1) {
475 blocks[x+y*WIDTH] = false; 443 case 1:
476 444 if ((x > 13) && (x < 17) && (y > 13) && (y < 17)) {
477 switch (level/10+1) 445 blocks[x + y * WIDTH] = rand() % 2;
478 { 446 }
479 case 1: 447 break;
480 if ((x>13)&&(x<17)&&(y>13)&&(y<17)) 448 case 2:
481 { 449 case 3:
482 blocks[x+y*WIDTH] = rand() % 2; 450 if ((x > 12) && (x < 18) && (y > 12) && (y < 18)) {
483 } 451 blocks[x + y * WIDTH] = rand() % 2;
484 break; 452 }
485 case 2: 453 break;
486 case 3: 454 case 4:
487 if ((x>12)&&(x<18)&&(y>12)&&(y<18)) 455 case 5:
488 { 456 if ((x > 11) && (x < 19) && (y > 11) && (y < 19)) {
489 blocks[x+y*WIDTH] = rand() % 2; 457 blocks[x + y * WIDTH] = rand() % 2;
490 } 458 }
491 break; 459 break;
492 case 4: 460 default:
493 case 5: 461 blocks[x + y * WIDTH] = rand() % 2;
494 if ((x>11)&&(x<19)&&(y>11)&&(y<19)) 462 }
495 { 463 }
496 blocks[x+y*WIDTH] = rand() % 2; 464 }
497 } 465
498 break; 466 blocks[15 + 15 * WIDTH] = false;
499 default:
500 blocks[x+y*WIDTH] = rand() % 2;
501 }
502 }
503 }
504
505 blocks[15+15*WIDTH] = false;
506} 467}
507 468
508bool GameBoard::operator<(const GameBoard& other) const 469bool GameBoard::operator<(const GameBoard& other) const {
509{ 470 for (int i = WIDTH * HEIGHT - 1; i >= 0; i--) {
510 for (int i = WIDTH*HEIGHT-1; i >= 0; i--) 471 if (blocks[i] ^ other.blocks[i]) {
511 {
512 if (blocks[i] ^ other.blocks[i])
513 {
514 return other.blocks[i]; 472 return other.blocks[i];
515 } 473 }
516 } 474 }
@@ -518,8 +476,7 @@ bool GameBoard::operator<(const GameBoard& other) const
518 return false; 476 return false;
519} 477}
520 478
521bool GameBoard::solve(int playerx, int playery) const 479bool GameBoard::solve(int playerx, int playery) const {
522{
523 std::deque<std::tuple<GameBoard, coord, int>> search; 480 std::deque<std::tuple<GameBoard, coord, int>> search;
524 std::unordered_map<board_type, board_type> done; 481 std::unordered_map<board_type, board_type> done;
525 482
@@ -532,12 +489,10 @@ bool GameBoard::solve(int playerx, int playery) const
532 std::unordered_set<board_type> pastStates; 489 std::unordered_set<board_type> pastStates;
533 pastStates.insert(original.blocks); 490 pastStates.insert(original.blocks);
534 491
535 while (original.updateable.any()) 492 while (original.updateable.any()) {
536 {
537 original.tick(playerx, playery); 493 original.tick(playerx, playery);
538 494
539 if (pastStates.count(original.blocks)) 495 if (pastStates.count(original.blocks)) {
540 {
541 break; 496 break;
542 } 497 }
543 498
@@ -549,8 +504,7 @@ bool GameBoard::solve(int playerx, int playery) const
549 504
550 // Use breadth first search to find a solution. 505 // Use breadth first search to find a solution.
551 bool exists = false; 506 bool exists = false;
552 while (!search.empty()) 507 while (!search.empty()) {
553 {
554 auto cur = std::move(search.front()); 508 auto cur = std::move(search.front());
555 search.pop_front(); 509 search.pop_front();
556 510
@@ -559,8 +513,7 @@ bool GameBoard::solve(int playerx, int playery) const
559 int cns = std::get<2>(cur); 513 int cns = std::get<2>(cur);
560 514
561 // If it has been over 100 generations, give up. 515 // If it has been over 100 generations, give up.
562 if (cns > 100) 516 if (cns > 100) {
563 {
564 continue; 517 continue;
565 } 518 }
566 519
@@ -568,8 +521,7 @@ bool GameBoard::solve(int playerx, int playery) const
568 int cply = std::get<1>(cpl); 521 int cply = std::get<1>(cpl);
569 522
570 // If this section of this board state has already been checked, skip it. 523 // If this section of this board state has already been checked, skip it.
571 if (done.count(cbr.blocks) && done.at(cbr.blocks)[cplx+cply*WIDTH]) 524 if (done.count(cbr.blocks) && done.at(cbr.blocks)[cplx + cply * WIDTH]) {
572 {
573 continue; 525 continue;
574 } 526 }
575 527
@@ -579,44 +531,39 @@ bool GameBoard::solve(int playerx, int playery) const
579 board_type flood; 531 board_type flood;
580 std::deque<coord> front; 532 std::deque<coord> front;
581 front.push_front(cpl); 533 front.push_front(cpl);
582 flood[cplx+cply*WIDTH] = true; 534 flood[cplx + cply * WIDTH] = true;
583 535
584 std::set<coord> edges; 536 std::set<coord> edges;
585 537
586 while (!front.empty()) 538 while (!front.empty()) {
587 {
588 coord frontLoc = std::move(front.front()); 539 coord frontLoc = std::move(front.front());
589 front.pop_front(); 540 front.pop_front();
590 541
591 // Iterate over the positions 4-adjacent to the current one. 542 // Iterate over the positions 4-adjacent to the current one.
592 for (coord& fc : std::list<coord>{ 543 for (coord& fc : std::list<coord>{
593 {std::get<0>(frontLoc) - 1, std::get<1>(frontLoc) }, 544 {std::get<0>(frontLoc) - 1, std::get<1>(frontLoc)},
594 {std::get<0>(frontLoc) + 1, std::get<1>(frontLoc) }, 545 {std::get<0>(frontLoc) + 1, std::get<1>(frontLoc)},
595 {std::get<0>(frontLoc) , std::get<1>(frontLoc) - 1}, 546 {std::get<0>(frontLoc), std::get<1>(frontLoc) - 1},
596 {std::get<0>(frontLoc) , std::get<1>(frontLoc) + 1}, 547 {std::get<0>(frontLoc), std::get<1>(frontLoc) + 1},
597 }) 548 }) {
598 {
599 wrap(std::get<0>(fc), std::get<1>(fc)); 549 wrap(std::get<0>(fc), std::get<1>(fc));
600 int fcx = std::get<0>(fc); 550 int fcx = std::get<0>(fc);
601 int fcy = std::get<1>(fc); 551 int fcy = std::get<1>(fc);
602 552
603 // If this position is already in the flood, skip it. 553 // If this position is already in the flood, skip it.
604 if (flood[fcx+fcy*WIDTH]) 554 if (flood[fcx + fcy * WIDTH]) {
605 {
606 continue; 555 continue;
607 } 556 }
608 557
609 // If the player could not move into this position, skip it. 558 // If the player could not move into this position, skip it.
610 if (cbr.isObstructed(fcx, fcy)) 559 if (cbr.isObstructed(fcx, fcy)) {
611 {
612 continue; 560 continue;
613 } 561 }
614 562
615 // If this position is adjacent to the event, then the board is 563 // If this position is adjacent to the event, then the board is
616 // solvable. 564 // solvable.
617 if (((fcx == 15) && ((fcy == 14) || (fcy == 16))) || 565 if (((fcx == 15) && ((fcy == 14) || (fcy == 16))) ||
618 ((fcy == 15) && ((fcx == 14) || (fcx == 16)))) 566 ((fcy == 15) && ((fcx == 14) || (fcx == 16)))) {
619 {
620 exists = true; 567 exists = true;
621 break; 568 break;
622 } 569 }
@@ -625,12 +572,9 @@ bool GameBoard::solve(int playerx, int playery) const
625 // the start or end positions to change. This is more efficient than 572 // the start or end positions to change. This is more efficient than
626 // copying the board state and then running tick. 573 // copying the board state and then running tick.
627 bool changed = false; 574 bool changed = false;
628 for (int dy = -1; dy <= 1; dy++) 575 for (int dy = -1; dy <= 1; dy++) {
629 { 576 for (int dx = -1; dx <= 1; dx++) {
630 for (int dx = -1; dx <=1; dx++) 577 if (dx == 0 && dy == 0) {
631 {
632 if (dx == 0 && dy == 0)
633 {
634 continue; 578 continue;
635 } 579 }
636 580
@@ -639,13 +583,7 @@ bool GameBoard::solve(int playerx, int playery) const
639 wrap(cpldx, cpldy); 583 wrap(cpldx, cpldy);
640 584
641 if (cbr.isObstructed(cpldx, cpldy) != 585 if (cbr.isObstructed(cpldx, cpldy) !=
642 applyNeighbors( 586 applyNeighbors(cpldx, cpldy, cbr.blocks, fcx, fcy)) {
643 cpldx,
644 cpldy,
645 cbr.blocks,
646 fcx,
647 fcy))
648 {
649 changed = true; 587 changed = true;
650 break; 588 break;
651 } 589 }
@@ -655,43 +593,33 @@ bool GameBoard::solve(int playerx, int playery) const
655 wrap(fcxdx, fcydy); 593 wrap(fcxdx, fcydy);
656 594
657 if (cbr.isObstructed(fcxdx, fcydy) != 595 if (cbr.isObstructed(fcxdx, fcydy) !=
658 applyNeighbors( 596 applyNeighbors(fcxdx, fcydy, cbr.blocks, fcx, fcy)) {
659 fcxdx,
660 fcydy,
661 cbr.blocks,
662 fcx,
663 fcy))
664 {
665 changed = true; 597 changed = true;
666 break; 598 break;
667 } 599 }
668 } 600 }
669 601
670 if (changed) 602 if (changed) {
671 {
672 break; 603 break;
673 } 604 }
674 } 605 }
675 606
676 // If moving to this position would change the board state, add it to 607 // If moving to this position would change the board state, add it to
677 // the set of edges; otherwise, add it to the flood and the flood front. 608 // the set of edges; otherwise, add it to the flood and the flood front.
678 if (changed) 609 if (changed) {
679 {
680 edges.insert(fc); 610 edges.insert(fc);
681 } else { 611 } else {
682 flood[fcx+fcy*WIDTH] = true; 612 flood[fcx + fcy * WIDTH] = true;
683 front.push_back(fc); 613 front.push_back(fc);
684 } 614 }
685 } 615 }
686 616
687 if (exists) 617 if (exists) {
688 {
689 break; 618 break;
690 } 619 }
691 } 620 }
692 621
693 if (exists) 622 if (exists) {
694 {
695 break; 623 break;
696 } 624 }
697 625
@@ -699,8 +627,7 @@ bool GameBoard::solve(int playerx, int playery) const
699 done[cbr.blocks] |= flood; 627 done[cbr.blocks] |= flood;
700 628
701 // Add the edges to the search queue. 629 // Add the edges to the search queue.
702 for (const coord& newLoc : edges) 630 for (const coord& newLoc : edges) {
703 {
704 GameBoard nextState1 = cbr; 631 GameBoard nextState1 = cbr;
705 nextState1.tick(std::get<0>(newLoc), std::get<1>(newLoc)); 632 nextState1.tick(std::get<0>(newLoc), std::get<1>(newLoc));
706 633
@@ -710,12 +637,10 @@ bool GameBoard::solve(int playerx, int playery) const
710 std::unordered_set<board_type> pastStates; 637 std::unordered_set<board_type> pastStates;
711 pastStates.insert(nextState1.blocks); 638 pastStates.insert(nextState1.blocks);
712 639
713 while (nextState1.updateable.any()) 640 while (nextState1.updateable.any()) {
714 {
715 nextState1.tick(std::get<0>(newLoc), std::get<1>(newLoc)); 641 nextState1.tick(std::get<0>(newLoc), std::get<1>(newLoc));
716 642
717 if (pastStates.count(nextState1.blocks)) 643 if (pastStates.count(nextState1.blocks)) {
718 {
719 break; 644 break;
720 } 645 }
721 646
@@ -723,10 +648,9 @@ bool GameBoard::solve(int playerx, int playery) const
723 } 648 }
724 649
725 if (!done.count(nextState1.blocks) || 650 if (!done.count(nextState1.blocks) ||
726 !done.at(nextState1.blocks) 651 !done.at(nextState1.blocks)[std::get<0>(newLoc) +
727 [std::get<0>(newLoc) + std::get<1>(newLoc)*WIDTH]) 652 std::get<1>(newLoc) * WIDTH]) {
728 { 653 search.emplace_back(std::move(nextState1), newLoc, cns + 1);
729 search.emplace_back(std::move(nextState1), newLoc, cns+1);
730 } 654 }
731 } 655 }
732 } 656 }
@@ -734,13 +658,12 @@ bool GameBoard::solve(int playerx, int playery) const
734 return exists; 658 return exists;
735} 659}
736 660
737std::string GameBoard::dump() const 661std::string GameBoard::dump() const {
738{
739 std::stringstream output; 662 std::stringstream output;
740 output << std::hex; 663 output << std::hex;
741 for (int i=0; i<WIDTH*HEIGHT/4; i++) 664 for (int i = 0; i < WIDTH * HEIGHT / 4; i++) {
742 { 665 int chunk = (8 * blocks[i * 4]) + (4 * blocks[i * 4 + 1]) +
743 int chunk = (8 * blocks[i*4]) + (4 * blocks[i*4+1]) + (2 * blocks[i*4+2]) + blocks[i*4+3]; 666 (2 * blocks[i * 4 + 2]) + blocks[i * 4 + 3];
744 output << chunk; 667 output << chunk;
745 } 668 }
746 669