summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/main.c2
-rw-r--r--include/othello.h4
-rw-r--r--include/othello_move.h6
-rw-r--r--src/board.c36
-rw-r--r--src/game_loop.c6
-rw-r--r--src/move.c96
-rw-r--r--src/print_board.c4
-rw-r--r--src/valid_moves.c69
-rw-r--r--strategies/first-move.scm34
-rw-r--r--strategies/user-input.scm1
10 files changed, 176 insertions, 82 deletions
diff --git a/cmd/main.c b/cmd/main.c
index d87be49..33cfcad 100644
--- a/cmd/main.c
+++ b/cmd/main.c
@@ -97,7 +97,7 @@ int main(int argc, char **argv) {
}
puts("Here was the final board:");
- print_board();
+ print_board(get_board());
return EXIT_SUCCESS;
}
diff --git a/include/othello.h b/include/othello.h
index 14c402b..40a36c4 100644
--- a/include/othello.h
+++ b/include/othello.h
@@ -45,14 +45,14 @@ void initialize_board(void);
enum player_color **copy_board(enum player_color **board);
// Free the specified board.
-enum player_color **free_board(enum player_color **board);
+void free_board(enum player_color **board);
// Plays a game to completion, starting with board.
enum player_color game_loop(char *player_one_strategy,
char *player_two_strategy);
// Prints the current state of the board, including coordinates in the margins.
-void print_board(void);
+void print_board(enum player_color **board);
// Returns the color of the player whose turn it is.
enum player_color get_current_player(void);
diff --git a/include/othello_move.h b/include/othello_move.h
index 0c3716e..281cb9b 100644
--- a/include/othello_move.h
+++ b/include/othello_move.h
@@ -27,12 +27,14 @@ struct move get_scm_move(char *strategy_path);
// True if move is valid for current_player.
// Otherwise false.
-bool is_valid_move(const enum player_color current_player,
+bool is_valid_move(enum player_color **board,
+ const enum player_color current_player,
const struct move move);
// True if current_player has any valid moves.
// Otherwise false.
-bool has_valid_moves(const enum player_color current_player);
+bool has_valid_moves(enum player_color **board,
+ const enum player_color current_player);
/* Returns true if the move was valid */
bool apply_move(enum player_color **board, enum player_color current_player,
diff --git a/src/board.c b/src/board.c
index 62171ff..6859952 100644
--- a/src/board.c
+++ b/src/board.c
@@ -25,14 +25,12 @@
static enum player_color **board;
-enum player_color **get_board(void) {
- return board;
-}
+enum player_color **get_board(void) { return board; }
void initialize_board() {
- board = malloc(8 * sizeof(enum player_color *));
+ board = calloc(8, sizeof(enum player_color *));
for (int i = 0; i < 8; i++) {
- board[i] = malloc(8 * sizeof(enum player_color));
+ board[i] = calloc(8, sizeof(enum player_color));
}
// Set all the positions to empty
@@ -49,14 +47,13 @@ void initialize_board() {
board[4][4] = WHITE;
}
-
enum player_color get_winner() {
int white_score = 0, black_score = 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.
+ // 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);
}
@@ -66,3 +63,24 @@ enum player_color get_winner() {
: black_score > white_score ? BLACK
: EMPTY;
}
+
+// 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 *));
+
+ for (int i = 0; i < 8; i++) {
+ board[i] = calloc(8, sizeof(enum player_color));
+ for (int j = 0; j < 8; j++) {
+ board[i][j] = other[i][j];
+ }
+ }
+
+ return board;
+}
+
+void free_board(enum player_color **board) {
+ for (int i = 0; i < 8; i++) {
+ free(board[i]);
+ }
+ free(board);
+}
diff --git a/src/game_loop.c b/src/game_loop.c
index 67c9ea0..8186623 100644
--- a/src/game_loop.c
+++ b/src/game_loop.c
@@ -67,9 +67,9 @@ enum player_color game_loop(char *player_one_strategy_path,
current_player = WHITE;
#define other_player (current_player == WHITE ? BLACK : WHITE)
- while (has_valid_moves(current_player)) {
- struct move move = current_player_move(current_player, player_one_strategy_path,
- player_two_strategy_path);
+ 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 = other_player;
}
diff --git a/src/move.c b/src/move.c
index 60cf58b..aaaaf9e 100644
--- a/src/move.c
+++ b/src/move.c
@@ -66,7 +66,7 @@ struct move prompt_get_move(enum player_color current_player) {
if (STREQ(input, "h")) {
print_help();
} else if (STREQ(input, "p")) {
- print_board();
+ print_board(get_board());
/*} else if (STREQ(input, "g")) {*/
/*int argc = 1;*/
/*char **argv = calloc(1, sizeof(char *));*/
@@ -84,7 +84,7 @@ struct move prompt_get_move(enum player_color current_player) {
}
free(input);
- } while (!is_valid_move(current_player, move));
+ } while (!is_valid_move(get_board(), current_player, move));
return move;
}
@@ -185,15 +185,15 @@ static SCM scm_get_board(void) {
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_c_eval_string("'w"),
+ 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_c_eval_string("'b"),
+ 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_c_eval_string("'e"),
+ scm_cons(scm_from_utf8_symbol("empty"),
scm_list_ref(scm_board, scm_from_int(i))));
}
}
@@ -201,14 +201,94 @@ static SCM scm_get_board(void) {
return scm_board;
}
+static 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");
+ }
+}
+
+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;
+ }
+ }
+ }
+
+ enum player_color current_player = BLACK;
+
+ struct move move = scm_move_to_c_move(scm_move);
+ return 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));
+ }
+
+ enum player_color current_player = EMPTY;
+
+ 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;
+
+ SCM result = scm_make_list(scm_from_int(0), NULL);
+ 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);
+ }
+ }
+ }
+
+ free_board(board);
+ return result;
+}
+
struct move get_scm_move(char *strategy_path) {
// Initialize move to an invalid move.
struct move move = {-1, -1};
scm_init_guile();
+
+ // 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);
+ // Read the move from scheme
SCM scm_move = scm_c_primitive_load(strategy_path);
- move.row = scm_to_int(scm_car(scm_move));
- move.col = scm_to_int(scm_cdr(scm_move));
- return move;
+
+ return scm_move_to_c_move(scm_move);
}
diff --git a/src/print_board.c b/src/print_board.c
index b0ce650..a7e332b 100644
--- a/src/print_board.c
+++ b/src/print_board.c
@@ -22,9 +22,7 @@
#include "othello.h"
-void print_board() {
- enum player_color **board = get_board();
-
+void print_board(enum player_color **board) {
puts(" 0 1 2 3 4 5 6 7");
for (int row = 0; row < 8; row++) {
diff --git a/src/valid_moves.c b/src/valid_moves.c
index 7c3e676..5913fb8 100644
--- a/src/valid_moves.c
+++ b/src/valid_moves.c
@@ -21,73 +21,34 @@
#include <stdbool.h>
#include "othello.h"
+#include "othello_move.h"
-bool is_valid_move(const enum player_color current_player,
+bool is_valid_move(enum player_color **board,
+ const enum player_color current_player,
const struct move move) {
- return true;
- enum player_color **board = get_board();
- // The move must be a positive position.
- if (move.row < 0 || move.col < 0) {
+ if (current_player == EMPTY) {
return false;
}
- // The move must be below the upper bounds of the board.
- if (move.row > 8 || move.col > 8) {
- return false;
- }
-
- // The move must be an empty spot to be valid.
- if (board[move.row][move.col] != EMPTY) {
- return false;
- }
-
- const enum player_color other_color = current_player == WHITE ? BLACK : WHITE;
-
- bool is_valid_up = false;
- bool is_valid_down = false;
- bool is_valid_left = false;
- bool is_valid_right = false;
-
-#define check_valid_direction(direction_bool, start, end_cond, step, cur_pos) \
- /* This if statement ensures that we don't check after one direction is \
- * already valid. \
- */ \
- if (!is_valid_up && !is_valid_down && !is_valid_left && !is_valid_right) { \
- bool would_flip_oppenent = false; \
- bool has_other_end = false; \
- for (int i = start; end_cond && !has_other_end; step) { \
- if (cur_pos == current_player) { \
- has_other_end = true; \
- } else if (cur_pos == other_color) { \
- would_flip_oppenent = true; \
- } else { \
- /* We have reached an empty tile*/ \
- break; \
- } \
- } \
- direction_bool = has_other_end && would_flip_oppenent; \
- }
-
- check_valid_direction(is_valid_up, move.row - 1, i > 0, i--,
- board[i][move.col]);
- check_valid_direction(is_valid_down, move.row + 1, i < 8, i++,
- board[i][move.col]);
- check_valid_direction(is_valid_left, move.col - 1, i > 0, i--,
- board[move.row][i]);
- check_valid_direction(is_valid_right, move.col + 1, i < 8, i++,
- board[move.row][i]);
+ // Make a copy of the input board. This is done because we lean on the logic
+ // that exists in apply_move to check if a move is valid. We don't want to
+ // 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);
-#undef check_valid_direction
+ free_board(b);
- return is_valid_up || is_valid_down || is_valid_left || is_valid_right;
+ return res;
}
-bool has_valid_moves(const enum player_color current_player) {
+bool has_valid_moves(enum player_color **board,
+ const enum player_color current_player) {
bool result = false;
struct move move;
for (move.row = 0; move.row < 8 && !result; move.row++) {
for (move.col = 0; move.col < 8 && !result; move.col++) {
- result = is_valid_move(current_player, move);
+ result = is_valid_move(board, current_player, move);
}
}
diff --git a/strategies/first-move.scm b/strategies/first-move.scm
new file mode 100644
index 0000000..7c89078
--- /dev/null
+++ b/strategies/first-move.scm
@@ -0,0 +1,34 @@
+(use-modules (ice-9 pretty-print)
+ (srfi srfi-1))
+
+;(pretty-print (get-board))
+;(newline)
+
+(define (make-point row col)
+ (cons row col))
+
+(define (point->row point)
+ (car point))
+
+(define (point->col point)
+ (cdr point))
+
+(define (valid-move-current-board? move)
+ (valid-move? (get-board) (current-player) move))
+
+(define all-spots
+ (concatenate
+ (map (lambda (row) (map (lambda (col) (make-point row col)) (iota 8)))
+ (iota 8))))
+
+(display "All valid moves: ")
+(for-each (lambda (valid-move) (display valid-move) (newline))
+ (filter valid-move-current-board? all-spots))
+(newline)
+
+; Does not work yet
+(display (valid-moves (get-board) (current-player)))
+(newline)
+
+; The last value is simply used as the move
+(make-point 3 2)
diff --git a/strategies/user-input.scm b/strategies/user-input.scm
new file mode 100644
index 0000000..afdab2d
--- /dev/null
+++ b/strategies/user-input.scm
@@ -0,0 +1 @@
+(read)