summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobby Zambito <contact@robbyzambito.me>2021-11-21 16:14:41 -0500
committerRobby Zambito <contact@robbyzambito.me>2021-11-21 16:14:41 -0500
commitc39ad6eb10bea035fbe1b88f9bfcf77d0fd3d7b3 (patch)
tree4499b8a3891b37e253a2cfe8157e891a67e50b02
parent0ed931c4ff167c957c0b772b7d3c73a7e6dcb403 (diff)
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.
-rw-r--r--src/game_loop.c176
1 files 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 <errno.h>
+#include <libguile.h>
+#include <readline/readline.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -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);
}
}