ref: ffac9231da5c1b585b6d4947918d8e20ce841f0a
parent: 3906bf099df6dea54b0cbeff50ccc246f69a0c2c
author: zamfofex <zamfofex@twdb.moe>
date: Mon Dec 30 11:03:56 EST 2024
add MultiPV support
--- a/main.c
+++ b/main.c
@@ -11,21 +11,38 @@
#include "moonfish.h"
#include "threads.h"
+struct moonfish_option {+ char *name;
+ char *type;
+ int value;
+ int min, max;
+};
+
struct moonfish_info {struct moonfish_root *root;
- _Atomic int thread_count;
_Atomic unsigned char searching;
#ifndef moonfish_no_threads
unsigned char has_thread;
thrd_t thread;
#endif
+ struct moonfish_option *options;
};
+static int moonfish_getoption(struct moonfish_option *options, char *name)
+{+ int i;
+ for (i = 0 ; options[i].name != NULL ; i++) {+ if (!strcasecmp(options[i].name, name)) return options[i].value;
+ }
+ return -1;
+}
+
static moonfish_result_t moonfish_go(void *data)
{- static struct moonfish_result result;
+ static struct moonfish_result result, pv_result;
static struct moonfish_options options;
static struct moonfish_chess chess;
+ static struct moonfish_move pv[256];
long int our_time, their_time, *xtime, time;
char *arg, *end;
@@ -32,6 +49,7 @@
char name[6];
struct moonfish_info *info;
long int node_count;
+ int i, j, pv_count, count;
info = data;
@@ -113,13 +131,32 @@
options.max_time = time;
options.our_time = our_time;
- options.thread_count = info->thread_count;
+ options.thread_count = moonfish_getoption(info->options, "Threads");
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);+ }
+ printf("\n");+ }
+
+ 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);
- info->searching = 0;
- 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);
@@ -191,10 +228,11 @@
if (!moonfish_equal(&chess0, &chess)) moonfish_reroot(root, &chess);
}
-static void moonfish_setoption(_Atomic int *thread_count)
+static void moonfish_setoption(struct moonfish_info *info)
{char *arg, *end;
- long int count;
+ long int value;
+ int i;
arg = strtok(NULL, "\r\n\t ");
if (arg == NULL || strcmp(arg, "name")) {@@ -203,7 +241,16 @@
}
arg = strtok(NULL, "\r\n\t ");
- if (arg == NULL || strcasecmp(arg, "Threads")) {+ if (arg == NULL) {+ fprintf(stderr, "missing option name\n");
+ exit(1);
+ }
+
+ for (i = 0 ; info->options[i].name != NULL ; i++) {+ if (!strcasecmp(arg, info->options[i].name)) break;
+ }
+
+ if (info->options[i].name == NULL) {fprintf(stderr, "unknown option '%s'\n", arg);
exit(1);
}
@@ -221,21 +268,29 @@
}
errno = 0;
- count = strtol(arg, &end, 10);
- if (errno || *end != 0 || count < 1 || count > 256) {- fprintf(stderr, "malformed thread count\n");
+ value = strtol(arg, &end, 10);
+ if (errno || *end != 0 || value < info->options[i].min || value > info->options[i].max) {+ fprintf(stderr, "malformed option value\n");
exit(1);
}
- *thread_count = count;
+ info->options[i].value = value;
}
int main(int argc, char **argv)
{static char line[2048];
+ static struct moonfish_info info;
+ static struct moonfish_option options[] = {+#ifndef moonfish_no_threads
+ {"Threads", "spin", 0, 1, 256},+#endif
+ {"MultiPV", "spin", 0, 0, 256},+ {NULL},+ };
char *arg;
- struct moonfish_info info;
+ int i;
if (argc > 1) {fprintf(stderr, "usage: %s (no arguments)\n", argv[0]);
@@ -243,14 +298,14 @@
}
info.root = moonfish_new();
- info.thread_count = 1;
info.searching = 0;
+ info.options = options;
#ifndef moonfish_no_threads
info.has_thread = 0;
- info.thread_count = sysconf(_SC_NPROCESSORS_ONLN);
- if (info.thread_count > 256) info.thread_count = 256;
- if (info.thread_count < 1) info.thread_count = 4;
+ options[0].value = sysconf(_SC_NPROCESSORS_ONLN);
+ if (options[0].value > options[0].max) options[0].value = options[0].max;
+ if (options[0].value < 1) options[0].value = 4;
#endif
for (;;) {@@ -307,9 +362,9 @@
if (!strcmp(arg, "uci")) { printf("id name moonfish\n"); printf("id author zamfofex\n");-#ifndef moonfish_no_threads
- printf("option name Threads type spin default %d min 1 max 256\n", info.thread_count);-#endif
+ for (i = 0 ; options[i].name != NULL ; i++) {+ printf("option name %s type %s default %d min %d max %d\n", options[i].name, options[i].type, options[i].value, options[i].min, options[i].max);+ }
printf("uciok\n");continue;
}
@@ -319,13 +374,13 @@
continue;
}
-#ifndef moonfish_no_threads
-
if (!strcmp(arg, "setoption")) {- moonfish_setoption(&info.thread_count);
- if (info.searching) printf("info string warning: option will only take effect next search request\n");+ moonfish_setoption(&info);
+ if (info.searching) printf("info string warning: option may only take effect next search request\n");continue;
}
+
+#ifndef moonfish_no_threads
if (!strcmp(arg, "stop")) {moonfish_stop(info.root);
--- a/moonfish.h
+++ b/moonfish.h
@@ -203,6 +203,9 @@
void moonfish_stop(struct moonfish_root *root);
void moonfish_unstop(struct moonfish_root *root);
+/* requests the PV with the given index, with at most 'count' moves */
+void moonfish_pv(struct moonfish_root *root, struct moonfish_move *moves, struct moonfish_result *result, int index, int *count);
+
#endif
#endif
--- a/search.c
+++ b/search.c
@@ -129,6 +129,8 @@
const struct moonfish_node *a, *b;
a = ax;
b = bx;
+ if (!a->ignored && b->ignored) return -1;
+ if (a->ignored && !b->ignored) return 1;
return a->score - b->score;
}
@@ -337,9 +339,7 @@
void moonfish_best_move(struct moonfish_root *root, struct moonfish_result *result, struct moonfish_options *options)
{struct moonfish_data data;
- struct moonfish_node *best_node;
long int time;
- long int best_visits;
int i;
#ifndef moonfish_no_threads
thrd_t threads[256];
@@ -378,18 +378,8 @@
#endif
- best_visits = -1;
- best_node = NULL;
-
- for (i = 0 ; i < root->node.count ; i++) {- if (root->node.children[i].ignored) continue;
- if (root->node.children[i].visits > best_visits) {- best_node = root->node.children + i;
- best_visits = best_node->visits;
- }
- }
-
- moonfish_node_move(best_node, &root->chess, &result->move);
+ qsort(root->node.children, root->node.count, sizeof root->node, &moonfish_compare);
+ moonfish_node_move(root->node.children, &root->chess, &result->move);
result->score = root->node.score;
result->node_count = root->node.visits;
}
@@ -469,6 +459,48 @@
void moonfish_unstop(struct moonfish_root *root)
{root->stop = 0;
+}
+
+void moonfish_pv(struct moonfish_root *root, struct moonfish_move *moves, struct moonfish_result *result, int i, int *count)
+{+ struct moonfish_node *node;
+ struct moonfish_chess chess;
+ int j;
+ int best_score;
+ struct moonfish_node *best_node;
+
+ if (i >= root->node.count) *count = 0;
+ if (*count == 0) return;
+
+ node = root->node.children + i;
+ chess = root->chess;
+
+ moonfish_node_move(node, &chess, &result->move);
+ result->score = -node->score;
+ result->node_count = node->visits;
+
+ for (j = 0 ; j < *count ; j++) {+
+ if (node == NULL) {+ *count = j - 1;
+ break;
+ }
+
+ moonfish_node_move(node, &chess, moves + j);
+ chess = moves[j].chess;
+
+ best_score = INT_MAX;
+ best_node = NULL;
+ for (i = 0 ; i < node->count ; i++) {+ if (node->children[i].ignored) continue;
+ if (node->children[i].score < best_score) {+ best_node = node->children + i;
+ best_score = best_node->score;
+ }
+ }
+
+ node = best_node;
+ }
}
#endif
--
⑨