summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobby Zambito <contact@robbyzambito.me>2022-01-21 17:20:17 -0500
committerRobby Zambito <contact@robbyzambito.me>2022-01-21 17:20:17 -0500
commitf1a4b5757f0d20739270b22726ebf8442b13cb50 (patch)
tree93e170ddebc79cf5a41777fc040797bc6dfa5d85 /src
parent3a85be307b6240525f032b9fad5114bdf172bdc1 (diff)
Fleshed out Scheme primitives
* Moved board specific functions from othello.h to new othello_board.h * Removed unused function pointer for player moves * Added prototypes in headers for SCM functions, including scm_get_current_player, * Made get_winner accept a board and current player. This is useful for predictions to see if some move would make the other player a winner. * get_winner also writes the players scores to provided pointers.
Diffstat (limited to 'src')
-rw-r--r--src/board.c86
-rw-r--r--src/game_loop.c25
-rw-r--r--src/move.c134
-rw-r--r--src/valid_moves.c1
4 files changed, 164 insertions, 82 deletions
diff --git a/src/board.c b/src/board.c
index 6859952..a03fddd 100644
--- a/src/board.c
+++ b/src/board.c
@@ -18,14 +18,20 @@
#define _GNU_SOURCE
+#include <libguile.h>
#include <stdlib.h>
#include "othello.h"
+#include "othello_board.h"
#include "othello_move.h"
static enum player_color **board;
-enum player_color **get_board(void) { return board; }
+enum player_color **get_board() { return board; }
+
+SCM scm_get_board() {
+ return scm_board_from_c_board(board);
+}
void initialize_board() {
board = calloc(8, sizeof(enum player_color *));
@@ -47,23 +53,42 @@ void initialize_board() {
board[4][4] = WHITE;
}
-enum player_color get_winner() {
- int white_score = 0, black_score = 0;
+enum player_color get_winner(enum player_color **board,
+ enum player_color current_player, int *white_score,
+ int *black_score) {
+
+ int ws = 0, bs = 0;
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
// This takes advantage of the fact that the 1 is the same thing as a
// true, and 0 is the same thing as a false. This will count the number of
// white and black spaces.
- white_score += (int)(board[row][col] == WHITE);
- black_score += (int)(board[row][col] == BLACK);
+ ws += (int)(board[row][col] == WHITE);
+ bs += (int)(board[row][col] == BLACK);
}
}
+ if (white_score != NULL) {
+ *white_score = ws;
+ }
+ if (black_score != NULL) {
+ *black_score = bs;
+ }
+
return white_score > black_score ? WHITE
: black_score > white_score ? BLACK
: EMPTY;
}
+SCM scm_get_winner(SCM scm_board, SCM scm_current_player) {
+ enum player_color **board = scm_board_to_c_board(scm_board);
+ enum player_color current_player = scm_player_to_c_player(scm_current_player);
+
+ bool res = get_winner(board, current_player, NULL, NULL);
+ free_board(board);
+ return scm_from_bool(res);
+}
+
// Should be freed be the caller
enum player_color **copy_board(enum player_color **other) {
enum player_color **board = calloc(8, sizeof(enum player_color *));
@@ -84,3 +109,54 @@ void free_board(enum player_color **board) {
}
free(board);
}
+
+SCM scm_board_from_c_board(enum player_color **board) {
+ // 2D list of empty rows
+ SCM scm_board =
+ scm_make_list(scm_from_int(8), SCM_EOL);
+
+ for (int i = 0; i < 8; i++) {
+ // cons up each row.
+ for (int j = 7; j >= 0; j--) {
+ if (board[i][j] == WHITE) {
+ scm_list_set_x(scm_board, scm_from_int(i),
+ scm_cons(scm_from_utf8_symbol("white"),
+ scm_list_ref(scm_board, scm_from_int(i))));
+ } else if (board[i][j] == BLACK) {
+ scm_list_set_x(scm_board, scm_from_int(i),
+ scm_cons(scm_from_utf8_symbol("black"),
+ scm_list_ref(scm_board, scm_from_int(i))));
+ } else {
+ scm_list_set_x(scm_board, scm_from_int(i),
+ scm_cons(scm_from_utf8_symbol("empty"),
+ scm_list_ref(scm_board, scm_from_int(i))));
+ }
+ }
+ }
+
+ return scm_board;
+}
+
+enum player_color **scm_board_to_c_board(SCM scm_board) {
+ enum player_color **board = calloc(8, sizeof(enum player_color *));
+ for (int i = 0; i < 8; i++) {
+ board[i] = calloc(8, sizeof(enum player_color));
+ for (int j = 0; j < 8; j++) {
+ if (scm_is_true(
+ scm_eq_p(scm_list_ref(scm_list_ref(scm_board, scm_from_int(i)),
+ scm_from_int(j)),
+ scm_from_utf8_symbol("white")))) {
+ board[i][j] = WHITE;
+ } else if (scm_is_true(scm_eq_p(
+ scm_list_ref(scm_list_ref(scm_board, scm_from_int(i)),
+ scm_from_int(j)),
+ scm_from_utf8_symbol("black")))) {
+ board[i][j] = BLACK;
+ } else {
+ board[i][j] = EMPTY;
+ }
+ }
+ }
+
+ return board;
+}
diff --git a/src/game_loop.c b/src/game_loop.c
index 8186623..f52bdb7 100644
--- a/src/game_loop.c
+++ b/src/game_loop.c
@@ -28,6 +28,7 @@
#include <string.h>
#include "othello.h"
+#include "othello_board.h"
#include "othello_move.h"
#define STREQ(a, b) (strcmp(a, b) == 0)
@@ -36,8 +37,26 @@ static enum player_color current_player;
enum player_color get_current_player(void) { return current_player; }
-struct move (*player_one_get_move)();
-struct move (*player_two_get_move)();
+SCM scm_get_current_player(void) {
+ switch (current_player) {
+ case WHITE:
+ return scm_from_utf8_symbol("white");
+ case BLACK:
+ return scm_from_utf8_symbol("black");
+ default:
+ return scm_from_utf8_symbol("empty");
+ }
+}
+
+enum player_color scm_player_to_c_player(SCM player) {
+ if (scm_is_true(scm_eq_p(player, scm_from_utf8_symbol("white")))) {
+ return WHITE;
+ } else if (scm_is_true(scm_eq_p(player, scm_from_utf8_symbol("black")))) {
+ return BLACK;
+ } else {
+ return EMPTY;
+ }
+}
static struct move current_player_move(enum player_color current_player,
char *player_one_strategy_path,
@@ -81,5 +100,5 @@ enum player_color game_loop(char *player_one_strategy_path,
rl_clear_history();
}
- return get_winner();
+ return get_winner(get_board(), current_player, NULL, NULL);
}
diff --git a/src/move.c b/src/move.c
index 8828ef0..d2a05dd 100644
--- a/src/move.c
+++ b/src/move.c
@@ -25,6 +25,7 @@
#include <readline/readline.h>
#include "othello.h"
+#include "othello_board.h"
#include "othello_move.h"
#define STREQ(a, b) (strcmp(a, b) == 0)
@@ -175,104 +176,87 @@ bool apply_move(enum player_color **board, enum player_color current_player,
return flipped_up || flipped_down || flipped_left || flipped_right;
}
-// Return the current board as a list of lists
-static SCM scm_get_board(void) {
- enum player_color **board = get_board();
- // 2D list of empty spaces
- SCM scm_board =
- scm_make_list(scm_from_int(8), scm_make_list(scm_from_int(0), NULL));
- for (int i = 0; i < 8; i++) {
- for (int j = 7; j >= 0; j--) {
- if (board[i][j] == WHITE) {
- scm_list_set_x(scm_board, scm_from_int(i),
- scm_cons(scm_from_utf8_symbol("white"),
- scm_list_ref(scm_board, scm_from_int(i))));
- } else if (board[i][j] == BLACK) {
- scm_list_set_x(scm_board, scm_from_int(i),
- scm_cons(scm_from_utf8_symbol("black"),
- scm_list_ref(scm_board, scm_from_int(i))));
- } else {
- scm_list_set_x(scm_board, scm_from_int(i),
- scm_cons(scm_from_utf8_symbol("empty"),
- scm_list_ref(scm_board, scm_from_int(i))));
- }
- }
+SCM scm_apply_move(SCM scm_move, SCM scm_board, SCM scm_player) {
+ struct move move = scm_move_to_c_move(scm_move);
+
+ enum player_color **board;
+ if (scm_is_null(scm_board)) {
+ board = copy_board(get_board());
+ } else {
+ board = scm_board_to_c_board(scm_board);
+ }
+
+ enum player_color player;
+ if (scm_is_null(scm_player)) {
+ player = get_current_player();
+ } else {
+ player = scm_player_to_c_player(scm_player);
}
- return scm_board;
+
+ SCM res_board;
+
+ if (apply_move(board, player, move)) {
+ res_board = scm_board_from_c_board(board);
+ } else {
+ res_board = SCM_EOL;
+ }
+
+ free_board(board);
+ return res_board;
}
-static struct move scm_move_to_c_move(SCM scm_move) {
+struct move scm_move_to_c_move(SCM scm_move) {
struct move move = {-1, -1};
move.row = scm_to_int(scm_car(scm_move));
move.col = scm_to_int(scm_cdr(scm_move));
return move;
}
-static SCM scm_current_player(void) {
- switch (get_current_player()) {
- case WHITE:
- return scm_from_utf8_symbol("white");
- case BLACK:
- return scm_from_utf8_symbol("black");
- default:
- return scm_from_utf8_symbol("empty");
- }
+SCM scm_move_from_c_move(struct move move) {
+ return scm_cons(scm_from_int(move.row), scm_from_int(move.col));
}
-static SCM scm_is_valid_move(SCM scm_board, SCM scm_player, SCM scm_move) {
- enum player_color **board = calloc(8, sizeof(enum player_color *));
- for (int i = 0; i < 8; i++) {
- board[i] = calloc(8, sizeof(enum player_color));
- for (int j = 0; j < 8; j++) {
- if (scm_is_true(
- scm_eq_p(scm_list_ref(scm_list_ref(scm_board, scm_from_int(i)),
- scm_from_int(j)),
- scm_from_utf8_symbol("white")))) {
- board[i][j] = WHITE;
- } else if (scm_is_true(scm_eq_p(
- scm_list_ref(scm_list_ref(scm_board, scm_from_int(i)),
- scm_from_int(j)),
- scm_from_utf8_symbol("black")))) {
- board[i][j] = BLACK;
- } else {
- board[i][j] = EMPTY;
- }
- }
- }
+SCM scm_is_valid_move(SCM scm_move, SCM scm_board, SCM scm_player) {
+ enum player_color **board =
+ SCM_UNBNDP(scm_board) ? get_board() : scm_board_to_c_board(scm_board);
- enum player_color current_player = BLACK;
+ enum player_color current_player = SCM_UNBNDP(scm_player)
+ ? get_current_player()
+ : scm_player_to_c_player(scm_player);
struct move move = scm_move_to_c_move(scm_move);
- return scm_from_bool(is_valid_move(board, current_player, move));
-}
+ SCM is_valid = scm_from_bool(is_valid_move(board, current_player, move));
-// Return the list of valid moves on a board for a player
-static SCM scm_valid_moves(SCM scm_board, SCM player) {
- enum player_color **board = calloc(8, sizeof(enum player_color *));
- for (int i = 0; i < 8; i++) {
- board[i] = calloc(8, sizeof(enum player_color));
+ if (!SCM_UNBNDP(scm_board)) {
+ free_board(board);
}
- enum player_color current_player = EMPTY;
+ return is_valid;
+}
- if (scm_is_true(scm_eq_p(player, scm_from_utf8_symbol("white")))) {
- current_player = WHITE;
- } else if (scm_is_true(scm_eq_p(player, scm_from_utf8_symbol("black")))) {
- current_player = BLACK;
- }
- current_player = BLACK;
+// Return the list of valid moves on a board for a player
+SCM scm_valid_moves(SCM scm_board, SCM player) {
+ enum player_color **board =
+ SCM_UNBNDP(scm_board) ? get_board() : scm_board_to_c_board(scm_board);
- SCM result = scm_make_list(scm_from_int(0), NULL);
+ enum player_color current_player = SCM_UNBNDP(player)
+ ? get_current_player()
+ : scm_player_to_c_player(player);
+
+ SCM result = SCM_EOL;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
struct move move = {i, j};
if (is_valid_move(board, current_player, move)) {
- result = scm_cons(scm_cons(scm_from_int(i), scm_from_int(j)), result);
+ result = scm_cons(scm_move_from_c_move(move), result);
}
}
}
- free_board(board);
+ if (!SCM_UNBNDP(scm_board)) {
+ free_board(board);
+ }
+
return result;
}
@@ -283,9 +267,11 @@ struct move get_scm_move(char *strategy_path) {
// Initialize primitives
scm_c_define_gsubr("get-board", 0, 0, 0, scm_get_board);
- scm_c_define_gsubr("current-player", 0, 0, 0, scm_current_player);
- scm_c_define_gsubr("valid-move?", 3, 0, 0, scm_is_valid_move);
- scm_c_define_gsubr("valid-moves", 2, 0, 0, scm_valid_moves);
+ scm_c_define_gsubr("current-player", 0, 0, 0, scm_get_current_player);
+ scm_c_define_gsubr("valid-move?", 1, 2, 0, scm_is_valid_move);
+ scm_c_define_gsubr("valid-moves", 0, 2, 0, scm_valid_moves);
+ scm_c_define_gsubr("apply-move", 1, 2, 0, scm_apply_move);
+ scm_c_define_gsubr("get-winner", 2, 0, 0, scm_get_winner);
// Read the move from scheme
SCM scm_move = scm_c_primitive_load(strategy_path);
diff --git a/src/valid_moves.c b/src/valid_moves.c
index 5913fb8..11f5926 100644
--- a/src/valid_moves.c
+++ b/src/valid_moves.c
@@ -21,6 +21,7 @@
#include <stdbool.h>
#include "othello.h"
+#include "othello_board.h"
#include "othello_move.h"
bool is_valid_move(enum player_color **board,