ref: 06a96d4d98f4308bf512bdb7fa6d87a29fbce4a9
parent: 401af6dfdde75f7e37b5f4874e99776d9ea1de67
author: zamfofex <zamfofex@twdb.moe>
date: Mon Jan 22 21:47:58 EST 2024
improve search (experimental)
--- a/main.c
+++ b/main.c
@@ -11,7 +11,7 @@
int main(int argc, char **argv)
{static char line[2048];
- struct moonfish *ctx;
+ struct moonfish_analysis *analysis;
char *arg;
struct moonfish_move move;
char name[6];
@@ -18,6 +18,7 @@
long int wtime, btime, *xtime;
int score;
int depth;
+ struct moonfish_chess chess;
if (argc > 1)
{@@ -25,16 +26,9 @@
return 1;
}
- ctx = malloc(sizeof *ctx);
- if (ctx == NULL)
- {- perror(argv[0]);
- return 1;
- }
+ analysis = moonfish_analysis(argv[0]);
+ moonfish_chess(&chess);
- ctx->argv0 = argv[0];
- moonfish_chess(&ctx->chess);
-
for (;;)
{errno = 0;
@@ -42,7 +36,6 @@
{if (errno)
{- free(ctx);
perror(argv[0]);
return 1;
}
@@ -72,7 +65,6 @@
if (arg == NULL || sscanf(arg, "%ld", xtime) != 1 || *xtime < 0)
{- free(ctx);
fprintf(stderr, "%s: malformed 'go' command\n", argv[0]);
return 1;
}
@@ -84,7 +76,6 @@
if (arg == NULL || sscanf(arg, "%d", &depth) != 1 || depth < 0)
{- free(ctx);
fprintf(stderr, "%s: malformed 'go depth' command\n", argv[0]);
return 1;
}
@@ -99,12 +90,12 @@
#ifdef moonfish_mini
exit(1);
#else
- score = moonfish_best_move_depth(ctx, &move, depth);
+ score = moonfish_best_move_depth(analysis, &move, depth);
#endif
- else if (ctx->chess.white)
- score = moonfish_best_move_time(ctx, &move, &depth, wtime, btime);
+ else if (chess.white)
+ score = moonfish_best_move_time(analysis, &move, &depth, wtime, btime);
else
- score = moonfish_best_move_time(ctx, &move, &depth, btime, wtime);
+ score = moonfish_best_move_time(analysis, &move, &depth, btime, wtime);
printf("info depth %d ", depth);if (score >= moonfish_omega || score <= -moonfish_omega)
@@ -124,19 +115,18 @@
if (arg == NULL)
{fprintf(stderr, "incomplete 'position' command\n");
- free(ctx);
return 1;
}
if (!strcmp(arg, "startpos"))
{- moonfish_chess(&ctx->chess);
+ moonfish_chess(&chess);
}
#ifndef moonfish_mini
else if (!strcmp(arg, "fen"))
{arg = strtok(NULL, "\r\n");
- moonfish_fen(&ctx->chess, arg);
+ moonfish_fen(&chess, arg);
arg = strstr(arg, "moves");
if (arg != NULL)
@@ -155,7 +145,6 @@
else
{fprintf(stderr, "malformed 'position' command\n");
- free(ctx);
return 1;
}
@@ -164,10 +153,12 @@
{while ((arg = strtok(NULL, "\r\n\t ")) != NULL)
{- moonfish_from_uci(&ctx->chess, &move, arg);
- moonfish_play(&ctx->chess, &move);
+ moonfish_from_uci(&chess, &move, arg);
+ moonfish_play(&chess, &move);
}
}
+
+ moonfish_new(analysis, &chess);
}
else if (!strcmp(arg, "uci"))
{@@ -192,6 +183,6 @@
fflush(stdout);
}
- free(ctx);
+ moonfish_free(analysis);
return 0;
}
--- a/moonfish.h
+++ b/moonfish.h
@@ -49,12 +49,6 @@
int score;
};
-struct moonfish
-{- struct moonfish_chess chess;
- char *argv0;
-};
-
struct moonfish_move
{unsigned char from, to;
@@ -66,6 +60,8 @@
int score;
};
+struct moonfish_analysis;
+
void moonfish_chess(struct moonfish_chess *chess);
void moonfish_moves(struct moonfish_chess *chess, struct moonfish_move *moves, unsigned char from);
@@ -73,9 +69,13 @@
void moonfish_play(struct moonfish_chess *chess, struct moonfish_move *move);
void moonfish_unplay(struct moonfish_chess *chess, struct moonfish_move *move);
-int moonfish_best_move_time(struct moonfish *ctx, struct moonfish_move *move, int *depth, long int our_time, long int their_time);
+int moonfish_best_move_time(struct moonfish_analysis *analysis, struct moonfish_move *move, int *depth, long int our_time, long int their_time);
int moonfish_countdown(int score);
+struct moonfish_analysis *moonfish_analysis(char *argv0);
+void moonfish_new(struct moonfish_analysis *analysis, struct moonfish_chess *chess);
+void moonfish_free(struct moonfish_analysis *analysis);
+
void moonfish_move(struct moonfish_chess *chess, struct moonfish_move *move, unsigned char from, unsigned char to);
void moonfish_from_uci(struct moonfish_chess *chess, struct moonfish_move *move, char *name);
void moonfish_to_uci(char *name, struct moonfish_move *move);
@@ -86,7 +86,7 @@
#ifndef moonfish_mini
int moonfish_fen(struct moonfish_chess *chess, char *fen);
-int moonfish_best_move_depth(struct moonfish *ctx, struct moonfish_move *move, int depth);
+int moonfish_best_move_depth(struct moonfish_analysis *analysis, struct moonfish_move *move, int depth);
int moonfish_finished(struct moonfish_chess *chess);
int moonfish_checkmate(struct moonfish_chess *chess);
--- a/search.c
+++ b/search.c
@@ -47,127 +47,164 @@
struct moonfish_node
{- unsigned char from, to;
struct moonfish_node *children;
+ int score;
+ int visits;
+ unsigned char from, to;
unsigned char count;
- short int score;
};
struct moonfish_info
{- struct moonfish *ctx;
+ struct moonfish_analysis *analysis;
pthread_t thread;
+ struct moonfish_node *node;
struct moonfish_move move;
struct moonfish_chess chess;
int depth;
int score;
- struct moonfish_node node;
- struct moonfish_node *nodes;
- int count;
};
-static void moonfish_free(struct moonfish_node *node)
+struct moonfish_analysis
{+ char *argv0;
+ struct moonfish_chess chess;
+ struct moonfish_info info[256];
+ struct moonfish_node root;
+ int depth;
+};
+
+static void moonfish_free_node(struct moonfish_node *node)
+{int i;
for (i = 0 ; i < node->count ; i++)
- moonfish_free(node->children + i);
+ moonfish_free_node(node->children + i);
if (node->count > 0)
free(node->children);
+ node->count = 0;
}
-static int moonfish_quiesce(struct moonfish_chess *chess, int alpha, int beta, int depth, int i)
+struct moonfish_analysis *moonfish_analysis(char *argv0)
{- int x, y;
+ struct moonfish_analysis *analysis;
+ struct moonfish_chess chess;
+
+ analysis = malloc(sizeof *analysis);
+ if (analysis == NULL)
+ {+ perror(argv0);
+ exit(1);
+ }
+
+ analysis->argv0 = argv0;
+ analysis->root.count = 0;
+
+ moonfish_chess(&chess);
+ moonfish_new(analysis, &chess);
+
+ return analysis;
+}
+
+void moonfish_new(struct moonfish_analysis *analysis, struct moonfish_chess *chess)
+{+ moonfish_free_node(&analysis->root);
+ analysis->root.visits = 0;
+ analysis->root.count = 0;
+ analysis->chess = *chess;
+ analysis->depth = 1;
+}
+
+void moonfish_free(struct moonfish_analysis *analysis)
+{+ struct moonfish_chess chess;
+ moonfish_new(analysis, &chess);
+ free(analysis);
+}
+
+static void moonfish_expand(char *argv0, struct moonfish_node *node, struct moonfish_chess *chess)
+{struct moonfish_move moves[32];
struct moonfish_move *move;
- int score;
+ int x, y;
+ int done;
- score = chess->score;
- if (!chess->white) score *= -1;
+ if (node->count != 0) return;
- if (i >= depth) return score;
- if (score >= beta) return beta;
- if (score > alpha) alpha = score;
+ done = 0;
+ node->children = NULL;
- for (y = 0 ; y < 8 ; y++)
- for (x = 0 ; x < 8 ; x++)
+ for (y = 0 ; y < 8 && !done ; y++)
+ for (x = 0 ; x < 8 && !done ; x++)
{moonfish_moves(chess, moves, (x + 1) + (y + 2) * 10);
for (move = moves ; move->piece != moonfish_outside ; move++)
{- if (move->captured == moonfish_empty)
- if (move->promotion == move->piece)
- continue;
+ node->children = realloc(node->children, (node->count + 1) * sizeof *node->children);
+ if (node->children == NULL)
+ {+ perror(argv0);
+ exit(1);
+ }
- if (move->captured % 16 == moonfish_king)
- return moonfish_omega * (moonfish_depth - i);
-
- moonfish_play(chess, move);
- score = -moonfish_quiesce(chess, -beta, -alpha, depth, i + 1);
- moonfish_unplay(chess, move);
-
- if (score >= beta) return beta;
- if (score > alpha) alpha = score;
+ node->children[node->count].from = move->from;
+ node->children[node->count].to = move->to;
+ node->children[node->count].count = 0;
+ node->children[node->count].visits = 0;
+ node->count++;
}
}
-
- return alpha;
}
-static int moonfish_search(struct moonfish_info *info, struct moonfish_node *node, int alpha, int beta, int depth, int qdepth, int i)
+static int moonfish_search(struct moonfish_info *info, struct moonfish_node *parent, struct moonfish_node *node, int alpha, int beta, int depth, int i)
{- int x, y;
- struct moonfish_move moves[32];
- struct moonfish_move *move;
int score;
int j, k;
struct moonfish_node swap_node;
- int done;
- struct moonfish_move move0;
+ struct moonfish_move move;
+ int group_count;
+ unsigned char adjust[256];
- if (i >= depth) return moonfish_quiesce(&info->chess, alpha, beta, depth + qdepth, i);
+ if (i >= depth)
+ {+ node->visits++;
+ score = info->chess.score;
+ if (!info->chess.white) score *= -1;
+ return score;
+ }
- if (node->count == 0)
+ moonfish_expand(info->analysis->argv0, node, &info->chess);
+
+ group_count = (parent->visits / parent->count) / (node->visits + 1) / 16 + 1;
+
+ for (j = 0 ; j < node->count ; j++)
{- done = 0;
- node->children = NULL;
-
- for (y = 0 ; y < 8 && !done ; y++)
- for (x = 0 ; x < 8 && !done ; x++)
+ if (node->children[j].visits == 0)
{- moonfish_moves(&info->chess, moves, (x + 1) + (y + 2) * 10);
-
- for (move = moves ; move->piece != moonfish_outside ; move++)
- {- node->children = realloc(node->children, (node->count + 1) * sizeof *node->children);
- if (node->children == NULL)
- {- perror(info->ctx->argv0);
- exit(1);
- }
-
- node->children[node->count].from = move->from;
- node->children[node->count].to = move->to;
- node->children[node->count].count = 0;
- node->count++;
- }
+ adjust[j] = 0;
+ continue;
}
+ if (node->children[j].score >= moonfish_omega || node->children[j].score <= -moonfish_omega)
+ {+ adjust[j] = 0xFF;
+ continue;
+ }
+ adjust[j] = j * group_count / node->count;
}
for (j = 0 ; j < node->count ; j++)
{- moonfish_move(&info->chess, &move0, node->children[j].from, node->children[j].to);
+ moonfish_move(&info->chess, &move, node->children[j].from, node->children[j].to);
- if (move0.captured % 16 == moonfish_king)
+ if (move.captured % 16 == moonfish_king)
{score = moonfish_omega * (moonfish_depth - i);
}
else
{- moonfish_play(&info->chess, &move0);
- score = -moonfish_search(info, node->children + j, -beta, -alpha, depth, qdepth, i + 1);
- moonfish_unplay(&info->chess, &move0);
+ moonfish_play(&info->chess, &move);
+ score = -moonfish_search(info, node, node->children + j, -beta, -alpha, depth - adjust[j], i + 1);
+ moonfish_unplay(&info->chess, &move);
}
node->children[j].score = score;
@@ -182,10 +219,15 @@
}
break;
}
+
if (score > alpha) alpha = score;
}
+ node->visits = 0;
for (j = 1 ; j < node->count ; j++)
+ node->visits += node->children[j].visits;
+
+ for (j = 1 ; j < node->count ; j++)
for (k = j ; k > 0 && node->children[k - 1].score < node->children[k].score ; k--)
{swap_node = node->children[k];
@@ -193,6 +235,12 @@
node->children[k - 1] = swap_node;
}
+ if (i > 5 && node->count > 0)
+ {+ free(node->children);
+ node->count = 0;
+ }
+
return alpha;
}
@@ -208,97 +256,63 @@
{struct moonfish_info *info;
info = data;
- info->score = -moonfish_search(info, &info->node, -100 * moonfish_omega, 100 * moonfish_omega, info->depth, 4, 0);
+ info->score = -moonfish_search(info, &info->analysis->root, info->node, -100 * moonfish_omega, 100 * moonfish_omega, info->depth, 0);
return moonfish_value;
}
-static int moonfish_iteration(struct moonfish *ctx, struct moonfish_move *best_move, int depth, int init)
+static int moonfish_iteration(struct moonfish_analysis *analysis, struct moonfish_move *best_move, int depth)
{- static struct moonfish_move all_moves[256];
- static struct moonfish_info infos[256];
- static struct moonfish_move move_array[32];
- static int init0 = 0;
-
- int x, y;
+ struct moonfish_move move;
int best_score;
- int move_count;
- int i;
+ int i, j;
int result;
- if (!init0)
- {- init0 = 1;
- for (i = 0 ; i < 256 ; i++)
- infos[i].node.count = 0;
- }
+ moonfish_expand(analysis->argv0, &analysis->root, &analysis->chess);
- if (!init)
- {- for (i = 0 ; i < 256 ; i++)
- moonfish_free(&infos[i].node),
- infos[i].node.count = 0;
- }
+ j = 0;
- if (ctx == NULL) return 0;
-
- best_score = -200 * moonfish_omega;
-
- move_count = 0;
- for (y = 0 ; y < 8 ; y++)
- for (x = 0 ; x < 8 ; x++)
+ for (i = 0 ; i < analysis->root.count ; i++)
{- moonfish_moves(&ctx->chess, move_array, (x + 1) + (y + 2) * 10);
+ analysis->info[j].chess = analysis->chess;
- for (i = 0 ; move_array[i].piece != moonfish_outside ; i++)
- {- moonfish_play(&ctx->chess, move_array + i);
- if (moonfish_validate(&ctx->chess))
- {- all_moves[move_count] = move_array[i];
- move_count++;
- }
- moonfish_unplay(&ctx->chess, move_array + i);
- }
- }
-
- if (move_count == 1)
- {- *best_move = *all_moves;
- return 0;
- }
-
- for (i = 0 ; i < move_count ; i++)
- {- moonfish_play(&ctx->chess, all_moves + i);
+ moonfish_move(&analysis->info[j].chess, &move, analysis->root.children[i].from, analysis->root.children[i].to);
+ moonfish_play(&analysis->info[j].chess, &move);
- infos[i].ctx = ctx;
- infos[i].move = all_moves[i];
- infos[i].chess = ctx->chess;
- infos[i].depth = depth;
+ if (!moonfish_validate(&analysis->chess)) continue;
- result = pthread_create(&infos[i].thread, NULL, &moonfish_start_search, infos + i);
+ analysis->info[j].analysis = analysis;
+ analysis->info[j].node = analysis->root.children + i;
+ analysis->info[j].move = move;
+ analysis->info[j].depth = depth;
+
+ result = pthread_create(&analysis->info[j].thread, NULL, &moonfish_start_search, analysis->info + j);
if (result)
{- fprintf(stderr, "%s: %s\n", ctx->argv0, strerror(result));
+ fprintf(stderr, "%s: %s\n", analysis->argv0, strerror(result));
exit(1);
}
- moonfish_unplay(&ctx->chess, all_moves + i);
+ j++;
}
- for (i = 0 ; i < move_count ; i++)
+ best_score = -200 * moonfish_omega;
+ analysis->root.visits = 0;
+
+ for (i = 0 ; i < j ; i++)
{- result = pthread_join(infos[i].thread, NULL);
+ result = pthread_join(analysis->info[i].thread, NULL);
if (result)
{- fprintf(stderr, "%s: %s\n", ctx->argv0, strerror(result));
+ fprintf(stderr, "%s: %s\n", analysis->argv0, strerror(result));
exit(1);
}
- if (infos[i].score > best_score)
+ analysis->root.visits += analysis->info[i].node->visits;
+
+ if (analysis->info[i].score > best_score)
{- *best_move = infos[i].move;
- best_score = infos[i].score;
+ *best_move = analysis->info[i].move;
+ best_score = analysis->info[i].score;
}
}
@@ -307,20 +321,15 @@
#ifndef moonfish_mini
-int moonfish_best_move_depth(struct moonfish *ctx, struct moonfish_move *best_move, int depth)
+int moonfish_best_move_depth(struct moonfish_analysis *analysis, struct moonfish_move *best_move, int depth)
{- int i;
int score;
-
- moonfish_iteration(NULL, NULL, 0, 0);
-
- score = 0;
-
- i = 3;
- do score = moonfish_iteration(ctx, best_move, i++, 1);
- while (i <= depth);
-
- return score;
+ for (;;)
+ {+ score = moonfish_iteration(analysis, best_move, analysis->depth);
+ if (analysis->depth >= depth) return score;
+ analysis->depth++;
+ }
}
#endif
@@ -327,21 +336,21 @@
#ifdef _WIN32
-static long int moonfish_clock(struct moonfish *ctx)
+static long int moonfish_clock(struct moonfish_analysis *analysis)
{- (void) ctx;
+ (void) analysis;
return GetTickCount();
}
#else
-static long int moonfish_clock(struct moonfish *ctx)
+static long int moonfish_clock(struct moonfish_analysis *analysis)
{struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts))
{- perror(ctx->argv0);
+ perror(analysis->argv0);
exit(1);
}
@@ -350,7 +359,7 @@
#endif
-int moonfish_best_move_time(struct moonfish *ctx, struct moonfish_move *best_move, int *i, long int our_time, long int their_time)
+int moonfish_best_move_time(struct moonfish_analysis *analysis, struct moonfish_move *best_move, int *depth, long int our_time, long int their_time)
{long int d, t, t0, t1;
int score;
@@ -363,13 +372,11 @@
if (d < 0) d = 0;
d += our_time / 8;
- moonfish_iteration(NULL, NULL, 0, 0);
-
- for (*i = 1 ; *i < 32 ; (*i)++)
+ for (;;)
{- t0 = moonfish_clock(ctx);
- score = moonfish_iteration(ctx, best_move, *i, 1);
- t1 = moonfish_clock(ctx) + 50;
+ t0 = moonfish_clock(analysis);
+ score = moonfish_iteration(analysis, best_move, analysis->depth);
+ t1 = moonfish_clock(analysis) + 50;
if (t >= 0) r = (t1 - t0) * 2048 / (t + 1);
t = t1 - t0;
@@ -376,7 +383,10 @@
d -= t;
if (t * r > d * 2048) break;
+
+ analysis->depth++;
}
+ *depth = analysis->depth;
return score;
}
--
⑨