]> git.lizzy.rs Git - ttfe.git/blob - main.c
Use escape sequence to clear the entire screen
[ttfe.git] / main.c
1 #include "main.h"
2
3 #define DBG 0
4
5 bool move_possible_north(board *b);
6 bool move_possible_south(board *b);
7 bool move_possible_east(board *b);
8 bool move_possible_west(board *b);
9
10 void move_north(board *b);
11 void move_south(board *b);
12 void move_east(board *b);
13 void move_west(board *b);
14 void merge(board *b, const int d);
15 void merge_north(board *b);
16 void merge_south(board *b);
17 void merge_east(board *b);
18 void merge_west(board *b);
19
20 void place_new_piece(board *b);
21 void game_loop(board *b);
22
23 board* new_board() {
24         board *tmp = malloc(sizeof(board));
25         init_board(tmp);
26         return tmp;
27 }
28
29 void init_board(board *b) {
30         for(int i = 0; i < 4; ++i) {
31                 for(int j = 0; j < 4; ++j)
32                         b->x[i][j] = 0;
33         }
34         b->points = 0;
35         b->num_p = 0;
36         srand((uint)time(NULL));
37         place_new_piece(b);
38         // second piece will be placed in game_loop
39 }
40
41 void game_start() {
42         printf("\e[?1049h");
43         board *b = new_board();
44         game_loop(b);
45         print_score(b);
46         free_board(b);
47         printf("\e[?1049l");
48 }
49
50 void game_loop(board *b) {
51         char c[16];
52         int d;
53         bool r = true;
54         while(move_possible_any(b)) {
55                 place_new_piece(b);
56                 print_board(b);
57                 INPUT:
58                 printf("Make a move:\n");
59                 fgets(c, sizeof(c), stdin);
60                 switch(c[0]) {
61                         case 'a':
62                                 d = west;
63                                 break;
64                         case 's':
65                                 d = south;
66                                 break;
67                         case 'w':
68                                 d = north;
69                                 break;
70                         case 'd':
71                                 d = east;
72                                 break;
73                         case 'q':
74                                 r = false;
75                                 break;
76                         default:
77                                 printf("Invalid move: %c\n", c[0]);
78                                 goto INPUT;
79                 }
80                 if(!r)
81                         return;
82                 if(!move_possible(b, d)) {
83                         printf("Move not possible: %c\n", c[0]);
84                         goto INPUT;
85                 }
86                 make_move(b, d);
87         }
88 }
89
90 void place_new_piece(board *b) {
91         int prob = rand() % 100;
92         int possibs[32];
93         uint val = 0;
94         int cnt = 0;
95         int pair = 0;
96         int rx = 0, ry = 0;
97         for(int i = 0; i < 4; ++i) {
98                 for(int j = 0; j < 4; ++j) {
99                         if(b->x[i][j] == 0) {
100                                 possibs[2*cnt] = i;
101                                 possibs[2*cnt+1] = j;
102                                 cnt++;
103                         }
104                 }
105         }
106         assert(cnt > 0);
107         pair = rand() % cnt;
108         rx = possibs[2*pair];
109         ry = possibs[2*pair+1];
110         assert(b->x[rx][ry] == 0);
111         if(prob > 9)
112                 val = 2;
113         else
114                 val = 4;
115         b->x[rx][ry] = val;
116         b->num_p++;
117 }
118
119 void free_board(board *b) {
120         free(b);
121 }
122
123 void make_move(board *b, const int d) {
124         bool ok = (d == south) ||
125                 (d == east) ||
126                 (d == north) ||
127                 (d == west);
128         assert(ok);
129         /*
130          * checked before already
131          * if(!move_possible(b, d))
132          *      return;
133         */
134         move(b, d);
135         merge(b, d);
136         move(b, d);
137 }
138
139 bool move_possible_any(board *b) {
140         if(b->num_p < 16)
141                 return true;
142         if(move_possible_south(b))
143                 return true;
144         if(move_possible_east(b))
145                 return true;
146         if(move_possible_north(b))
147                 return true;
148         if(move_possible_west(b))
149                 return true;
150         return false;
151 }
152
153 bool move_possible(board *b, const int d) {
154         bool ok = (d == south) ||
155                 (d == east) ||
156                 (d == north) ||
157                 (d == west);
158         assert(ok);
159         switch(d) {
160                 case north:
161                         return move_possible_north(b);
162                 case south:
163                         return move_possible_south(b);
164                 case east:
165                         return move_possible_east(b);
166                 case west:
167                         return move_possible_west(b);
168                 default: // will never execute anyway
169                         return false;
170         }
171 }
172
173 void move(board *b, const int d) {
174         bool ok = (d == south) ||
175                 (d == east) ||
176                 (d == north) ||
177                 (d == west);
178         assert(ok);
179         switch(d) {
180                 case north:
181                         move_north(b);
182                         break;
183                 case south:
184                         move_south(b);
185                         break;
186                 case east:
187                          move_east(b);
188                         break;
189                 case west:
190                         move_west(b);
191                         break;
192                 default: // will never execute anyway
193                         return;
194         }
195 }
196
197 void merge(board *b, const int d) {
198         bool ok = (d == south) ||
199                 (d == east) ||
200                 (d == north) ||
201                 (d == west);
202         assert(ok);
203         switch(d) {
204                 case north:
205                         merge_north(b);
206                         break;
207                 case south:
208                         merge_south(b);
209                         break;
210                 case east:
211                         merge_east(b);
212                         break;
213                 case west:
214                         merge_west(b);
215                         break;
216                 default: // will never execute anyway
217                         return;
218         }
219 }
220
221 bool move_possible_south(board *b) {
222         for(int i = 0; i < 4; ++i) {
223                 for(int j = 0; j < 3; ++j) {
224                         if(b->x[i][j] != 0) {
225                                 if(b->x[i][j+1] == 0)
226                                         return true;
227                                 if(b->x[i][j] == b->x[i][j+1])
228                                         return true;
229                         }
230                 }
231         }
232         return false;
233 }
234
235 bool move_possible_north(board *b) {
236         for(int i = 0; i < 4; ++i) {
237                 for(int j = 1; j < 4; ++j) {
238                         if(b->x[i][j] != 0) {
239                                 if(b->x[i][j-1] == 0)
240                                         return true;
241                                 if(b->x[i][j] == b->x[i][j-1])
242                                         return true;
243                         }
244                 }
245         }
246         return false;
247 }
248
249 bool move_possible_east(board *b) {
250         for(int i = 0; i < 3; ++i) {
251                 for(int j = 0; j < 4; ++j) {
252                         if(b->x[i][j] != 0) {
253                                 if(b->x[i+1][j] == 0)
254                                         return true;
255                                 if(b->x[i+1][j] == b->x[i][j])
256                                         return true;
257                         }
258                 }
259         }
260         return false;
261 }
262
263 bool move_possible_west(board *b) {
264         for(int i = 1; i < 4; ++i) {
265                 for(int j = 0; j < 4; ++j) {
266                         if(b->x[i][j] != 0) {
267                                 if(b->x[i-1][j] == 0)
268                                         return true;
269                                 if(b->x[i-1][j] == b->x[i][j])
270                                         return true;
271                         }
272                 }
273         }
274         return false;
275 }
276
277 void move_north(board *b) {
278         int k;
279         for(int i = 0; i < 4; ++i) {
280                 for(int j = 1; j < 4; ++j) {
281                         if(b->x[i][j] != 0) {
282                                 k = j;
283                                 while(b->x[i][k-1] == 0) {
284                                         b->x[i][k-1] = b->x[i][k];
285                                         b->x[i][k] = 0;
286                                         k--;
287                                         if(k < 1)
288                                                 break;
289                                 }
290                         }
291                 }
292         }
293 }
294
295 void move_south(board *b) {
296         int k;
297         for(int i = 0; i < 4; ++i) {
298                 for(int j = 2; j >= 0; --j) {
299                         if(b->x[i][j] != 0) {
300                                 k = j;
301                                 while(b->x[i][k+1] == 0) {
302                                         b->x[i][k+1] = b->x[i][k];
303                                         b->x[i][k] = 0;
304                                         k++;
305                                         if(k > 2)
306                                                 break;
307                                 }
308                         }
309                 }
310         }
311 }
312
313 void move_east(board *b) {
314         int k;
315         for(int i = 2; i >= 0; --i) {
316                 for(int j = 0; j < 4; ++j) {
317                         if(b->x[i][j] != 0) {
318                                 k = i;
319                                 while(b->x[k+1][j] == 0) {
320                                         b->x[k+1][j] = b->x[k][j];
321                                         b->x[k][j] = 0;
322                                         k++;
323                                         if(k > 2)
324                                                 break;
325                                 }
326                         }
327                 }
328         }
329 }
330
331 void move_west(board *b) {
332         int k;
333         for(int i = 1; i < 4; ++i) {
334                 for(int j = 0; j < 4; ++j) {
335                         if(b->x[i][j] != 0) {
336                                 k = i;
337                                 while(b->x[k-1][j] == 0) {
338                                         b->x[k-1][j] = b->x[k][j];
339                                         b->x[k][j] = 0;
340                                         k--;
341                                         if(k < 1)
342                                                 break;
343                                 }
344                         }
345                 }
346         }
347 }
348
349 void merge_north(board *b) {
350         for(int i = 0; i < 4; ++i) {
351                 for(int j = 1; j < 4; ++j) {
352                         if(b->x[i][j] != 0 && b->x[i][j] == b->x[i][j-1]) {
353                                 b->x[i][j-1] *= 2;
354                                 b->x[i][j] = 0;
355                                 b->num_p--;
356                                 b->points += b->x[i][j-1];
357                         }
358                 }
359         }
360 }
361
362 void merge_south(board *b) {
363         for(int i = 0; i < 4; ++i) {
364                 for(int j = 2; j >= 0; --j) {
365                         if(b->x[i][j] != 0 && b->x[i][j] == b->x[i][j+1]) {
366                                 b->x[i][j+1] *= 2;
367                                 b->x[i][j] = 0;
368                                 b->num_p--;
369                                 b->points += b->x[i][j+1];
370                         }
371                 }
372         }
373 }
374
375 void merge_east(board *b) {
376         for(int i = 2; i >= 0; --i) {
377                 for(int j = 0; j < 4; ++j) {
378                         if(b->x[i][j] != 0 && b->x[i+1][j] == b->x[i][j]) {
379                                 b->x[i+1][j] *= 2;
380                                 b->points += b->x[i+1][j];
381                                 b->num_p--;
382                                 b->x[i][j] = 0;
383                         }
384                 }
385         }
386 }
387
388 void merge_west(board *b) {     
389         for(int i = 1; i < 4; ++i) {
390                 for(int j = 0; j < 4; ++j) {
391                         if(b->x[i][j] != 0 && b->x[i-1][j] == b->x[i][j]) {
392                                 b->x[i-1][j] *= 2;
393                                 b->points += b->x[i-1][j];
394                                 b->num_p--;
395                                 b->x[i][j] = 0;
396                         }
397                 }
398         }
399 }
400
401 void print_sep() {
402         printf("||--------------------------------------------------------------||\n");
403 }
404
405 void print_board_line(board *b, int l) {
406         printf("||\t%u\t|\t%u\t|\t%u\t|\t%u\t||\n", b->x[0][l], b->x[1][l], b->x[2][l], b->x[3][l]); 
407         print_sep();
408 }
409
410 void print_board(board *b) {
411         printf("\e[2J\e[0;0H");
412         printf("Score: %u\n", b->points);
413         print_sep();
414         for(int i = 0; i < 4; ++i) {
415                 print_board_line(b, i);
416         }
417         printf("\n");
418 }
419
420 void print_score(board *b) {
421         printf("Game Over\nScore:%u\n", b->points);
422 }
423
424 void merge_test1() {
425         board *b = new_board();
426         b->x[2][0] = 2;
427         b->x[3][0] = 2;
428         merge_east(b);
429         assert(b->x[3][0] == 4);
430 }
431
432 void merge_test2() {
433         board *b = new_board();
434         b->x[2][0] = 2;
435         b->x[3][0] = 2;
436         print_board(b);
437         move_west(b);
438         print_board(b);
439         merge_west(b);
440         print_board(b);
441         assert(b->x[0][0] == 4);
442 }
443
444 void merge_test3() {
445         board *b = new_board();
446         b->x[0][0] = 2;
447         b->x[0][1] = 2;
448         print_board(b);
449         merge_north(b);
450         print_board(b);
451         assert(b->x[0][0] == 4);
452 }
453
454 void merge_test4() {
455         board *b = new_board();
456         b->x[0][2] = 2;
457         b->x[0][3] = 2;
458         print_board(b);
459         merge_south(b);
460         print_board(b);
461         assert(b->x[0][3] == 4);
462 }
463
464 void move_merge_test1() {
465         board *b = new_board();
466         b->x[2][0] = 4;
467         b->x[3][0] = 2;
468         b->x[3][2] = 2;
469         print_board(b);
470         move_south(b);
471         print_board(b);
472         merge_south(b);
473         print_board(b);
474         assert(b->x[3][3] == 4);
475 }
476
477 void move_north_test() {
478         board *b = new_board();
479         b->x[2][3] = 8;
480         b->x[2][2] = 0;
481         b->x[2][1] = 0;
482         b->x[2][0] = 0;
483         b->x[0][1] = 2;
484         b->x[0][0] = 0;
485         b->x[3][0] = 4;
486         b->x[3][1] = 2;
487         b->x[3][2] = 3;
488         b->x[3][3] = 16;
489         print_board(b);
490         move_north(b);
491         merge_north(b);
492         move_north(b);
493         print_board(b);
494         assert(b->x[2][0] == 8);
495         assert(b->x[0][0] == 2);
496 }
497
498 void move_merge_test2() {
499         board *b = new_board();
500         b->x[3][0] = 2;
501         b->x[3][1] = 2;
502         b->x[3][2] = 4;
503         b->x[3][3] = 32;
504         print_board(b);
505         move_south(b);
506         merge_south(b);
507         move_south(b);
508         print_board(b);
509         assert(b->x[3][1] == 4);
510 }
511
512 void move_merge_test3() {
513         board *b = new_board();
514         b->x[0][0] = 0;
515         b->x[0][1] = 0;
516         b->x[0][2] = 0;
517         b->x[0][3] = 2;
518         b->x[1][0] = 0;
519         b->x[1][1] = 0;
520         b->x[1][2] = 0;
521         b->x[1][3] = 8;
522         b->x[2][0] = 0;
523         b->x[2][1] = 0;
524         b->x[2][2] = 0;
525         b->x[2][3] = 4;
526         b->x[3][0] = 2;
527         b->x[3][1] = 2;
528         b->x[3][2] = 4;
529         b->x[3][3] = 16;
530         print_board(b);
531         move_south(b);
532         merge_south(b);
533         move_south(b);
534         print_board(b);
535         assert(b->x[3][1] == 4);
536 }
537
538 void run_tests() {
539         /*
540         merge_test1();
541         merge_test2();
542         merge_test3();
543         merge_test4();
544         move_merge_test1();
545         move_north_test();
546         */
547         move_merge_test2();
548         move_merge_test3();
549 }
550
551 int main() {
552 #if DBG
553         run_tests();
554 #else
555         game_start();
556 #endif
557 }