main.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdbool.h>
  4. #include <string.h>
  5. #define SIZE 3
  6. #define ROWS SIZE
  7. #define COLS SIZE
  8. typedef enum {
  9. SHAPE_X = 0,
  10. SHAPE_O,
  11. COUNT_SHAPES,
  12. } Shape;
  13. typedef enum {
  14. CELL_EMPTY = 0,
  15. CELL_FULL,
  16. } Cell;
  17. char shape_chars[COUNT_SHAPES] = {
  18. [SHAPE_X] = 'x',
  19. [SHAPE_O] = 'o',
  20. };
  21. typedef struct {
  22. bool quit;
  23. Cell cells[ROWS][COLS];
  24. int filled_count;
  25. int cur_row;
  26. int cur_col;
  27. Shape shape;
  28. } Game;
  29. void game_render(const Game *game)
  30. {
  31. for (int row = 0; row < ROWS; ++row) {
  32. for (int col = 0; col < COLS; ++col) {
  33. bool selected = row == game.cur_row && col == game.cur_col;
  34. putc(selected ? '[' : ' ', stdout);
  35. Cell cell = game.cells[row][col];
  36. putc(cell == CELL_EMPTY ? '.' : shape_chars[cell - CELL_FULL], stdout);
  37. putc(selected ? ']' : ' ', stdout);
  38. }
  39. putc('\n', stdout);
  40. }
  41. }
  42. typedef int Outcome;
  43. bool check_row(const Game *game, int row, Shape s)
  44. {
  45. for (int col = 0; col < COLS; ++col) {
  46. if (game.cells[row][col] - CELL_FULL != s) {
  47. return false;
  48. }
  49. }
  50. return true;
  51. }
  52. bool check_col(const Game *game, int col, Shape s)
  53. {
  54. for (int row = 0; row < ROWS; ++row) {
  55. if (game.cells[row][col] - CELL_FULL != s) {
  56. return false;
  57. }
  58. }
  59. return true;
  60. }
  61. bool check_main_diag(const Game *game, Shape s)
  62. {
  63. for (int i = 0; i < SIZE; ++i) {
  64. if (game.cells[i][i] - CELL_FULL != s) {
  65. return false;
  66. }
  67. }
  68. return true;
  69. }
  70. bool check_sec_diag(const Game *game, Shape s)
  71. {
  72. for (int i = 0; i < SIZE; ++i) {
  73. if (game.cells[i][SIZE - i - 1] - CELL_FULL != s) {
  74. return false;
  75. }
  76. }
  77. return true;
  78. }
  79. typedef int Outcome;
  80. Outcome game_check_victory(Game *game)
  81. {
  82. for (Shape s = 0; s < COUNT_SHAPES; ++s) {
  83. for (int i = 0; i < SIZE; ++i) {
  84. if (check_row(game, i, s)) return s + 1;
  85. if (check_col(game, i, s)) return s + 1;
  86. }
  87. if (check_main_diag(game, s)) return s + 1;
  88. if (check_sec_diag(game, s)) return s + 1;
  89. }
  90. return 0;
  91. }
  92. void game_move(Game *game, char c)
  93. {
  94. switch (c) {
  95. case 'a':
  96. game.cur_col -= 1;
  97. break;
  98. case 'd':
  99. game.cur_col += 1;
  100. break;
  101. case 'w':
  102. game.cur_row -= 1;
  103. break;
  104. case 's':
  105. game.cur_row += 1;
  106. break;
  107. case 'q':
  108. game.quit = true;
  109. break;
  110. case ' ': {
  111. Cell *cell = &game.cells[game.cur_row][game.cur_col];
  112. if (*cell == CELL_EMPTY) {
  113. *cell = CELL_FULL + game.shape;
  114. game.filled_count += 1;
  115. Outcome outcome = game_check_victory(game);
  116. if (outcome) {
  117. game_render(game);
  118. printf("%c won\n", shape_chars[outcome-1]);
  119. game.quit = true;
  120. } else if (game.filled_count == ROWS*COLS) {
  121. game_render(game);
  122. printf("tie\n");
  123. game.quit = true;
  124. }
  125. game.shape = 1 - game.shape;
  126. }
  127. } break;
  128. default:
  129. {}
  130. }
  131. if (game.cur_col < 0) game.cur_col = 0;
  132. if (game.cur_col >= COLS) game.cur_col = COLS-1;
  133. if (game.cur_row < 0) game.cur_row = 0;
  134. if (game.cur_row >= ROWS) game.cur_row = ROWS-1;
  135. }
  136. int main(void)
  137. {
  138. static Game game = {0};
  139. static char cmd[256];
  140. while (!game.quit) {
  141. game_render(&game);
  142. printf("> ");
  143. fgets(cmd, sizeof(cmd), stdin);
  144. size_t n = strlen(cmd);
  145. for (size_t i = 0; i < n; ++i) {
  146. game_move(&game, cmd[i]);
  147. }
  148. }
  149. return 0;
  150. }