shithub: moonfish

Download patch

ref: edfb1269aba6f7602aab6e6a25945064a5c97e0f
parent: 2777bd283d4e238761e594fcd038e20f5b9a1d7b
author: zamfofex <zamfofex@twdb.moe>
date: Wed Nov 27 12:36:47 EST 2024

add support for 'stop'

--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@
 !/.build.yml
 !/moonfish.vcxproj
 !/moonfish.h
+!/threads.h
 !/chess.c
 !/search.c
 !/main.c
--- a/main.c
+++ b/main.c
@@ -8,8 +8,18 @@
 #include <strings.h>
 
 #include "moonfish.h"
+#include "threads.h"
 
-static void moonfish_go(struct moonfish_node *node, int thread_count)
+struct moonfish_info {
+	struct moonfish_node *node;
+	int thread_count;
+	_Atomic unsigned char searching;
+#ifndef moonfish_no_threads
+	thrd_t thread;
+#endif
+};
+
+static moonfish_result_t moonfish_go(void *data)
 {
 	static struct moonfish_result result;
 	static struct moonfish_options options;
@@ -18,12 +28,15 @@
 	long int our_time, their_time, *xtime, time;
 	char *arg, *end;
 	char name[6];
+	struct moonfish_info *info;
 	
+	info = data;
+	
 	our_time = -1;
 	their_time = -1;
 	time = -1;
 	
-	moonfish_root(node, &chess);
+	moonfish_root(info->node, &chess);
 	
 	for (;;) {
 		
@@ -78,12 +91,16 @@
 	
 	options.max_time = time;
 	options.our_time = our_time;
-	options.thread_count = thread_count;
-	moonfish_best_move(node, &result, &options);
+	options.thread_count = info->thread_count;
+	moonfish_best_move(info->node, &result, &options);
 	moonfish_to_uci(&chess, &result.move, name);
 	
+	info->searching = 2;
 	printf("info depth 1 score cp %d nodes %ld multipv 1 pv %s\n", result.score, result.node_count, name);
 	printf("bestmove %s\n", name);
+	fflush(stdout);
+	
+	return moonfish_value;
 }
 
 static void moonfish_position(struct moonfish_node *node)
@@ -193,10 +210,9 @@
 int main(int argc, char **argv)
 {
 	static char line[2048];
-	int thread_count;
 	
 	char *arg;
-	struct moonfish_node *node;
+	struct moonfish_info info;
 	
 	if (argc > 1) {
 		fprintf(stderr, "usage: %s (no arguments)\n", argv[0]);
@@ -203,8 +219,9 @@
 		return 1;
 	}
 	
-	node = moonfish_new();
-	thread_count = 1;
+	info.node = moonfish_new();
+	info.thread_count = 1;
+	info.searching = 0;
 	
 	for (;;) {
 		
@@ -220,7 +237,27 @@
 		if (arg == NULL) continue;
 		
 		if (!strcmp(arg, "go")) {
-			moonfish_go(node, thread_count);
+#ifdef moonfish_no_threads
+			moonfish_go(&info);
+#else
+			if (info.searching == 2) {
+				if (thrd_join(info.thread, NULL) != thrd_success) {
+					fprintf(stderr, "could not join thread\n");
+					exit(1);
+				}
+			}
+			else {
+				if (info.searching) {
+					fprintf(stderr, "cannot start search while searching\n");
+					exit(1);
+				}
+			}
+			info.searching = 1;
+			if (thrd_create(&info.thread, &moonfish_go, &info) != thrd_success) {
+				fprintf(stderr, "could not create thread\n");
+				exit(1);
+			}
+#endif
 			continue;
 		}
 		
@@ -227,7 +264,11 @@
 		if (!strcmp(arg, "quit")) break;
 		
 		if (!strcmp(arg, "position")) {
-			moonfish_position(node);
+			if (info.searching == 1) {
+				fprintf(stderr, "cannot set position while searching\n");
+				exit(1);
+			}
+			moonfish_position(info.node);
 			continue;
 		}
 		
@@ -247,10 +288,27 @@
 		}
 		
 #ifndef moonfish_no_threads
+		
 		if (!strcmp(arg, "setoption")) {
-			moonfish_setoption(&thread_count);
+			moonfish_setoption(&info.thread_count);
+			if (info.searching == 1) {
+				printf("info string warning: option will only take effect next search request\n");
+			}
 			continue;
 		}
+		
+		if (!strcmp(arg, "stop")) {
+			if (info.searching) {
+				moonfish_stop(info.node);
+				if (thrd_join(info.thread, NULL) != thrd_success) {
+					fprintf(stderr, "could not join thread\n");
+					exit(1);
+				}
+				info.searching = 0;
+			}
+			continue;
+		}
+		
 #endif
 		
 		if (!strcmp(arg, "debug") || !strcmp(arg, "ucinewgame") || !strcmp(arg, "stop")) continue;
@@ -258,6 +316,16 @@
 		fprintf(stderr, "warning: unknown command '%s'\n", arg);
 	}
 	
-	moonfish_finish(node);
+#ifndef moonfish_no_threads
+	if (info.searching) {
+		moonfish_stop(info.node);
+		if (thrd_join(info.thread, NULL) != thrd_success) {
+			fprintf(stderr, "could not join thread\n");
+			exit(1);
+		}
+	}
+#endif
+	
+	moonfish_finish(info.node);
 	return 0;
 }
--- a/makefile
+++ b/makefile
@@ -12,7 +12,7 @@
 
 all: moonfish lichess analyse chat
 
-moonfish: moonfish.h chess.c search.c main.c
+moonfish: moonfish.h threads.h chess.c search.c main.c
 	$(cc) $(filter %.c,$^) -o $@ -lm -pthread -latomic
 
 %: moonfish.h tools/tools.h tools/utils.c chess.c tools/%.c
--- a/moonfish.h
+++ b/moonfish.h
@@ -202,4 +202,7 @@
 /* frees the given state (so that it is no longer usable) */
 void moonfish_finish(struct moonfish_node *node);
 
+/* requests to stop searching the given state (from a different thread) */
+void moonfish_stop(struct moonfish_node *node);
+
 #endif
--- a/moonfish.vcxproj
+++ b/moonfish.vcxproj
@@ -20,6 +20,7 @@
 	</ItemDefinitionGroup>
 	<ItemGroup>
 		<ClInclude Include="moonfish.h" />
+		<ClInclude Include="threads.h" />
 		<ClCompile Include="chess.c" />
 		<ClCompile Include="search.c" />
 		<ClCompile Include="main.c" />
--- a/scripts/compare.sh
+++ b/scripts/compare.sh
@@ -58,7 +58,7 @@
 "$cli" \
 	-engine {name=,cmd=./}moonfish-"$rev1$dirty" \
 	-engine {name=,cmd=./}moonfish-"$rev2" \
-	-each $protocol tc=inf/10+0.1 \
+	-each $protocol tc=inf/10+0.1 option.Threads=1 \
 	-openings $format file=openings.fen order=random \
 	-games 2 -rounds 1024 \
 	-sprt elo0=0 elo1=12 alpha=0.05 beta=0.05 \
--- a/scripts/minify.sh
+++ b/scripts/minify.sh
@@ -11,7 +11,7 @@
 (sleep 3;rm $t)&exec $t'
 
 # for each C source file
-cat moonfish.h chess.c search.c mini.c |
+cat moonfish.h threads.h chess.c search.c mini.c |
 
 # remove the '#' from system '#include'
 sed -E 's/^#(include <)/\1/g' |
--- a/search.c
+++ b/search.c
@@ -13,42 +13,8 @@
 #include <time.h>
 #endif
 
-#ifdef moonfish_no_threads
-
-#define moonfish_result_t int
-#define moonfish_value 0
-#define _Atomic
-
-#else
-
-#include <stdatomic.h>
-
-#ifndef moonfish_pthreads
-
-#include <threads.h>
-#define moonfish_result_t int
-#define moonfish_value 0
-
-#else
-
-#include <pthread.h>
-#define thrd_t pthread_t
-#define thrd_create(thread, fn, arg) pthread_create(thread, NULL, fn, arg)
-#define thrd_join pthread_join
-#define moonfish_result_t void *
-#define moonfish_value NULL
-#define thrd_success 0
-
-#endif
-
-#endif
-
-#ifdef moonfish_mini
-#undef atomic_compare_exchange_strong
-#undef atomic_fetch_add
-#endif
-
 #include "moonfish.h"
+#include "threads.h"
 
 #ifdef _WIN32
 
@@ -323,6 +289,7 @@
 	
 	moonfish_search(data->node, 0x100);
 	while (moonfish_clock() - data->time0 < data->time) {
+		if (data->node->ignored) break;
 		count = data->node->count;
 		for (i = 0 ; i < data->node->count ; i++) {
 			if (data->node->children[i].ignored) count--;
@@ -350,6 +317,7 @@
 	if (options->our_time >= 0 && time > options->our_time / 16) time = options->our_time / 16;
 	time -= time / 32 + 125;
 	
+	node->ignored = 0;
 	data.node = node;
 	data.time = time;
 	data.time0 = moonfish_clock();
@@ -450,3 +418,12 @@
 	moonfish_discard(node);
 	free(node);
 }
+
+#ifndef moonfish_mini
+
+void moonfish_stop(struct moonfish_node *node)
+{
+	node->ignored = 1;
+}
+
+#endif
--- /dev/null
+++ b/threads.h
@@ -1,0 +1,42 @@
+/* moonfish is licensed under the AGPL (v3 or later) */
+/* copyright 2024 zamfofex */
+
+#ifndef MOONFISH_THREADS
+#define MOONFISH_THREADS
+
+#ifdef moonfish_no_threads
+
+#define moonfish_result_t int
+#define moonfish_value 0
+#define _Atomic
+
+#else
+
+#include <stdatomic.h>
+
+#ifndef moonfish_pthreads
+
+#include <threads.h>
+#define moonfish_result_t int
+#define moonfish_value 0
+
+#else
+
+#include <pthread.h>
+#define thrd_t pthread_t
+#define thrd_create(thread, fn, arg) pthread_create(thread, NULL, fn, arg)
+#define thrd_join pthread_join
+#define moonfish_result_t void *
+#define moonfish_value NULL
+#define thrd_success 0
+
+#endif
+
+#endif
+
+#ifdef moonfish_mini
+#undef atomic_compare_exchange_strong
+#undef atomic_fetch_add
+#endif
+
+#endif
--