aboutsummaryrefslogtreecommitdiff
path: root/src/ct1986.c
diff options
context:
space:
mode:
authortslil clingman <tslil@posteo.de>2021-01-20 22:49:49 -0500
committertslil <tslil@posteo.de>2026-08-28 19:37:41 +0100
commit2ac4a6e1d3b6440de22d95f48454d6282c78726d (patch)
tree2496adbdf994c0bf574fbcc62486d244d9673d8b /src/ct1986.c
parent1b0338a0546b760e8a7ffa61b38c410a166aae7c (diff)
parent36cecb722fb66d35cdbf69ebcf2aa6f49bfc082b (diff)
Merge branch 'pi'
Diffstat (limited to 'src/ct1986.c')
-rw-r--r--src/ct1986.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/src/ct1986.c b/src/ct1986.c
new file mode 100644
index 0000000..b930b13
--- /dev/null
+++ b/src/ct1986.c
@@ -0,0 +1,197 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <tak.h>
+#include <minimax_cnn1986.h>
+
+const char* esc = "\x1B[L";
+
+FILE *lcd = NULL;
+static char *gamelog = 0;
+static int human, search_depth;
+
+static void
+write_line(const char *line) {
+ fprintf(lcd, "%s\n", line);
+ fflush(lcd);
+}
+
+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);
+ fprintf(lcd, "Game over: %s\n", win);
+ fflush(lcd);
+}
+
+static int
+handle_turn(char *line) {
+ // Track win state
+ uint8_t new_win = (won == 0xFF);
+ switch (do_ptn(line)) {
+ // Errors
+ case PTN_INVALID: { write_line("Invalid PTN."); break; }
+ case ACT_ILLEGAL: { write_line("Illegal ply."); break; }
+ case ACT_OVERFLOW: { write_line("Overflow."); 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; }
+ }
+ return EXIT_SUCCESS;
+ } else {
+ write_line("Game over.");
+ break;
+ }
+ }
+ // Valid, append to game log
+ default: {
+ append_to_gamelog(line, 0);
+ return EXIT_SUCCESS;
+ }
+ }
+ return EXIT_FAILURE;
+}
+
+static void
+new_game(uint8_t size) {
+ reset_state(size);
+ write_line("New 5x5 game.");
+ if (gamelog) gamelog = realloc(gamelog, sizeof(char));
+ else gamelog = malloc(sizeof(char));
+ gamelog[0] = 0;
+}
+
+// Set up output function for ct1986
+
+static uint8_t perc;
+inline void
+ct1986_display_progress(const uint8_t depth) {
+ if (depth == 0) {
+ perc++;
+ // back four spaces and clear line, followed by perc%
+ fprintf(lcd, "%sl%sl%sl%sl%sk%3d%%",
+ esc, esc, esc, esc, esc,
+ perc*4);
+ fflush(lcd);
+ }
+}
+
+static int
+ct1986_turn(const uint8_t search_depth) {
+ // Prepare progress bar
+ fputs("Computing: ", lcd); fflush(lcd);
+ // Run the minimax
+ perc = 0;
+ float minimax = ct1986_generate(search_depth);
+ fputc('\n', lcd); fflush(lcd);
+ // Failed to find a move?
+ if (minimax <= -infty) {
+ fprintf(lcd, "%s concedes!\n", (ply & 1) ? "Black" : "White");
+ return EXIT_FAILURE;
+ } else {
+ fprintf(lcd, "%s: %s\n",
+ (ply & 1) ? "Black" : "White",
+ ct1986_ptn);
+ handle_turn(ct1986_ptn);
+ return EXIT_SUCCESS;
+ }
+}
+
+static void
+do_game_log(void) {
+ fputs(gamelog, lcd);
+}
+
+static int
+input_is_not_turn(const char *line) {
+ switch (line[0]) {
+ case 'l': { do_game_log(); break; }
+ case 'n': { new_game(5); break; }
+ case 'd': {
+ search_depth = line[1] - '0';
+ fprintf(lcd, "Search depth: %d\n", search_depth);
+ fflush(lcd);
+ break;
+ }
+ case 'b': { human = 1; new_game(5); break; }
+ case 'w': { human = 0; new_game(5); break; }
+ default: return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+}
+
+int
+main(int argc, char **argv) {
+ (void)(argc);
+ (void)(argv);
+
+ lcd = fopen("/dev/lcd", "w");
+ if (lcd == NULL) return EXIT_FAILURE;
+
+ human = 0;
+ search_depth = 1;
+ new_game(5);
+ fprintf(lcd, "%sB", esc);
+ fflush(lcd);
+
+ char *line = NULL;
+ ssize_t read;
+ size_t alloc_size;
+
+ for (int playing = 1; playing;) {
+ while (human == 0) {
+ if (ply & 1) write_line("Black: ");
+ else write_line("White: ");
+ read = getline(&line, &alloc_size, stdin);
+ if (read > 0) {
+ line[read - 1] = 0;
+ if (input_is_not_turn(line)) {
+ int r = handle_turn(line);
+ if (r == EXIT_SUCCESS && won == 0xFF) {
+ human = 1;
+ }
+ }
+ } else if (read == -1) {
+ playing = 0;
+ break;
+ }
+ }
+ ct1986_turn(search_depth);
+ human = 0;
+ }
+
+ fclose(lcd);
+ return EXIT_SUCCESS;
+}