reversi.c 5.3 KB

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