ref: 71d5b0ec838cc99a34d1c3669fb014adb75d097f
parent: f4a1bc7b7e2a7f68b74ae757e452cab54819b3e9
author: zamfofex <zamfofex@twdb.moe>
date: Sat Jan 25 07:35:21 EST 2025
fix some concurrency issues
--- a/chess.c
+++ b/chess.c
@@ -317,24 +317,6 @@
return 1;
}
-int moonfish_finished(struct moonfish_chess *chess)
-{- struct moonfish_move moves[32];
- int x, y;
- int i, count;
-
- for (y = 0 ; y < 8 ; y++) {- for (x = 0 ; x < 8 ; x++) {- count = moonfish_moves(chess, moves, (x + 1) + (y + 2) * 10);
- for (i = 0 ; i < count ; i++) {- if (moonfish_validate(&moves[i].chess)) return 0;
- }
- }
- }
-
- return 1;
-}
-
int moonfish_equal(struct moonfish_chess *a, struct moonfish_chess *b)
{int x, y, i;
@@ -361,6 +343,24 @@
#ifndef moonfish_mini
#include <ctype.h>
+
+int moonfish_finished(struct moonfish_chess *chess)
+{+ struct moonfish_move moves[32];
+ int x, y;
+ int i, count;
+
+ for (y = 0 ; y < 8 ; y++) {+ for (x = 0 ; x < 8 ; x++) {+ count = moonfish_moves(chess, moves, (x + 1) + (y + 2) * 10);
+ for (i = 0 ; i < count ; i++) {+ if (moonfish_validate(&moves[i].chess)) return 0;
+ }
+ }
+ }
+
+ return 1;
+}
int moonfish_move(struct moonfish_chess *chess, struct moonfish_move *found, int from, int to)
{--- a/main.c
+++ b/main.c
@@ -26,6 +26,8 @@
thrd_t thread;
#endif
struct moonfish_option *options;
+ struct moonfish_result result;
+ struct moonfish_options search_options;
};
static int moonfish_getoption(struct moonfish_option *options, char *name)
@@ -37,21 +39,54 @@
return -1;
}
-static moonfish_result_t moonfish_go(void *data)
+static moonfish_result_t moonfish_go0(void *data)
{- static struct moonfish_result result, pv_result;
- static struct moonfish_options options;
- static struct moonfish_chess chess;
static struct moonfish_move pv[256];
+ static struct moonfish_result result;
+ static struct moonfish_chess chess;
+ struct moonfish_info *info;
+ int i, j, count;
+ char name[6];
+
+ info = data;
+
+ moonfish_best_move(info->root, &info->result, &info->search_options);
+
+ count = moonfish_getoption(info->options, "MultiPV");
+ for (i = 0 ; i < count ; i++) {+ count = sizeof pv / sizeof *pv;
+ moonfish_pv(info->root, pv, &result, i, &count);
+ if (count == 0) continue;
+ printf("info depth 1 score cp %d nodes %ld multipv %d pv", result.score, result.node_count, i + 1);+ moonfish_root(info->root, &chess);
+ for (j = 0 ; j < count ; j++) {+ moonfish_to_uci(&chess, pv + j, name);
+ chess = pv[j].chess;
+ printf(" %s", name);+ }
+ printf("\n");+ }
+
+ printf("info depth 1 score cp %d nodes %ld\n", info->result.score, info->result.node_count);+
+ moonfish_root(info->root, &chess);
+ moonfish_to_uci(&chess, &info->result.move, name);
+
+ printf("bestmove %s\n", name);+ fflush(stdout);
+ return moonfish_value;
+}
+
+static void moonfish_go(struct moonfish_info *info)
+{+ static struct moonfish_chess chess;
+
long int our_time, their_time, *xtime, time;
char *arg, *end;
- char name[6];
- struct moonfish_info *info;
long int node_count;
- int i, j, pv_count, count;
- info = data;
+ info->searching = 1;
our_time = -1;
their_time = -1;
@@ -129,38 +164,29 @@
}
}
- options.max_time = time;
- options.our_time = our_time;
- options.thread_count = moonfish_getoption(info->options, "Threads");
- options.node_count = node_count;
+ info->search_options.max_time = time;
+ info->search_options.our_time = our_time;
+ info->search_options.thread_count = moonfish_getoption(info->options, "Threads");
+ info->search_options.node_count = node_count;
- moonfish_best_move(info->root, &result, &options);
- info->searching = 0;
-
- pv_count = moonfish_getoption(info->options, "MultiPV");
- for (i = 0 ; i < pv_count ; i++) {- count = sizeof pv / sizeof *pv;
- moonfish_pv(info->root, pv, &pv_result, i, &count);
- if (count == 0) continue;
- printf("info depth 1 score cp %d nodes %ld multipv %d pv", pv_result.score, pv_result.node_count, i + 1);- moonfish_root(info->root, &chess);
- for (j = 0 ; j < count ; j++) {- moonfish_to_uci(&chess, pv + j, name);
- chess = pv[j].chess;
- printf(" %s", name);+#ifdef moonfish_no_threads
+ moonfish_go0(info);
+#else
+ if (info->has_thread) {+ if (thrd_join(info->thread, NULL) != thrd_success) {+ fprintf(stderr, "could not join thread\n");
+ exit(1);
}
- printf("\n");}
+ info->has_thread = 1;
+ moonfish_unstop(info->root);
+ if (thrd_create(&info->thread, &moonfish_go0, info) != thrd_success) {+ fprintf(stderr, "could not create thread\n");
+ exit(1);
+ }
+#endif
- printf("info depth 1 score cp %d nodes %ld\n", result.score, result.node_count);-
- moonfish_root(info->root, &chess);
- moonfish_to_uci(&chess, &result.move, name);
-
- printf("bestmove %s\n", name);- fflush(stdout);
-
- return moonfish_value;
+ info->searching = 0;
}
static void moonfish_position(struct moonfish_root *root)
@@ -322,29 +348,11 @@
if (arg == NULL) continue;
if (!strcmp(arg, "go")) {-
-#ifdef moonfish_no_threads
- moonfish_go(&info);
-#else
if (info.searching) {fprintf(stderr, "cannot start search while searching\n");
exit(1);
}
- info.searching = 1;
- if (info.has_thread) {- if (thrd_join(info.thread, NULL) != thrd_success) {- fprintf(stderr, "could not join thread\n");
- exit(1);
- }
- }
- info.has_thread = 1;
- moonfish_unstop(info.root);
- if (thrd_create(&info.thread, &moonfish_go, &info) != thrd_success) {- fprintf(stderr, "could not create thread\n");
- exit(1);
- }
-#endif
-
+ moonfish_go(&info);
continue;
}
--- a/scripts/check.txt
+++ b/scripts/check.txt
@@ -1,105 +1,105 @@
perft 0: 1
-info depth 1 score cp -1 nodes 4352
+info depth 1 score cp 2 nodes 4096
bestmove b1c3
perft 0: 1
-info depth 1 score cp 85 nodes 4352
+info depth 1 score cp 116 nodes 4096
bestmove e2a6
perft 0: 1
-info depth 1 score cp 64 nodes 4352
+info depth 1 score cp 64 nodes 4096
bestmove b4c4
perft 0: 1
-info depth 1 score cp -522 nodes 4352
-bestmove d2d4
+info depth 1 score cp -498 nodes 4096
+bestmove b4c5
perft 0: 1
-info depth 1 score cp -522 nodes 4352
-bestmove d7d5
+info depth 1 score cp -498 nodes 4096
+bestmove b5c4
perft 0: 1
-info depth 1 score cp 577 nodes 4352
-bestmove d7c8r
+info depth 1 score cp 304 nodes 4096
+bestmove d7c8q
perft 0: 1
-info depth 1 score cp 20 nodes 4352
-bestmove a1d1
+info depth 1 score cp 35 nodes 4096
+bestmove c4d5
perft 1: 20
-info depth 1 score cp 0 nodes 8448
+info depth 1 score cp 0 nodes 8192
bestmove b1c3
perft 1: 48
-info depth 1 score cp 84 nodes 8448
+info depth 1 score cp 84 nodes 8192
bestmove e2a6
perft 1: 14
-info depth 1 score cp 38 nodes 8448
+info depth 1 score cp 64 nodes 8192
bestmove b4c4
perft 1: 6
-info depth 1 score cp -111 nodes 8448
+info depth 1 score cp -113 nodes 8192
bestmove c4c5
perft 1: 6
-info depth 1 score cp -111 nodes 8448
+info depth 1 score cp -113 nodes 8192
bestmove c5c4
perft 1: 44
-info depth 1 score cp 619 nodes 8448
+info depth 1 score cp 619 nodes 8192
bestmove d7c8r
perft 1: 46
-info depth 1 score cp 36 nodes 8448
+info depth 1 score cp 37 nodes 8192
bestmove c3d5
perft 2: 400
-info depth 1 score cp 9 nodes 12544
+info depth 1 score cp 9 nodes 12288
bestmove b1c3
perft 2: 2039
-info depth 1 score cp 203 nodes 12544
+info depth 1 score cp 202 nodes 12288
bestmove e2a6
perft 2: 191
-info depth 1 score cp 38 nodes 12544
+info depth 1 score cp 38 nodes 12288
bestmove b4c4
perft 2: 264
-info depth 1 score cp -345 nodes 12544
+info depth 1 score cp -345 nodes 12288
bestmove c4c5
perft 2: 264
-info depth 1 score cp -345 nodes 12544
+info depth 1 score cp -345 nodes 12288
bestmove c5c4
perft 2: 1486
-info depth 1 score cp 640 nodes 12544
+info depth 1 score cp 640 nodes 12288
bestmove d7c8r
perft 2: 2079
-info depth 1 score cp 25 nodes 12544
+info depth 1 score cp 22 nodes 12288
bestmove c3d5
perft 3: 8902
-info depth 1 score cp 9 nodes 16640
+info depth 1 score cp 9 nodes 16384
bestmove b1c3
perft 3: 97862
-info depth 1 score cp 217 nodes 16640
+info depth 1 score cp 217 nodes 16384
bestmove e2a6
perft 3: 2812
-info depth 1 score cp 38 nodes 16640
+info depth 1 score cp 32 nodes 16384
bestmove b4c4
perft 3: 9467
-info depth 1 score cp -345 nodes 16640
+info depth 1 score cp -443 nodes 16384
bestmove c4c5
perft 3: 9467
-info depth 1 score cp -345 nodes 16640
+info depth 1 score cp -443 nodes 16384
bestmove c5c4
perft 3: 62379
-info depth 1 score cp 640 nodes 16640
+info depth 1 score cp 640 nodes 16384
bestmove d7c8q
perft 3: 89890
-info depth 1 score cp 161 nodes 16640
+info depth 1 score cp 161 nodes 16384
bestmove c3d5
perft 4: 197281
-info depth 1 score cp 19 nodes 20736
+info depth 1 score cp 19 nodes 20480
bestmove g1f3
perft 4: 4085603
-info depth 1 score cp 172 nodes 20736
+info depth 1 score cp 178 nodes 20480
bestmove e2a6
perft 4: 43238
-info depth 1 score cp 32 nodes 20736
+info depth 1 score cp 26 nodes 20480
bestmove b4c4
perft 4: 422333
-info depth 1 score cp -443 nodes 20736
+info depth 1 score cp -443 nodes 20480
bestmove c4c5
perft 4: 422333
-info depth 1 score cp -443 nodes 20736
+info depth 1 score cp -443 nodes 20480
bestmove c5c4
perft 4: 2103487
-info depth 1 score cp 632 nodes 20736
+info depth 1 score cp 632 nodes 20480
bestmove d7c8r
perft 4: 3894594
-info depth 1 score cp 164 nodes 20736
+info depth 1 score cp 164 nodes 20480
bestmove c3d5
--- a/search.c
+++ b/search.c
@@ -60,7 +60,7 @@
_Atomic long int visits;
_Atomic unsigned char bounds[2];
_Atomic short int count;
- _Atomic unsigned char ignored;
+ _Atomic unsigned char ignored, uses;
unsigned char from, index;
};
@@ -131,18 +131,19 @@
#ifdef moonfish_no_threads
count = node->count;
- if (count <= 0) return;
#else
for (;;) {count = node->count;
- if (count == -1) continue;
- if (count <= 0) return;
- if (atomic_compare_exchange_strong(&node->count, &count, -1)) break;
+ if (count < 0) continue;
+ if (atomic_compare_exchange_strong(&node->count, &count, -2)) break;
}
+ for (;;) {+ if (node->uses == 0) break;
+ }
#endif
for (i = 0 ; i < count ; i++) moonfish_discard(node->children + i);
- free(node->children);
+ if (count > 0) free(node->children);
node->count = 0;
}
@@ -154,6 +155,7 @@
node->ignored = 0;
node->bounds[0] = 0;
node->bounds[1] = 1;
+ node->uses = 0;
}
static int moonfish_compare(const void *ax, const void *bx)
@@ -174,12 +176,6 @@
int child_count;
struct moonfish_move moves[32];
- if (node->count == -2) return;
- if (moonfish_finished(chess)) {- node->count = -2;
- return;
- }
-
node->children = NULL;
child_count = 0;
@@ -212,8 +208,9 @@
}
}
- if (child_count > 0) qsort(node->children, child_count, sizeof *node, &moonfish_compare);
if (child_count == 0 && node->children != NULL) free(node->children);
+ if (child_count > 0) qsort(node->children, child_count, sizeof *node, &moonfish_compare);
+
node->count = child_count;
}
@@ -237,44 +234,62 @@
*chess = move.chess;
}
+#ifndef moonfish_no_threads
+
+static void moonfish_clear(struct moonfish_node *node)
+{+ if (node == NULL) return;
+ moonfish_clear(node->parent);
+ atomic_fetch_add(&node->uses, -1);
+}
+
+#endif
+
static struct moonfish_node *moonfish_select(struct moonfish_node *node, struct moonfish_chess *chess)
{struct moonfish_node *next;
float max_confidence, confidence;
- short int i, n;
+ short int i, count;
for (;;) {#ifdef moonfish_no_threads
- n = node->count;
- if (n <= 0) break;
+ count = node->count;
+ if (count == 0) return node;
#else
- n = 0;
- if (atomic_compare_exchange_strong(&node->count, &n, -1)) break;
- if (n == -1) continue;
- if (n == -2) break;
+ atomic_fetch_add(&node->uses, 1);
+ for (;;) {+ count = 0;
+ if (atomic_compare_exchange_strong(&node->count, &count, -1)) return node;
+ if (count == -2) {+ moonfish_clear(node);
+ return NULL;
+ }
+ if (count > 0) break;
+ }
#endif
- next = NULL;
- max_confidence = -1;
-
- for (i = 0 ; i < n ; i++) {- if (node->children[i].ignored) continue;
- if (node->children[i].count == -1) continue;
- confidence = moonfish_confidence(node->children + i);
- if (confidence > max_confidence) {- next = node->children + i;
- max_confidence = confidence;
+ for (;;) {+
+ next = NULL;
+ max_confidence = -1;
+
+ for (i = 0 ; i < count ; i++) {+ if (node->children[i].ignored) continue;
+ if (node->children[i].count == -1) continue;
+ confidence = moonfish_confidence(node->children + i);
+ if (confidence > max_confidence) {+ next = node->children + i;
+ max_confidence = confidence;
+ }
}
+
+ if (next != NULL) break;
}
- if (next == NULL) continue;
-
node = next;
moonfish_node_chess(node, chess);
}
-
- return node;
}
static void moonfish_propagate(struct moonfish_node *node)
@@ -281,28 +296,33 @@
{int i;
short int score, child_score;
+ struct moonfish_node *next;
while (node != NULL) {- score = node->count == -2 ? 0 : SHRT_MIN;
+ score = node->count == 0 ? 0 : SHRT_MIN;
for (i = 0 ; i < node->count ; i++) {child_score = -node->children[i].score;
if (score < child_score) score = child_score;
}
+ next = node->parent;
node->score = score;
#ifdef moonfish_no_threads
node->visits++;
#else
atomic_fetch_add(&node->visits, 1);
+ atomic_fetch_add(&node->uses, -1);
#endif
- node = node->parent;
+ node = next;
}
}
-static void moonfish_propagate_bounds(struct moonfish_node *node, int i)
+static void moonfish_propagate_bounds(struct moonfish_node *node)
{- int j;
+ int i, j;
int bound;
+ i = 1;
+
while (node != NULL) {bound = 0;
@@ -325,20 +345,19 @@
}
}
-static void moonfish_search(struct moonfish_node *node, struct moonfish_chess *chess0, int count)
+static void moonfish_search(struct moonfish_node *node, struct moonfish_chess *chess0)
{int i;
struct moonfish_node *leaf;
struct moonfish_chess chess;
- for (i = 0 ; i < count ; i++) {+ for (i = 0 ; i < 0x1000 ; i++) {chess = *chess0;
leaf = moonfish_select(node, &chess);
+ if (leaf == NULL) continue;
moonfish_expand(leaf, &chess);
+ if (leaf->count == 0 && moonfish_check(&chess)) moonfish_propagate_bounds(leaf);
moonfish_propagate(leaf);
- if (leaf->count == -2 && moonfish_check(&chess)) {- moonfish_propagate_bounds(leaf, 1);
- }
}
}
@@ -345,11 +364,8 @@
static void moonfish_clean(struct moonfish_node *node)
{int i;
-
for (i = 0 ; i < node->count ; i++) {- if (node->children[i].ignored) continue;
- if (node->children[i].count <= 0) continue;
- if (node->children[i].visits < node->visits / node->count / 3) {+ if (node->children[i].visits < node->visits / node->count / 2) {moonfish_discard(node->children + i);
}
moonfish_clean(node->children + i);
@@ -363,7 +379,7 @@
thread = data;
- moonfish_search(&thread->root->node, &thread->root->chess, 0x100);
+ moonfish_search(&thread->root->node, &thread->root->chess);
while (moonfish_clock() - thread->time0 < thread->time) {#ifndef moonfish_mini
if (thread->root->stop) break;
@@ -374,7 +390,7 @@
if (thread->root->node.children[i].ignored) count--;
}
if (count <= 1) break;
- moonfish_search(&thread->root->node, &thread->root->chess, 0x1000);
+ moonfish_search(&thread->root->node, &thread->root->chess);
if (thread->clean) moonfish_clean(&thread->root->node);
}
--
⑨