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