summaryrefslogtreecommitdiff
path: root/src/game_loop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/game_loop.c')
-rw-r--r--src/game_loop.c175
1 files changed, 175 insertions, 0 deletions
diff --git a/src/game_loop.c b/src/game_loop.c
new file mode 100644
index 0000000..9cbd5e2
--- /dev/null
+++ b/src/game_loop.c
@@ -0,0 +1,175 @@
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "othello.h"
+
+#define STREQ(a, b) (strcmp(a, b) == 0)
+
+static player_color other_player(player_color current_player) {
+ switch (current_player) {
+ case WHITE:
+ return BLACK;
+ case BLACK:
+ return WHITE;
+ default:
+ return EMPTY;
+ }
+}
+
+static int player_number_from_color(player_color player) {
+ switch (player) {
+ case WHITE:
+ return 1;
+ case BLACK:
+ return 2;
+ default:
+ return -1;
+ }
+}
+
+static void prompt_player(player_color current_player) {
+ printf("Player %d [h for help] > ", player_number_from_color(current_player));
+}
+
+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"
+ "To print the board again, enter `p`\n\n"
+ "To drop into a guile repl enter `g`.\n\n"
+ "In the guile repl you can define an AI to use for the current player.\n\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.");
+}
+
+static struct move get_move(player_color board[8][8],
+ player_color current_player) {
+ // Initialize move to an invalid move.
+ struct move move = {-1, -1};
+
+ 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);
+ }
+ }
+
+ if (STREQ(input, "h\n")) {
+ print_help();
+ } else if (STREQ(input, "p\n")) {
+ print_board(board);
+ } else if (STREQ(input, "g\n")) {
+ puts("NOT IMPLEMENTED YET!");
+ } else {
+ sscanf(input, "%d %d", &move.row, &move.col);
+ }
+
+ free(input);
+ } while (!is_valid_move(board, current_player, move));
+
+ return move;
+}
+
+static void apply_move(player_color board[8][8], 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) + 1);
+ 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 + 1;*/
+ up_end = i;
+ break;
+ }
+ }
+
+ // 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 - 1;*/
+ down_end = i;
+ break;
+ }
+ }
+
+ // 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 + 1;*/
+ left_end = i;
+ break;
+ }
+ }
+
+ // 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 - 1;*/
+ right_end = i;
+ break;
+ }
+ }
+
+ 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;
+ }
+}
+
+char game_loop(player_color board[8][8]) {
+ player_color current_player = WHITE;
+
+ while (has_valid_moves(board, current_player)) {
+ struct move move = get_move(board, current_player);
+ apply_move(board, current_player, move);
+ /*board[move.row][move.col] = current_player;*/
+ current_player = other_player(current_player);
+ }
+
+ 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;
+ }
+ }
+
+ return white_score > black_score ? WHITE
+ : black_score > white_score ? BLACK
+ : EMPTY;
+}