aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ct1986.c197
-rw-r--r--src/ctaklm.c96
2 files changed, 249 insertions, 44 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;
+}
diff --git a/src/ctaklm.c b/src/ctaklm.c
index 080da01..24613e9 100644
--- a/src/ctaklm.c
+++ b/src/ctaklm.c
@@ -1,10 +1,9 @@
-#include <stdio.h>
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
-#include <linenoise.h>
#include <tak.h>
-#include <ct1986.h>
+#include <minimax_cnn1986.h>
static const char *blk = "\033[41m", *wht = "\033[44m";
static const char *und = "\033[4m", *rst = "\033[0m";
@@ -147,12 +146,9 @@ print_info(void) {
(ply & 1) ? "Black" : "White",
rst,
(ply < 2) ? " (counter-play start)" : "");
- printf("Flats remaining: %s%02d%s, %s%02d%s\n",
- wht,white_count & 127,rst,
- blk,black_count & 127,rst);
- printf("Caps remaining: %s%d%s, %s%d%s\n",
- wht,white_count >> 7,rst,
- blk,black_count >> 7,rst);
+ printf("Flats/Caps remaining: %s%02d/%d%s, %s%02d/%d%s\n",
+ wht, white_count & 127, white_count >> 7, rst,
+ blk, black_count & 127, black_count >> 7, rst);
}
static char *gamelog = 0;
@@ -300,8 +296,9 @@ load_ptn(const char* fn) {
static float sum_depth, num_check;
-static void
-dot(const uint8_t depth) {
+// Set up output function for ct1986
+inline void
+ct1986_display_progress(const uint8_t depth) {
sum_depth += depth;
num_check += 1;
if (depth == 0) {
@@ -312,28 +309,31 @@ dot(const uint8_t depth) {
static int
ct1986_turn(const uint8_t search_depth) {
- // Prepare progress bar
- fputs("Computing [", stdout);
- for (int k = 0; k < board_size * board_size; k++) putchar(' ');
- fputs("]\033[26D",stdout);
- fflush(stdout);
- // Run the minimax
- sum_depth = 0; num_check = 0;
- float minimax = ct1986_generate(search_depth);
- puts("]\033[1C");
- // Failed to find a move?
- if ((minimax <= -infty && (ply & 1) == 1)
- ||(minimax >= infty && (ply & 1) == 0)) {
- puts("Opponent concedes!");
- return EXIT_FAILURE;
+ if (won == 0xFF) {
+ // Prepare progress bar
+ fputs("Computing [", stdout);
+ for (int k = 0; k < board_size * board_size; k++) putchar(' ');
+ fputs("]\033[26D",stdout);
+ fflush(stdout);
+ // Run the minimax
+ sum_depth = 0; num_check = 0;
+ float minimax = ct1986_generate(search_depth);
+ fputs("\033[1C ", stdout);
+ // Failed to find a move?
+ if (minimax <= -infty) {
+ puts("Opponent concedes!");
+ return EXIT_FAILURE;
+ } else {
+ printf("Result: %s (%.2f, %.1e, %.2f)\n",
+ ct1986_ptn,
+ minimax*100.0,
+ num_check,
+ sum_depth/num_check);
+ handle_turn(ct1986_ptn);
+ return EXIT_SUCCESS;
+ }
} else {
- printf("Result: %s (%.2f, %.1e, %.2f)\n",
- ct1986_ptn,
- minimax*100.0,
- num_check,
- sum_depth/num_check);
- handle_turn(ct1986_ptn);
- return EXIT_SUCCESS;
+ return EXIT_FAILURE;
}
}
@@ -417,25 +417,33 @@ main(int argc, char **argv) {
(void)(argc);
(void)(argv);
- // Set up output function for ct1986
- ct1986_display_progress = &dot;
-
human = 0;
- search_depth = 3;
+ search_depth = 1;
new_game(5);
- char *line;
+ char *line = NULL;
+ ssize_t read = -1;
+ size_t alloc_size;
+
for (int playing = 1; playing;) {
- while((human == 0) && (line = linenoise("ctaklm> ")) != NULL) {
- if (input_is_not_turn(line)) {
- int r = handle_turn(line);
- if (r == EXIT_SUCCESS && won == 0xFF) {
- human = 1;
+ while (human == 0) {
+ fputs("ctaklm> ", stdout);
+ fflush(stdout);
+ 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 {
+ read = -1;
+ human = 1;
}
- free(line);
}
- if ((human == 0) && line == NULL) {
+ if (read == -1) {
playing = 0;
} else {
ct1986_turn(search_depth);