aboutsummaryrefslogtreecommitdiff
path: root/src/ct1986.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ct1986.c')
-rw-r--r--src/ct1986.c194
1 files changed, 194 insertions, 0 deletions
diff --git a/src/ct1986.c b/src/ct1986.c
new file mode 100644
index 0000000..56c76b1
--- /dev/null
+++ b/src/ct1986.c
@@ -0,0 +1,194 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <tak.h>
+#include <minimax_cnn1986.h>
+#include <LCDHD44780.h>
+
+static char *gamelog = 0;
+static int human, search_depth;
+
+static void
+append_to_gamelog(const char *line, const uint8_t win_line) {
+ // I _could_ dynamically compute the size but ... don't let
+ // `perfect' be the enemy of `good' ?
+ char prepend[8];
+
+ if (win_line) {
+ prepend[0] = '\n';
+ prepend[1] = 0;
+ } else if (ply & 1) {
+ snprintf(prepend, 7, "%s%d. ",
+ (ply == 1) ? "" : "\n", ply/2+1);
+ } else {
+ strcpy(prepend, " ");
+ }
+ // Make room for this line
+ gamelog = realloc(gamelog,
+ strlen(gamelog)
+ + strlen(prepend)
+ + strlen(line) + 1);
+ strcat(gamelog,prepend);
+ strcat(gamelog,line);
+}
+
+static void
+end_game(char *line, char *win) {
+ append_to_gamelog(line, 0);
+ append_to_gamelog(win, 1);
+ write_string("Game over: ");
+ write_string(win);
+}
+
+static int
+handle_turn(char *line) {
+ // Track win state
+ uint8_t new_win = (won == 0xFF);
+ switch (do_ptn(line)) {
+ // Errors
+ case PTN_INVALID: { write_string("Invalid PTN."); return -1; break; }
+ case ACT_ILLEGAL: { write_string("Illegal action."); return -1; break; }
+ case ACT_OVERFLOW: {
+ write_string("Move would cause internal overflow, select another.");
+ return EXIT_FAILURE;
+ break;
+ }
+ // Game has ended
+ case GAME_END: {
+ // Did it end this turn?
+ if (new_win) {
+ switch (won) {
+ case WIN_DRAW: { end_game(line,"1/2-1/2"); break; }
+ case WIN_FLAT_BLACK: { end_game(line,"0-F"); break; }
+ case WIN_FLAT_WHITE: { end_game(line,"F-0"); break; }
+ case WIN_ROAD_BLACK: { end_game(line,"0-R"); break; }
+ case WIN_ROAD_WHITE: { end_game(line,"R-0"); break; }
+ }
+ }
+ write_string("Game over, enter `new' to play again.");
+ if (! new_win) return EXIT_FAILURE;
+ break;
+ }
+ // Valid, append to game log
+ case PTN_VALID:
+ case ACT_OK: {
+ append_to_gamelog(line, 0);
+ break;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static void
+new_game(uint8_t size) {
+ reset_state(size);
+ write_string("New 5x5 game! ct1986 at search depth ");
+ write_to_lcd(search_depth + '0', LCD_DATA);
+ write_to_lcd('.', LCD_DATA);
+ if (gamelog) gamelog = realloc(gamelog, sizeof(char));
+ else gamelog = malloc(sizeof(char));
+ gamelog[0] = 0;
+}
+
+static void
+dot(const uint8_t depth) {
+ if (depth == 0) {
+ write_to_lcd('#', LCD_DATA);
+ }
+}
+
+static int
+ct1986_turn(const uint8_t search_depth) {
+ // Prepare progress bar
+ write_string("Computing ");
+ // Run the minimax
+ float minimax = ct1986_generate(search_depth);
+ // Failed to find a move?
+ if ((minimax <= -infty && (ply & 1) == 1)
+ ||(minimax >= infty && (ply & 1) == 0)) {
+ write_string("Opponent concedes!");
+ return EXIT_FAILURE;
+ } else {
+ write_string("Result: ");
+ write_string(ct1986_ptn);
+ handle_turn(ct1986_ptn);
+ return EXIT_SUCCESS;
+ }
+}
+
+static int
+input_is_not_turn(const char *line) {
+ if (!strcmp(line,"help")) {
+ write_string("Valid commands: depth [0-9], help, new, \
+play (b|w), self-play, <PTN>.");
+ } else if (!strcmp(line,"log")) {
+ write_string(gamelog);
+ } else if (!strcmp(line,"new")) {
+ new_game(5);
+ } else if (!strcmp(line,"self-play")) {
+ while (ct1986_turn(search_depth) == 0);
+ } else if (!strncmp(line,"depth",5)) {
+ if (strnlen(line,7) == 7 && line[6] >= '0' && line[6] <= '9') {
+ search_depth = line[6] - '0';
+ write_string("New search depth: ");
+ write_to_lcd(line[6], LCD_DATA);
+ } else {
+ write_string("Usage: depth [0-9].");
+ }
+ } else if (!strncmp(line,"play",4)) {
+ if (strnlen(line,7) == 6
+ && ((line[5] == 'b' || line[5] == 'B')
+ || (line[5] == 'w' || line[5] == 'W'))) {
+ // 'b' is even :)
+ human = 1 - (line[5] & 1);
+ new_game(5);
+ } else {
+ write_string("Usage: play (b|w).\n");
+ }
+ } else {
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+}
+
+int
+main(int argc, char **argv) {
+ (void)(argc);
+ (void)(argv);
+
+ // Set up output function for ct1986
+ ct1986_display_progress = &dot;
+
+ human = 0;
+ search_depth = 3;
+ new_game(5);
+
+ char *line = NULL;
+ ssize_t read;
+ size_t alloc_size;
+
+ for (int playing = 1; playing;) {
+ write_string("Welcome to ct1986!");
+ fflush(stdout);
+ while ((human == 0) && (read = getline(&line, &alloc_size, stdin)) != -1) {
+ if (read) {
+ line[read - 1] = 0;
+ if (input_is_not_turn(line)) {
+ int r = handle_turn(line);
+ if (r == EXIT_SUCCESS && won == 0xFF) {
+ human = 1;
+ }
+ }
+ }
+ }
+ if ((human == 0) && (read == -1)) {
+ playing = 0;
+ } else {
+ ct1986_turn(search_depth);
+ human = 0;
+ }
+ }
+ return 0;
+}