From 233750ab72abb2101a9b35211b90c0318020b2c9 Mon Sep 17 00:00:00 2001 From: Robby Zambito Date: Sun, 23 Jan 2022 17:13:28 -0500 Subject: Highlight the previous move. This is particularly helpful when using the game to play on a real board --- cmd/main.c | 2 +- include/othello_board.h | 2 +- include/othello_move.h | 9 ++++++--- src/board.c | 28 +++++++++++++++++++++++++--- src/game_loop.c | 21 +++++++++++++++++---- src/move.c | 47 +++++++++++++++++++++++++++++++++++++---------- 6 files changed, 87 insertions(+), 22 deletions(-) diff --git a/cmd/main.c b/cmd/main.c index 5863889..47df351 100644 --- a/cmd/main.c +++ b/cmd/main.c @@ -118,7 +118,7 @@ int main(int argc, char **argv) { } puts("Here was the final board:"); - print_board(get_board()); + print_board(get_board(), NULL, 0); printf("Final white score: %d\n", white_score); printf("Final black score: %d\n", black_score); diff --git a/include/othello_board.h b/include/othello_board.h index 99ad839..a8299fc 100644 --- a/include/othello_board.h +++ b/include/othello_board.h @@ -32,7 +32,7 @@ enum player_color **copy_board(enum player_color **board); void free_board(enum player_color **board); // Prints the current state of the board, including coordinates in the margins. -void print_board(enum player_color **board); +void print_board(enum player_color **board, struct move *highlighted_moves, size_t highlighted_moves_length); void scm_print_board(SCM board); // Returns the current board. diff --git a/include/othello_move.h b/include/othello_move.h index a1f030d..6b58bbe 100644 --- a/include/othello_move.h +++ b/include/othello_move.h @@ -22,7 +22,9 @@ #include "othello.h" -struct move prompt_get_move(enum player_color current_player); +struct move prompt_get_move(enum player_color current_player, + struct move *flipped_last_turn, + size_t flipped_last_turn_length); struct move get_scm_move(char *strategy_path); // True if move is valid for current_player. @@ -41,8 +43,9 @@ bool has_valid_moves(enum player_color **board, // Returns non-zero number if the move was valid. // Returns the number of flipped tiles. -int apply_move(enum player_color **board, enum player_color current_player, - struct move move); +size_t apply_move(enum player_color **board, enum player_color current_player, + struct move move, struct move **flipped_spots, + size_t *flipped_spots_capacity); // Does not actually modify the current board state. Returns a new board with // the move applied. If the move was not valid, an empty list (nil) is returned. SCM scm_apply_move(SCM move, SCM board, SCM current_player); diff --git a/src/board.c b/src/board.c index 54340e0..315cafe 100644 --- a/src/board.c +++ b/src/board.c @@ -156,14 +156,36 @@ enum player_color **scm_board_to_c_board(SCM scm_board) { return board; } -void print_board(enum player_color **board) { +void print_board(enum player_color **board, struct move *highlighted_moves, + size_t highlighted_moves_length) { puts(" 0 1 2 3 4 5 6 7"); for (int row = 0; row < 8; row++) { printf("%d ", row); for (int col = 0; col < 8; col++) { - printf("%c ", board[row][col]); + bool should_highlight = false; + for (size_t i = 0; !should_highlight && i < highlighted_moves_length; + i++) { + if (highlighted_moves[i].row == row && + highlighted_moves[i].col == col) { + should_highlight = true; + } + } + if (!should_highlight) { + printf("%c ", board[row][col]); + } else { + switch (board[row][col]) { + case WHITE: + printf("W "); + break; + case BLACK: + printf("B "); + break; + case EMPTY: + printf("* "); + } + } } printf("\n"); } @@ -173,5 +195,5 @@ void scm_print_board(SCM scm_board) { enum player_color **board = SCM_UNBNDP(scm_board) ? get_board() : scm_board_to_c_board(scm_board); - print_board(board); + print_board(board, NULL, 0); } diff --git a/src/game_loop.c b/src/game_loop.c index 2af20bd..cc20454 100644 --- a/src/game_loop.c +++ b/src/game_loop.c @@ -67,12 +67,15 @@ enum player_color scm_player_to_c_player(SCM player) { static struct move current_player_move(enum player_color current_player, char *player_one_strategy_path, - char *player_two_strategy_path) { + char *player_two_strategy_path, + struct move *flipped_by_last_turn, + size_t flipped_by_last_turn_length) { struct move move = {-1, -1}; if ((current_player == WHITE && player_one_strategy_path == NULL) || (current_player == BLACK && player_two_strategy_path == NULL)) { - move = prompt_get_move(current_player); + move = prompt_get_move(current_player, flipped_by_last_turn, + flipped_by_last_turn_length); } else if (current_player == WHITE) { move = get_scm_move(player_one_strategy_path); } else if (current_player == BLACK) { @@ -93,10 +96,18 @@ enum player_color game_loop(char *player_one_strategy_path, current_player = WHITE; + struct move *flipped_by_last_turn = malloc(sizeof(struct move)); + size_t flipped_by_last_turn_length = 0; + size_t flipped_by_last_turn_capacity = 1; + while (has_valid_moves(get_board(), current_player)) { struct move move = current_player_move( - current_player, player_one_strategy_path, player_two_strategy_path); - if (apply_move(get_board(), current_player, move)) { + current_player, player_one_strategy_path, player_two_strategy_path, + flipped_by_last_turn, flipped_by_last_turn_length); + + if ((flipped_by_last_turn_length = apply_move( + get_board(), current_player, move, &flipped_by_last_turn, + &flipped_by_last_turn_capacity))) { current_player = other_player; } } @@ -105,6 +116,8 @@ enum player_color game_loop(char *player_one_strategy_path, rl_clear_history(); } + free(flipped_by_last_turn); + return get_winner(get_board(), current_player, white_score, black_score); } diff --git a/src/move.c b/src/move.c index 2f96ca3..9f8df44 100644 --- a/src/move.c +++ b/src/move.c @@ -36,8 +36,10 @@ static void print_help() { "p - Print the board again\n"); } -static char *prompt_player(enum player_color current_player) { - print_board(get_board()); +static char *prompt_player(enum player_color current_player, + struct move *flipped_last_turn, + size_t flipped_last_turn_length) { + print_board(get_board(), flipped_last_turn, flipped_last_turn_length); switch (current_player) { case WHITE: return "Player 1 [h for help] > "; @@ -49,11 +51,14 @@ static char *prompt_player(enum player_color current_player) { } } -struct move prompt_get_move(enum player_color current_player) { +struct move prompt_get_move(enum player_color current_player, + struct move *flipped_last_turn, + size_t flipped_last_turn_length) { // Initialize move to an invalid move. struct move move = {-1, -1}; - char *prompt = prompt_player(current_player); + char *prompt = prompt_player(current_player, flipped_last_turn, + flipped_last_turn_length); do { char *input = readline(prompt); @@ -64,7 +69,7 @@ struct move prompt_get_move(enum player_color current_player) { if (STREQ(input, "h")) { print_help(); } else if (STREQ(input, "p")) { - print_board(get_board()); + print_board(get_board(), flipped_last_turn, flipped_last_turn_length); } else { sscanf(input, "%d %d", &move.row, &move.col); } @@ -82,8 +87,9 @@ struct move prompt_get_move(enum player_color current_player) { // Returns non-zero number if the move was valid. // Returns the number of flipped tiles. -int apply_move(enum player_color **board, enum player_color current_player, - struct move move) { +size_t apply_move(enum player_color **board, enum player_color current_player, + struct move move, struct move **flipped_spots, + size_t *flipped_spots_capacity) { // The move must be a positive position. if (move.row < 0 || move.col < 0) { @@ -107,6 +113,17 @@ int apply_move(enum player_color **board, enum player_color current_player, done_flipping_up_left = false, done_flipping_up_right = false, done_flipping_down_left = false, done_flipping_down_right = false; +#define add_flipped_spot(row_in, col_in) \ + if (flipped_spots != NULL && flipped_spots_capacity != NULL) { \ + if (num_flipped == *flipped_spots_capacity) { \ + *flipped_spots_capacity *= 2; \ + *flipped_spots = reallocarray(*flipped_spots, *flipped_spots_capacity, \ + sizeof(struct move)); \ + } \ + (*flipped_spots)[num_flipped].row = (row_in); \ + (*flipped_spots)[num_flipped].col = (col_in); \ + } + for (int i = 1; i < 8; i++) { if (!done_flipping_up && (move.row - i >= 0) && board[move.row - i][move.col] == current_player) { @@ -122,6 +139,7 @@ int apply_move(enum player_color **board, enum player_color current_player, if (flippable) { for (int j = 0; j < i; j++) { board[move.row - j][move.col] = current_player; + add_flipped_spot(move.row - j, move.col); num_flipped++; } } @@ -143,6 +161,7 @@ int apply_move(enum player_color **board, enum player_color current_player, if (flippable) { for (int j = 0; j < i; j++) { board[move.row + j][move.col] = current_player; + add_flipped_spot(move.row + j, move.col); num_flipped++; } } @@ -164,6 +183,7 @@ int apply_move(enum player_color **board, enum player_color current_player, if (flippable) { for (int j = 0; j < i; j++) { board[move.row][move.col - j] = current_player; + add_flipped_spot(move.row, move.col - j); num_flipped++; } } @@ -185,6 +205,7 @@ int apply_move(enum player_color **board, enum player_color current_player, if (flippable) { for (int j = 0; j < i; j++) { board[move.row][move.col + j] = current_player; + add_flipped_spot(move.row, move.col + j); num_flipped++; } } @@ -206,6 +227,7 @@ int apply_move(enum player_color **board, enum player_color current_player, if (flippable) { for (int j = 0; j < i; j++) { board[move.row - j][move.col - j] = current_player; + add_flipped_spot(move.row - j, move.col - j); num_flipped++; } } @@ -227,6 +249,7 @@ int apply_move(enum player_color **board, enum player_color current_player, if (flippable) { for (int j = 0; j < i; j++) { board[move.row - j][move.col + j] = current_player; + add_flipped_spot(move.row - j, move.col + j); num_flipped++; } } @@ -248,6 +271,7 @@ int apply_move(enum player_color **board, enum player_color current_player, if (flippable) { for (int j = 0; j < i; j++) { board[move.row + j][move.col - j] = current_player; + add_flipped_spot(move.row + j, move.col - j); num_flipped++; } } @@ -269,6 +293,7 @@ int apply_move(enum player_color **board, enum player_color current_player, if (flippable) { for (int j = 0; j < i; j++) { board[move.row + j][move.col + j] = current_player; + add_flipped_spot(move.row + j, move.col + j); num_flipped++; } } @@ -278,6 +303,8 @@ int apply_move(enum player_color **board, enum player_color current_player, } } +#undef add_flipped_spot + return num_flipped; } @@ -294,7 +321,7 @@ SCM scm_apply_move(SCM scm_move, SCM scm_board, SCM scm_player) { SCM res_board; - if (apply_move(board, player, move)) { + if (apply_move(board, player, move, NULL, NULL)) { res_board = scm_board_from_c_board(board); } else { res_board = SCM_EOL; @@ -314,7 +341,7 @@ SCM scm_get_num_flipped_by_move(SCM scm_move, SCM scm_board, SCM scm_player) { enum player_color player = SCM_UNBNDP(scm_player) ? get_current_player() : scm_player_to_c_player(scm_player); - SCM res_num = scm_from_int(apply_move(board, player, move)); + SCM res_num = scm_from_int(apply_move(board, player, move, NULL, NULL)); free_board(board); return res_num; @@ -409,7 +436,7 @@ bool is_valid_move(enum player_color **board, // necessarily mutate the board yet though. enum player_color **b = copy_board(board); // Apply the move to the copy of the board. - bool res = apply_move(b, current_player, move); + bool res = apply_move(b, current_player, move, NULL, NULL); free_board(b); -- cgit v1.2.3