From c39ad6eb10bea035fbe1b88f9bfcf77d0fd3d7b3 Mon Sep 17 00:00:00 2001 From: Robby Zambito Date: Sun, 21 Nov 2021 16:14:41 -0500 Subject: Improved on some readability issues Also made the apply_move function a bit more efficient, and return true if the move was valid. This helps because we can simply use the apply_move function for checking the validity of a move, rather than having a seperate function do similar logic. Use readline.h to read input from the user instead of getline. This adds some quality-of-life improvements. --- src/game_loop.c | 176 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 97 insertions(+), 79 deletions(-) diff --git a/src/game_loop.c b/src/game_loop.c index bcf7eb7..0ba2be6 100644 --- a/src/game_loop.c +++ b/src/game_loop.c @@ -19,6 +19,8 @@ #define _GNU_SOURCE #include +#include +#include #include #include #include @@ -54,50 +56,61 @@ static int player_number_from_color(enum player_color player) { } } -static void prompt_player(enum player_color current_player) { - printf("Player %d [h for help] > ", player_number_from_color(current_player)); +static char *prompt_player(enum player_color current_player) { + switch (current_player) { + case WHITE: + return "Player 1 [h for help] > "; + case BLACK: + return "Player 2 [h for help] > "; + default: + perror("There is no current player"); + exit(EXIT_FAILURE); + } } static void print_help() { puts("To enter a move, enter the two row and column seperated by spaces.\n" "For example `0 0` will select the top left corner.\n\n" "p - Print the board again\n" - "g - Drop into a guile repl\n\n" + "g - Drop into a guile repl\n" + "\n" "In the guile repl you can define an AI to use for the current" "player.\n" "After you define an AI for that player, it will be used for the rest " "of the game instead of prompting for input for that user.\n"); } -static struct move get_move(enum player_color board[8][8], - enum player_color current_player) { +static void inner_main(void *closure, int argc, char **argv) { + scm_shell(argc, argv); +} + +static struct move prompt_get_move(enum player_color board[8][8], + enum player_color current_player) { // Initialize move to an invalid move. struct move move = {-1, -1}; + char *prompt = prompt_player(current_player); do { - prompt_player(current_player); - char *input = NULL; - size_t input_length = 0; - - errno = 0; - while (getline(&input, &input_length, stdin) <= 0) { - if (errno != 0) { - perror("Error getting input"); - exit(EXIT_FAILURE); + char *input = readline(prompt); + + if (input != NULL) { + if (STREQ(input, "h")) { + print_help(); + } else if (STREQ(input, "p")) { + print_board(board); + } else if (STREQ(input, "g")) { + int argc = 1; + char **argv = calloc(1, sizeof(char *)); + argv[0] = "othello"; + /*scm_with_guile(void *(*func)(void *), void *data)*/ + scm_boot_guile(argc, argv, inner_main, NULL); + free(argv); + } else { + sscanf(input, "%d %d", &move.row, &move.col); } - } - - // Remove trailing newline - input[strcspn(input, "\n")] = '\0'; - - if (STREQ(input, "h")) { - print_help(); - } else if (STREQ(input, "p")) { - print_board(board); - } else if (STREQ(input, "g")) { - puts("NOT IMPLEMENTED YET!"); } else { - sscanf(input, "%d %d", &move.row, &move.col); + // If input was NULL, we have reached an EOF and would like to exit. + exit(0); } free(input); @@ -106,79 +119,84 @@ static struct move get_move(enum player_color board[8][8], return move; } -static void apply_move(enum player_color board[8][8], +/* Returns true if the move was valid */ +static bool apply_move(enum player_color board[8][8], enum player_color current_player, struct move move) { - if (!is_valid_move(board, current_player, move)) { - - // We should have checked for the validity of the move before we got here. - fprintf(stderr, "The move %d %d was not valid for player %d\n", move.row, - move.col, player_number_from_color(current_player)); - exit(EXIT_FAILURE); - } // Flip in up direction - int up_end = move.row; - for (int i = move.row - 1; i > 0; i--) { - if (board[i][move.col] == EMPTY) { - break; - } else if (board[i][move.col] == current_player) { - up_end = i; - break; + bool flipped_up = false; + for (int i = move.row - 1; + i > 0 && board[i][move.col] != EMPTY && !flipped_up; i--) { + if (board[i][move.col] == current_player) { + for (int j = move.row - 1; j > i; j--) { + board[j][move.col] = current_player; + } + flipped_up = true; } } // Flip in down direction - int down_end = move.row; - for (int i = move.row + 1; i < 8; i++) { - if (board[i][move.col] == EMPTY) { - break; - } else if (board[i][move.col] == current_player) { - down_end = i; - break; + bool flipped_down = false; + for (int i = move.row + 1; + i < 8 && board[i][move.col] == EMPTY && !flipped_down; i++) { + if (board[i][move.col] == current_player) { + for (int j = move.row + 1; j < i; j++) { + board[j][move.col] = current_player; + } + flipped_down = true; } } // Flip in left direction - int left_end = move.col; - for (int i = move.col - 1; i > 0; i--) { - if (board[move.row][i] == EMPTY) { - break; - } else if (board[move.row][i] == current_player) { - left_end = i; - break; + bool flipped_left = false; + for (int i = move.col - 1; + i > 0 && board[move.row][i] == EMPTY && !flipped_left; i--) { + if (board[move.row][i] == current_player) { + for (int j = move.col - 1; j > i; j--) { + board[move.row][j] = current_player; + } + flipped_left = true; } } // Flip in right direction - int right_end = move.col; - for (int i = move.col + 1; i < 8; i++) { - if (board[move.row][i] == EMPTY) { - break; - } else if (board[move.row][i] == current_player) { - right_end = i; - break; + bool flipped_right = false; + for (int i = move.col + 1; + i < 8 && board[move.row][i] == EMPTY && !flipped_right; i++) { + if (board[move.row][i] == current_player) { + for (int j = move.col + 1; j < i; j++) { + board[move.row][j] = current_player; + } + flipped_right = true; } } - for (int i = move.row; i > up_end; i--) { - board[i][move.col] = current_player; - } - for (int i = move.row; i < down_end; i++) { - board[i][move.col] = current_player; - } - for (int i = move.col; i > left_end; i--) { - board[move.row][i] = current_player; - } - for (int i = move.col; i < right_end; i++) { - board[move.row][i] = current_player; - } + return flipped_up || flipped_down || flipped_left || flipped_right; } -enum player_color game_loop(enum player_color board[8][8]) { - enum player_color current_player = WHITE; +static enum player_color current_player; + +enum player_color get_current_player(void) { return current_player; } + +static enum player_color board[8][8]; + +const enum player_color **get_board(void) { + return (const enum player_color **)board; +} + +enum player_color game_loop(enum player_color init_board[8][8]) { + + // Start with the initial board. + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 8; j++) { + board[i][j] = init_board[i][j]; + } + } + + current_player = WHITE; while (has_valid_moves(board, current_player)) { - struct move move = get_move(board, current_player); + struct move move = prompt_get_move(board, current_player); apply_move(board, current_player, move); current_player = other_player(current_player); } @@ -186,8 +204,8 @@ enum player_color game_loop(enum player_color board[8][8]) { int white_score = 0, black_score = 0; for (int row = 0; row < 8; row++) { for (int col = 0; col < 8; col++) { - white_score += board[row][col] == WHITE; - black_score += board[row][col] == BLACK; + white_score += (int)(board[row][col] == WHITE); + black_score += (int)(board[row][col] == BLACK); } } -- cgit v1.2.3