reversi.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // Game "Reversi" for Flipper Zero
  2. // Copyright 2023 Dmitry Matyukhin
  3. #include "reversi.h"
  4. // Psst! Most of this file was written with Copilot
  5. // Check if the move is legal by checking if it results in any opponent pieces being captured
  6. bool is_legal_move(int8_t board[BOARD_SIZE][BOARD_SIZE], int row, int col,
  7. int player) {
  8. if (board[row][col] != 0)
  9. return false;
  10. int opponent = -player;
  11. for (int i = -1; i <= 1; i++) {
  12. for (int j = -1; j <= 1; j++) {
  13. if (i == 0 && j == 0)
  14. continue;
  15. int r = row + i, c = col + j;
  16. if (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE &&
  17. board[r][c] == opponent) {
  18. int k = 2;
  19. while (true) {
  20. r += i;
  21. c += j;
  22. if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE)
  23. break;
  24. if (board[r][c] == player)
  25. return true;
  26. if (board[r][c] == 0)
  27. break;
  28. k++;
  29. }
  30. }
  31. }
  32. }
  33. return false;
  34. }
  35. // Check if the game is over by checking if there are no more moves left for
  36. // either player
  37. bool is_game_over(int8_t board[BOARD_SIZE][BOARD_SIZE]) {
  38. for (int i = 0; i < BOARD_SIZE; i++) {
  39. for (int j = 0; j < BOARD_SIZE; j++) {
  40. if (is_legal_move(board, i, j, BLACK) ||
  41. is_legal_move(board, i, j, WHITE)) {
  42. return false;
  43. }
  44. }
  45. }
  46. return true;
  47. }
  48. bool has_legal_moves(int8_t board[BOARD_SIZE][BOARD_SIZE],
  49. int8_t player_color) {
  50. for (int i = 0; i < BOARD_SIZE; i++) {
  51. for (int j = 0; j < BOARD_SIZE; j++) {
  52. if (is_legal_move(board, i, j, player_color)) {
  53. return true;
  54. }
  55. }
  56. }
  57. return false;
  58. }
  59. // Calculate the heuristic value of the current board. This function can
  60. // be replaced with a more complex evaluation function that takes into
  61. // account factors such as mobility, piece square tables, etc.
  62. int heuristic(int8_t board[BOARD_SIZE][BOARD_SIZE]) {
  63. int white = 0, black = 0;
  64. for (int i = 0; i < BOARD_SIZE; i++) {
  65. for (int j = 0; j < BOARD_SIZE; j++) {
  66. if (board[i][j] == 1)
  67. white++;
  68. if (board[i][j] == -1)
  69. black++;
  70. }
  71. }
  72. return white - black;
  73. }
  74. // Make a move on the board and capture any opponent pieces
  75. void make_move(GameState *state, int x, int y, int player) {
  76. state->board[x][y] = player;
  77. int opponent = -player;
  78. for (int i = -1; i <= 1; i++) {
  79. for (int j = -1; j <= 1; j++) {
  80. if (i == 0 && j == 0)
  81. continue;
  82. int r = x + i, c = y + j;
  83. if (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE &&
  84. state->board[r][c] == opponent) {
  85. int k = 2;
  86. while (true) {
  87. r += i;
  88. c += j;
  89. if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE)
  90. break;
  91. if (state->board[r][c] == player) {
  92. r -= i;
  93. c -= j;
  94. while (r != x || c != y) {
  95. state->board[r][c] = player;
  96. r -= i;
  97. c -= j;
  98. }
  99. break;
  100. }
  101. if (state->board[r][c] == 0)
  102. break;
  103. k++;
  104. }
  105. }
  106. }
  107. }
  108. state->is_game_over = is_game_over(state->board);
  109. }
  110. void init_game(GameState *state) {
  111. for (int i = 0; i < BOARD_SIZE; i++) {
  112. for (int j = 0; j < BOARD_SIZE; j++) {
  113. state->board[i][j] = 0;
  114. }
  115. }
  116. // Place the initial pieces
  117. int mid = BOARD_SIZE / 2;
  118. state->board[mid - 1][mid - 1] = WHITE;
  119. state->board[mid][mid] = WHITE;
  120. state->board[mid - 1][mid] = BLACK;
  121. state->board[mid][mid - 1] = BLACK;
  122. state->cursor_x = mid - 1;
  123. state->cursor_y = mid + 1;
  124. // Set up turn order
  125. state->human_color = WHITE;
  126. state->current_player = WHITE;
  127. state->is_game_over = false;
  128. }
  129. void human_move(GameState *game_state) {
  130. if (game_state->current_player != game_state->human_color) {
  131. return;
  132. }
  133. if (is_legal_move(game_state->board, game_state->cursor_x,
  134. game_state->cursor_y, game_state->current_player)) {
  135. make_move(game_state, game_state->cursor_x, game_state->cursor_y,
  136. game_state->current_player);
  137. game_state->current_player = -game_state->current_player;
  138. }
  139. }
  140. void computer_move(GameState *game_state) {
  141. if (game_state->current_player == game_state->human_color) {
  142. return;
  143. }
  144. int best_row = -1, best_col = -1, best_score = -1000000;
  145. for (int i = 0; i < BOARD_SIZE; i++) {
  146. for (int j = 0; j < BOARD_SIZE; j++) {
  147. if (!is_legal_move(game_state->board, i, j, game_state->current_player)) {
  148. continue;
  149. }
  150. int score = heuristic(game_state->board);
  151. if (score > best_score) {
  152. best_score = score;
  153. best_row = i;
  154. best_col = j;
  155. }
  156. }
  157. }
  158. if (best_row != -1) {
  159. make_move(game_state, best_row, best_col, game_state->current_player);
  160. }
  161. if (has_legal_moves(game_state->board, game_state->human_color)) {
  162. game_state->current_player = -game_state->current_player;
  163. }
  164. }