diff options
| author | tslil clingman <tslil@posteo.de> | 2021-01-18 23:14:12 -0500 |
|---|---|---|
| committer | tslil <tslil@posteo.de> | 2026-08-28 19:37:41 +0100 |
| commit | 82d679ab5fa43c33ae52fe7b66d7c358f6046a45 (patch) | |
| tree | fdb42bd3647c7c2934ec29d32aedbdf8b16d28fe /src | |
| parent | 10dcfac23be0a8cab39efaaf63abecf098c993db (diff) | |
First steps towards character LCD
Diffstat (limited to 'src')
| -rw-r--r-- | src/ct1986.c | 194 | ||||
| -rw-r--r-- | src/ctaklm.c | 2 |
2 files changed, 195 insertions, 1 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 = ˙ + + 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; +} diff --git a/src/ctaklm.c b/src/ctaklm.c index 5ae0a3b..2696231 100644 --- a/src/ctaklm.c +++ b/src/ctaklm.c @@ -3,7 +3,7 @@ #include <string.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"; |
