summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortslil <tslil@posteo.de>2021-01-14 13:00:18 -0500
committertslil <tslil@posteo.de>2026-08-28 19:37:41 +0100
commit2a7b485265997d62625dc0ee5d8e91ede1c5f99f (patch)
treee15e8e46743e8ce8bbaa0271834abbca82a784f1
parentb75526290b97e26d3fc3bbefef79f50a7febfe7d (diff)
So after a small tweak, it actually plays well!
-rw-r--r--Makefile2
-rw-r--r--include/ct1986.c10
-rw-r--r--include/ct1986.h1
-rw-r--r--src/ctaklm.c169
4 files changed, 107 insertions, 75 deletions
diff --git a/Makefile b/Makefile
index 1f472ed..7819070 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
IDIR=include
TPDIR=3rd-party
-CFLAGS=-O3 -Wall -Wextra -std=c99 -D_DEFAULT_SOURCE -I$(IDIR) -I$(TPDIR)
+CFLAGS=-Os -Wall -Wextra -std=c99 -D_DEFAULT_SOURCE -I$(IDIR) -I$(TPDIR)
LIBS=
SRCS=$(wildcard include/*.c) $(wildcard 3rd-party/*.c)
diff --git a/include/ct1986.c b/include/ct1986.c
index 706640e..8378f8c 100644
--- a/include/ct1986.c
+++ b/include/ct1986.c
@@ -4,6 +4,7 @@
// Globals
// ===================================================================
+const float infty = 3.0;
char ct1986_ptn[9];
void (*ct1986_display_progress)(const uint8_t);
@@ -121,16 +122,17 @@ previous_ply(void) {
if ((min == 0) && (w == WIN_ROAD_BLACK \
|| w == WIN_FLAT_BLACK \
|| w == WIN_DRAGON)) { \
- this = +3; \
+ this = infty; \
} else if ((min > 0) \
&& (w == WIN_ROAD_WHITE \
|| w == WIN_FLAT_WHITE \
|| w == WIN_DRAGON)) { \
- this = -3; \
+ this = -infty; \
} /* Otherwise decide what to do based on our depth */ \
} else if (cur_depth == max_depth) { \
/* We're at the bottom, evaluate */ \
this = ct1986_evaluate_black_win(); \
+ if (min == 0) this = this - 1.0;\
} else { \
/* We're not at the bottom, recurse first */ \
next_ply(); \
@@ -160,7 +162,7 @@ ct1986_minimax(const uint8_t cur_depth, const uint8_t max_depth,
black_count_backup = black_count;
// 1.0 is a `certain' black win, -1.0 is a `certain' white win.
- float this = 0, optimal = (min) ? 2.0 : -2.0;
+ float this = 0, optimal = (min) ? infty : -infty;
// Step across the board
for (uint8_t row = 0; row < board_size; row++) {
@@ -269,5 +271,5 @@ ct1986_minimax(const uint8_t cur_depth, const uint8_t max_depth,
inline float
ct1986_generate(const uint8_t max_depth) {
- return ct1986_minimax(0, max_depth, 0, -10, 10);
+ return ct1986_minimax(0, max_depth, (ply & 1) ? 0 : 1, -infty, infty);
}
diff --git a/include/ct1986.h b/include/ct1986.h
index ef56c1f..3f2568d 100644
--- a/include/ct1986.h
+++ b/include/ct1986.h
@@ -2,6 +2,7 @@
#include "tak.h"
#include "weights.h"
+extern const float infty;
extern char ct1986_ptn[9];
extern void (*ct1986_display_progress)(const uint8_t);
diff --git a/src/ctaklm.c b/src/ctaklm.c
index fdeccc8..cf7d0c4 100644
--- a/src/ctaklm.c
+++ b/src/ctaklm.c
@@ -6,8 +6,8 @@
#include <tak.h>
#include <ct1986.h>
-const char *blk = "\033[41m", *wht = "\033[44m";
-const char *rev = "\033[7m", *und = "\033[4m", *rst = "\033[0m";
+static const char *blk = "\033[41m", *wht = "\033[44m";
+static const char *und = "\033[4m", *rst = "\033[0m";
#define SQUARE_W 5
#define SQUARE_H 3
@@ -235,9 +235,12 @@ handle_turn(char *line) {
return EXIT_SUCCESS;
}
+static int human = 1;
+
static void
new_game(uint8_t size) {
reset_state(size);
+ human = 0;
printf("New %dx%d game!\n",size,size);
if (gamelog) gamelog = realloc(gamelog, sizeof(char));
else gamelog = malloc(sizeof(char));
@@ -305,85 +308,111 @@ dot(const uint8_t depth) {
}
}
+static void
+ct1986_turn(const uint8_t max_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
+ float minimax = ct1986_generate(max_depth);
+ if (minimax < -infty) {
+ puts("] Opponent concedes!");
+ } else {
+ printf("] Result: %s (%.3f)\n",
+ ct1986_ptn,
+ minimax*100.0);
+ handle_turn(ct1986_ptn);
+ }
+}
+
+static int
+input_is_not_turn(const char *line) {
+ if (!strncmp(line,"help",5)) {
+ puts("Valid commands: auto (board|info), board, help, info,\
+log, square, new [56], <PTN>.");
+ } else if (!strncmp(line,"board",6)) {
+ print_board();
+ } else if (!strncmp(line,"info",5)) {
+ print_info();
+ } else if (!strncmp(line,"eval",5)) {
+ float eval = ct1986_evaluate_black_win()*100;
+ if (ply & 1) {
+ printf("Black heuristic chance: %s%.2f%s\n",
+ blk, eval, rst);
+ } else {
+ printf("White heruistic chance: %s%.2f%s\n",
+ wht, 100-eval, rst);
+ }
+ } else if (!strncmp(line,"log",3)) {
+ puts(gamelog);
+ } else if (!strncmp(line,"load",4)) {
+ if (strnlen(line,6) >= 6) {
+ load_ptn(line+5);
+ } else {
+ puts("Usage: load <file.ptn>.");
+ }
+ } else if (!strncmp(line,"auto",4)) {
+ if (!strncmp(line,"auto board",10)) {
+ auto_board = ~auto_board;
+ printf("Automatic board display %s.\n",
+ (auto_board) ? "Enabled" : "Disabled");
+ } else if (!strncmp(line,"auto info",9)) {
+ auto_info = ~auto_info;
+ printf("Automatic info display %s.\n",
+ (auto_info) ? "Enabled" : "Disabled");
+ } else {
+ puts("Usage: auto (board|info).");
+ }
+ } else if (!strncmp(line,"square",6)) {
+ if (strnlen(line, 9) >= 9
+ && line[7] >= 'a' && line[7] <= '`'+board_size
+ && line[8] >= '1' && line[8] <= '0'+board_size) {
+ print_square(line[7]-'a', line[8]-'1');
+ } else {
+ printf("Usage: square [a-%c][1-%c]\n",'`'+board_size,'0'+board_size);
+ }
+ } else if (!strncmp(line,"new",3)) {
+ if (line[3] == 0) {
+ new_game(5);
+ } else if (strnlen(line,5) >= 5 && line[4] >= '5' && line[4] <= '6') {
+ new_game(line[4]-'0');
+ } else {
+ puts("Usage: new [56].");
+ }
+ } else {
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+}
+
int
main(int argc, char **argv) {
(void)(argc);
(void)(argv);
- new_game(5);
+ // Set up output function for ct1986
ct1986_display_progress = &dot;
+ new_game(5);
char *line;
- while((line = linenoise("ctaklm> ")) != NULL) {
- if (!strncmp(line,"help",5)) {
- puts("Valid commands: auto (board|info), board, help, info,\
- log, square, new [56], <PTN>.");
- } else if (!strncmp(line,"board",6)) {
- print_board();
- } else if (!strncmp(line,"info",5)) {
- print_info();
- } else if (!strncmp(line,"eval",5)) {
- printf("Valuation: %s%.6f%s\n",
- blk, ct1986_evaluate_black_win(), rst);
- } else if (!strncmp(line,"log",3)) {
- puts(gamelog);
- } else if (!strncmp(line,"load",4)) {
- if (strnlen(line,6) >= 6) {
- load_ptn(line+5);
- } else {
- puts("Usage: load <file.ptn>.");
- }
- } else if (!strncmp(line,"auto",4)) {
- if (!strncmp(line,"auto board",10)) {
- auto_board = ~auto_board;
- printf("Automatic board display %s.\n",
- (auto_board) ? "Enabled" : "Disabled");
- } else if (!strncmp(line,"auto info",9)) {
- auto_info = ~auto_info;
- printf("Automatic info display %s.\n",
- (auto_info) ? "Enabled" : "Disabled");
- } else {
- puts("Usage: auto (board|info).");
- }
- } else if (!strncmp(line,"square",6)) {
- if (strnlen(line, 9) >= 9
- && line[7] >= 'a' && line[7] <= '`'+board_size
- && line[8] >= '1' && line[8] <= '0'+board_size) {
- print_square(line[7]-'a', line[8]-'1');
- } else {
- printf("Usage: square [a-%c][1-%c]\n",'`'+board_size,'0'+board_size);
- }
- } else if (!strncmp(line,"new",3)) {
- if (line[3] == 0) {
- new_game(5);
- } else if (strnlen(line,5) >= 5 && line[4] >= '5' && line[4] <= '6') {
- new_game(line[4]-'0');
- } else {
- puts("Usage: new [56].");
- }
- } else {
- int r = handle_turn(line);
- if (r == EXIT_SUCCESS && 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
- float minimax = ct1986_generate(2);
- if (minimax < 0 || minimax > 1) {
- puts("] Opponent concedes!");
- } else {
- printf("] Result: %s (%.3f)\n",
- ct1986_ptn,
- minimax*100.0);
- handle_turn(ct1986_ptn);
+ for (int playing = 1; playing;) {
+ while(human && (line = linenoise("ctaklm> ")) != NULL) {
+ if (input_is_not_turn(line)) {
+ int r = handle_turn(line);
+ if (r == EXIT_SUCCESS && won == 0xFF) {
+ human = 0;
}
}
+ free(line);
+ }
+ if (human && line == NULL) {
+ playing = 0;
+ } else {
+ ct1986_turn(1);
+ human = 1;
}
-
- free(line);
}
return 0;
-
}