ref: 2c0fcbf09a5faa2800421e792955222460c3a695
parent: 3a4dd039662549083dfb672a6a78910af84ccce7
author: zamfofex <zamfofex@twdb.moe>
date: Fri Jun 21 23:09:52 EDT 2024
improve minification
--- a/.gitignore
+++ b/.gitignore
@@ -34,8 +34,4 @@
!/tools/https.c
!/tools/perft.c
!/tools/book.c
-!/extras
-!/extras/texel-tuner
-!/extras/moonfish.cc
-!/extras/moonfish.hh
-!/extras/config.h
+!/tools/learn.c
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +1,0 @@
-[submodule "extras/texel-tuner"]
- path = extras/texel-tuner
- url = https://github.com/GediminasMasaitis/texel-tuner
--- a/chess.c
+++ b/chess.c
@@ -3,86 +3,26 @@
#include "moonfish.h"
-static int moonfish_piece_square_scores[] =
-{- 0, 0, 0, 0,
- 232, 240, 242, 229,
- 172, 171, 176, 148,
- 128, 121, 129, 114,
- 119, 111, 116, 98,
- 102, 108, 116, 95,
- 95, 109, 121, 90,
- 0, 0, 0, 0,
-
- 330, 318, 308, 224,
- 360, 360, 324, 314,
- 386, 372, 366, 334,
- 371, 367, 352, 338,
- 347, 351, 339, 322,
- 337, 338, 322, 297,
- 319, 311, 301, 287,
- 299, 296, 289, 255,
-
- 358, 357, 353, 339,
- 368, 366, 363, 343,
- 386, 381, 378, 372,
- 388, 378, 376, 362,
- 377, 373, 366, 358,
- 370, 369, 363, 355,
- 352, 356, 364, 350,
- 331, 327, 326, 337,
-
- 583, 577, 576, 578,
- 593, 593, 585, 587,
- 588, 582, 579, 577,
- 574, 571, 569, 562,
- 554, 553, 552, 542,
- 540, 536, 535, 522,
- 537, 532, 524, 505,
- 553, 545, 529, 513,
-
- 1117, 1111, 1099, 1077,
- 1124, 1121, 1095, 1097,
- 1136, 1124, 1118, 1103,
- 1114, 1113, 1098, 1107,
- 1080, 1088, 1091, 1099,
- 1076, 1080, 1077, 1069,
- 1076, 1075, 1069, 1062,
- 1065, 1050, 1050, 1071,
-
- 30, 37, 43, -17,
- 33, 36, 52, 15,
- 24, 36, 42, 19,
- 7, 17, 20, 0,
- -5, 1, -1, -17,
- -15, -10, -9, -22,
- -37, -14, -1, -1,
- -14, -21, 16, -2,
-};
+moonfish_t moonfish_values[moonfish_size] = {0,0,0,0,138,180,159,139,137,167,147,150,135,159,159,167,170,190,176,191,222,260,267,253,313,370,387,366,0,0,0,0,311,363,377,386,366,390,408,413,382,416,436,433,416,448,459,462,431,459,483,483,435,479,491,505,402,418,469,477,307,390,403,431,431,422,411,426,452,467,461,456,466,470,482,483,473,475,483,493,470,485,492,508,489,483,496,505,441,465,476,483,442,451,462,465,653,686,713,726,660,684,687,698,680,703,700,711,709,726,728,729,736,755,757,757,760,781,785,777,780,772,790,785,762,764,759,775,1282,1267,1261,1274,1284,1289,1295,1297,1290,1300,1303,1301,1323,1338,1325,1325,1344,1328,1366,1361,1328,1368,1379,1392,1326,1324,1363,1384,1286,1306,1348,1351,-4,5,-51,-42,-9,-11,-30,-58,-37,-26,-36,-36,-44,-16,-17,-16,-11,14,9,-14,19,50,36,15,26,86,41,36,2,42,42,34};-static int moonfish_table(int from, unsigned char piece)
+static void moonfish_table(struct moonfish_chess *chess, int from, unsigned char piece, int n)
{int x, y;
unsigned char type, color;
- int score;
- if (piece == moonfish_empty) return 0;
+ if (piece == moonfish_empty) return;
x = from % 10 - 1;
y = from / 10 - 2;
- type = (piece % 16) - 1;
- color = (piece / 16) - 1;
+ type = piece % 16 - 1;
+ color = piece / 16 - 1;
+ n *= color * 2 - 1;
- if (color == 0) y = 7 - y;
+ if (x > 3) x = 7 - x;
+ if (color == 1) y = 7 - y;
- if (x < 4) x = 3 - x;
- else x %= 4;
-
- score = moonfish_piece_square_scores[x + y * 4 + type * 32];
- if (color != 0) score *= -1;
-
- return score;
+ chess->score -= moonfish_values[x + y * 4 + type * 32] * n;
}
static void moonfish_force_promotion(struct moonfish_chess *chess, struct moonfish_move **moves, unsigned char from, unsigned char to, unsigned char promotion)
@@ -90,18 +30,20 @@
(*moves)->from = from;
(*moves)->to = to;
(*moves)->chess = *chess;
+
+ moonfish_table(&(*moves)->chess, from, chess->board[from], -1);
+ moonfish_table(&(*moves)->chess, to, promotion, 1);
+ moonfish_table(&(*moves)->chess, to, chess->board[to], -1);
+
(*moves)->chess.board[to] = promotion;
(*moves)->chess.board[from] = moonfish_empty;
- (*moves)->chess.score -= moonfish_table(from, chess->board[from]);
- (*moves)->chess.score += moonfish_table(to, promotion);
- (*moves)->chess.score -= moonfish_table(to, chess->board[to]);
(*moves)->chess.passing = 0;
(*moves)->chess.white ^= 1;
- if (from == 21 || to == 21) (*moves)->chess.white_ooo = 0;
- if (from == 28 || to == 28) (*moves)->chess.white_oo = 0;
- if (from == 91 || to == 91) (*moves)->chess.black_ooo = 0;
- if (from == 98 || to == 98) (*moves)->chess.black_oo = 0;
+ if (from == 21 || to == 21) (*moves)->chess.ooo[0] = 0;
+ if (from == 28 || to == 28) (*moves)->chess.oo[0] = 0;
+ if (from == 91 || to == 91) (*moves)->chess.ooo[1] = 0;
+ if (from == 98 || to == 98) (*moves)->chess.oo[1] = 0;
(*moves)++;
}
@@ -111,7 +53,7 @@
moonfish_force_promotion(chess, moves, from, to, chess->board[from]);
}
-static void moonfish_deltas(struct moonfish_chess *chess, struct moonfish_move **moves, unsigned char from, int *deltas, int n)
+static void moonfish_deltas(struct moonfish_chess *chess, struct moonfish_move **moves, unsigned char from, int *deltas, int count, int n)
{int i;
unsigned char to;
@@ -119,9 +61,9 @@
while (*deltas)
{to = from;
- for (i = 0 ; i < n ; i++)
+ for (i = 0 ; i < count ; i++)
{- to += *deltas;
+ to += *deltas * n;
if (chess->board[to] == moonfish_outside) break;
if (chess->board[to] / 16 == chess->board[from] / 16) break;
moonfish_force_move(chess, moves, from, to);
@@ -131,20 +73,52 @@
}
}
+int moonfish_moves(struct moonfish_chess *chess, struct moonfish_move *moves, unsigned char from);
+
+int moonfish_validate(struct moonfish_chess *chess)
+{+ int x, y;
+ struct moonfish_move moves[32];
+ 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 (chess->board[moves[i].to] % 16 == moonfish_king)
+ return 0;
+ }
+
+ return 1;
+}
+
+int moonfish_check(struct moonfish_chess *chess)
+{+ struct moonfish_chess other;
+
+ other = *chess;
+ other.passing = 0;
+ other.oo[0] = 0;
+ other.oo[1] = 0;
+ other.ooo[0] = 0;
+ other.ooo[1] = 0;
+ other.white ^= 1;
+ return moonfish_validate(&other) ^ 1;
+}
+
static char moonfish_attacked(struct moonfish_chess *chess, unsigned char from, unsigned char to)
{- int check;
unsigned char piece;
+ struct moonfish_chess other;
if (chess->white) piece = moonfish_white_king;
else piece = moonfish_black_king;
- chess->board[from] = moonfish_empty;
- chess->board[to] = piece;
- check = moonfish_check(chess);
- chess->board[from] = piece;
- chess->board[to] = moonfish_empty;
- return check;
+ other = *chess;
+ other.board[from] = moonfish_empty;
+ other.board[to] = piece;
+ return moonfish_check(&other);
}
static void moonfish_castle_low(struct moonfish_chess *chess, struct moonfish_move **moves, unsigned char from)
@@ -151,6 +125,8 @@
{unsigned char to;
+ if (!chess->ooo[1 - chess->white]) return;
+
to = from - 3;
while (to != from)
if (chess->board[to++] != moonfish_empty)
@@ -170,6 +146,8 @@
{unsigned char to;
+ if (!chess->oo[1 - chess->white]) return;
+
to = from + 2;
while (to != from)
if (chess->board[to--] != moonfish_empty)
@@ -185,20 +163,6 @@
moonfish_force_move(&(*moves)->chess, moves, from, from + 2);
}
-static void moonfish_move_king(struct moonfish_chess *chess, struct moonfish_move **moves, unsigned char from)
-{- if (chess->white)
- {- if (chess->white_oo) moonfish_castle_high(chess, moves, from);
- if (chess->white_ooo) moonfish_castle_low(chess, moves, from);
- }
- else
- {- if (chess->black_oo) moonfish_castle_high(chess, moves, from);
- if (chess->black_ooo) moonfish_castle_low(chess, moves, from);
- }
-}
-
static void moonfish_pawn_moves(struct moonfish_chess *chess, struct moonfish_move **moves, unsigned char from, unsigned char to)
{unsigned char color;
@@ -225,7 +189,7 @@
dy = chess->white ? 10 : -10;
moonfish_force_move(chess, moves, from, to);
- (*moves)[-1].chess.score -= moonfish_table(to - dy, chess->board[to - dy]);
+ moonfish_table(&(*moves)[-1].chess, to - dy, chess->board[to - dy], -1);
(*moves)[-1].chess.board[to - dy] = moonfish_empty;
return;
}
@@ -261,14 +225,14 @@
int moonfish_moves(struct moonfish_chess *chess, struct moonfish_move *moves, unsigned char from)
{ static int steps[] = {0, 1, 8, 8, 8, 1};- static int deltas[][9] =
+ static int deltas[][5] =
{ {0},- {21, 19, -19, -21, 12, 8, -8, -12, 0},- {11, 9, -9, -11, 0},- {10, -10, 1, -1, 0},- {10, -10, 1, -1, 11, 9, -9, -11, 0},- {10, -10, 1, -1, 11, 9, -9, -11, 0},+ {21, 19, 12, 8, 0},+ {11, 9, 0},+ {10, 1, 0},+ {10, 1, 11, 9, 0},+ {10, 1, 11, 9, 0},};
struct moonfish_move *moves0;
@@ -280,28 +244,22 @@
if (chess->white ? piece / 16 == 1 : piece / 16 == 2)
{- moonfish_deltas(chess, &moves, from, deltas[piece % 16 - 1], steps[piece % 16 - 1]);
+ moonfish_deltas(chess, &moves, from, deltas[piece % 16 - 1], steps[piece % 16 - 1], 1);
+ moonfish_deltas(chess, &moves, from, deltas[piece % 16 - 1], steps[piece % 16 - 1], -1);
if (piece % 16 == moonfish_pawn) moonfish_move_pawn(chess, &moves, from);
if (piece % 16 == moonfish_king)
{- moonfish_move_king(chess, &moves, from);
+ moonfish_castle_high(chess, &moves, from);
+ moonfish_castle_low(chess, &moves, from);
count = moves - moves0;
for (i = 0 ; i < count ; i++)
{- if (chess->white)
- {- moves0[i].chess.white_oo = 0;
- moves0[i].chess.white_ooo = 0;
- }
- else
- {- moves0[i].chess.black_oo = 0;
- moves0[i].chess.black_ooo = 0;
- }
+ moves0[i].chess.oo[1 - chess->white] = 0;
+ moves0[i].chess.ooo[1 - chess->white] = 0;
}
}
}
@@ -311,16 +269,16 @@
void moonfish_chess(struct moonfish_chess *chess)
{- char pieces[] = {moonfish_rook, moonfish_knight, moonfish_bishop, moonfish_queen, moonfish_king, moonfish_bishop, moonfish_knight, moonfish_rook};+ static unsigned char pieces[] = {moonfish_rook, moonfish_knight, moonfish_bishop, moonfish_queen, moonfish_king, moonfish_bishop, moonfish_knight, moonfish_rook};int x, y;
chess->white = 1;
- chess->white_oo = 1;
- chess->white_ooo = 1;
- chess->black_oo = 1;
- chess->black_ooo = 1;
- chess->score = 0;
+ chess->oo[0] = 1;
+ chess->oo[1] = 1;
+ chess->ooo[0] = 1;
+ chess->ooo[1] = 1;
chess->passing = 0;
+ chess->score = 0;
for (y = 0 ; y < 12 ; y++)
for (x = 0 ; x < 10 ; x++)
@@ -328,10 +286,10 @@
for (x = 0 ; x < 8 ; x++)
{- chess->board[(x + 1) + 20] = pieces[x] | 0x10;
- chess->board[(x + 1) + 90] = pieces[x] | 0x20;
- chess->board[(x + 1) + 30] = moonfish_white_pawn;
- chess->board[(x + 1) + 80] = moonfish_black_pawn;
+ chess->board[x + 21] = pieces[x] | 0x10;
+ chess->board[x + 91] = pieces[x] | 0x20;
+ chess->board[x + 31] = moonfish_white_pawn;
+ chess->board[x + 81] = moonfish_black_pawn;
for (y = 4 ; y < 8 ; y++)
chess->board[(x + 1) + y * 10] = moonfish_empty;
@@ -342,7 +300,7 @@
{int x0, y0;
int x1, y1;
- unsigned char piece, color;
+ unsigned char type;
unsigned char from, to;
int i, count;
struct moonfish_move moves[32];
@@ -359,35 +317,20 @@
x1 = name[2] - 'a';
y1 = name[3] - '1';
- piece = chess->board[(x0 + 1) + (y0 + 2) * 10];
- if (piece % 16 == moonfish_king && x0 == 4)
+ type = chess->board[(x0 + 1) + (y0 + 2) * 10] % 16;
+ if (type == moonfish_king && x0 == 4)
{if (x1 == 0) x1 = 2;
if (x1 == 7) x1 = 6;
}
- color = piece & 0xF0;
+ if (name[4] == 0) { }+ else if (name[4] == 'q') type = moonfish_queen;
+ else if (name[4] == 'r') type = moonfish_rook;
+ else if (name[4] == 'b') type = moonfish_bishop;
+ else if (name[4] == 'n') type = moonfish_knight;
+ else return 1;
- switch (name[4])
- {- default:
- return 1;
- case 0:
- break;
- case 'q':
- piece = color | moonfish_queen;
- break;
- case 'r':
- piece = color | moonfish_rook;
- break;
- case 'b':
- piece = color | moonfish_bishop;
- break;
- case 'n':
- piece = color | moonfish_knight;
- break;
- }
-
from = (x0 + 1) + (y0 + 2) * 10;
to = (x1 + 1) + (y1 + 2) * 10;
@@ -396,7 +339,7 @@
for (i = 0 ; i < count ; i++)
{if (moves[i].to != to) continue;
- if (moves[i].chess.board[to] != piece) continue;
+ if (moves[i].chess.board[to] % 16 != type) continue;
*move = moves[i];
return 0;
}
@@ -435,55 +378,6 @@
}
}
-int moonfish_validate(struct moonfish_chess *chess)
-{- int x, y;
- struct moonfish_move moves[32];
- 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 (chess->board[moves[i].to] % 16 == moonfish_king)
- return 0;
- }
-
- return 1;
-}
-
-int moonfish_check(struct moonfish_chess *chess)
-{- int valid;
- unsigned char passing;
- int white_oo, white_ooo;
- int black_oo, black_ooo;
-
- passing = chess->passing;
- white_oo = chess->white_oo;
- white_ooo = chess->white_ooo;
- black_oo = chess->black_oo;
- black_ooo = chess->black_ooo;
-
- chess->white_oo = 0;
- chess->white_ooo = 0;
- chess->black_oo = 0;
- chess->black_ooo = 0;
-
- chess->white ^= 1;
- valid = moonfish_validate(chess);
- chess->white ^= 1;
-
- chess->passing = passing;
- chess->white_oo = white_oo;
- chess->white_ooo = white_ooo;
- chess->black_oo = black_oo;
- chess->black_ooo = black_ooo;
-
- return valid ^ 1;
-}
-
#ifndef moonfish_mini
#include <string.h>
@@ -524,12 +418,12 @@
y = 0;
chess->white = 1;
- chess->white_oo = 0;
- chess->white_ooo = 0;
- chess->black_oo = 0;
- chess->black_ooo = 0;
- chess->score = 0;
+ chess->oo[0] = 0;
+ chess->oo[1] = 0;
+ chess->ooo[0] = 0;
+ chess->ooo[1] = 0;
chess->passing = 0;
+ chess->score = 0;
for (;;)
{@@ -566,9 +460,8 @@
if (ch == 'k') type = 6;
chess->board[(x + 1) + (9 - y) * 10] = type | color;
+ moonfish_table(chess, (x + 1) + (9 - y) * 10, type | color, 1);
- chess->score += moonfish_table((x + 1) + (9 - y) * 10, type | color);
-
x++;
}
@@ -582,10 +475,10 @@
if (ch == 0) return 0;
if (ch == ' ') break;
- if (ch == 'K') chess->white_oo = 1;
- if (ch == 'Q') chess->white_ooo = 1;
- if (ch == 'k') chess->black_oo = 1;
- if (ch == 'q') chess->black_ooo = 1;
+ if (ch == 'K') chess->oo[0] = 1;
+ if (ch == 'k') chess->oo[1] = 1;
+ if (ch == 'Q') chess->ooo[0] = 1;
+ if (ch == 'q') chess->ooo[1] = 1;
if (ch >= 'A' && ch <= 'H') return 1;
if (ch >= 'a' && ch <= 'h') return 1;
@@ -860,10 +753,10 @@
else *fen++ = 'b';
*fen++ = ' ';
- if (chess->white_oo) *fen++ = 'K';
- if (chess->white_ooo) *fen++ = 'Q';
- if (chess->black_oo) *fen++ = 'k';
- if (chess->black_ooo) *fen++ = 'q';
+ if (chess->oo[0]) *fen++ = 'K';
+ if (chess->ooo[0]) *fen++ = 'Q';
+ if (chess->oo[1]) *fen++ = 'k';
+ if (chess->ooo[1]) *fen++ = 'q';
if (fen[-1] == ' ') *fen++ = '-';
*fen++ = ' ';
--- a/extras/config.h
+++ /dev/null
@@ -1,15 +1,0 @@
-/* moonfish is licensed under the AGPL (v3 or later) */
-/* copyright 2024 zamfofex */
-
-#ifndef MOONFISH_TEXEL_TUNER_CONFIG
-#define MOONFISH_TEXEL_TUNER_CONFIG
-
-#include "moonfish.hh"
-
-using TuneEval = moonfish::MoonfishEval;
-constexpr int data_load_thread_count = 4;
-constexpr int thread_count = 4;
-constexpr static bool print_data_entries = false;
-constexpr static int data_load_print_interval = 10000;
-
-#endif
--- a/extras/moonfish.cc
+++ /dev/null
@@ -1,98 +1,0 @@
-/* moonfish is licensed under the AGPL (v3 or later) */
-/* copyright 2024 zamfofex */
-
-#include <math.h>
-#include <stdio.h>
-
-#include "moonfish.hh"
-
-extern "C"
-{-#include "../moonfish.h"
-}
-
-struct moonfish_trace
-{- int values[32 * 6][2];
-};
-
-parameters_t moonfish::MoonfishEval::get_initial_parameters(void)
-{- static int scores[6 * 32] = {0};- parameters_t parameters;
- get_initial_parameter_array(parameters, scores, 6 * 32);
- return parameters;
-}
-
-void moonfish::MoonfishEval::print_parameters(parameters_t parameters)
-{- int x, y, type;
- long int l;
-
- printf("static int moonfish_piece_square_scores[] =\n{\n");-
- for (type = 0 ; type < 6 ; type++)
- {- for (y = 0 ; y < 8 ; y++)
- {- printf("\t");- for (x = 0 ; x < 4 ; x++)
- {- l = lround(parameters[x + y * 4 + type * 32]);
- printf("%ld,", l);- if (x != 7) printf(" ");- }
- printf("\n");- }
- if (type != 5) printf("\n");- }
-
- printf("};\n");-}
-
-
-EvalResult moonfish::MoonfishEval::get_fen_eval_result(std::string fen)
-{- struct moonfish_chess chess;
- int x0, y0;
- int x, y;
- struct moonfish_trace trace = {0};- unsigned char type, color;
- unsigned char piece;
- EvalResult result;
-
- moonfish_chess(&chess);
- moonfish_from_fen(&chess, (char *) fen.c_str());
-
- for (y0 = 0 ; y0 < 8 ; y0++)
- for (x0 = 0 ; x0 < 8 ; x0++)
- {- x = x0;
- y = y0;
-
- piece = chess.board[(x + 1) + (y + 2) * 10];
- if (piece == moonfish_empty) continue;
-
- type = (piece % 16) - 1;
- color = (piece / 16) - 1;
-
- if (color == 0) y = 7 - y;
-
- if (x < 4) x = 3 - x;
- else x %= 4;
-
- trace.values[x + y * 4 + type * 32][color]++;
- }
-
- get_coefficient_array(result.coefficients, trace.values, 6 * 32);
- result.score = 0;
- result.endgame_scale = 0;
- return result;
-}
-
-EvalResult moonfish::MoonfishEval::get_external_eval_result(chess::Board board)
-{- (void) board;
- EvalResult result;
- return result;
-}
--- a/extras/moonfish.hh
+++ /dev/null
@@ -1,39 +1,0 @@
-/* moonfish is licensed under the AGPL (v3 or later) */
-/* copyright 2024 zamfofex */
-
-#ifndef MOONFISH_TEXEL_TUNER
-#define MOONFISH_TEXEL_TUNER
-
-#define TAPERED 0
-
-#include <string>
-
-#include "texel-tuner/src/base.h"
-#include "texel-tuner/src/external/chess.hpp"
-
-namespace moonfish
-{- class MoonfishEval
- {- public:
- constexpr static bool includes_additional_score = true;
- constexpr static bool supports_external_chess_eval = false;
- constexpr static bool retune_from_zero = true;
- constexpr static tune_t preferred_k = 2.1;
- constexpr static int32_t max_epoch = 5001;
- constexpr static bool enable_qsearch = false;
- constexpr static bool filter_in_check = false;
- constexpr static tune_t initial_learning_rate = 1;
- constexpr static int32_t learning_rate_drop_interval = 10000;
- constexpr static tune_t learning_rate_drop_ratio = 1;
- constexpr static bool print_data_entries = false;
- constexpr static int32_t data_load_print_interval = 10000;
-
- static parameters_t get_initial_parameters(void);
- static EvalResult get_fen_eval_result(std::string fen);
- static EvalResult get_external_eval_result(chess::Board board);
- static void print_parameters(parameters_t parameters);
- };
-}
-
-#endif
--- a/main.c
+++ b/main.c
@@ -12,7 +12,6 @@
{static char line[2048];
- struct moonfish_analysis *analysis;
char *arg;
struct moonfish_move move;
char name[6];
@@ -25,11 +24,10 @@
if (argc > 1)
{- if (argc > 0) fprintf(stderr, "usage: %s\n", argv[0]);
+ fprintf(stderr, "usage: %s\n", argv[0]);
return 1;
}
- analysis = moonfish_analysis(argv[0]);
moonfish_chess(&chess);
for (;;)
@@ -141,11 +139,11 @@
if (their_time < 0) their_time = 0;
if (depth >= 0)
- score = moonfish_best_move_depth(analysis, &move, depth);
+ score = moonfish_best_move_depth(&chess, &move, depth);
else if (time >= 0)
- score = moonfish_best_move_time(analysis, &move, time);
+ score = moonfish_best_move_time(&chess, &move, time);
else
- score = moonfish_best_move_clock(analysis, &move, our_time, their_time);
+ score = moonfish_best_move_clock(&chess, &move, our_time, their_time);
if (depth < 0) depth = 4;
printf("info depth %d ", depth);@@ -217,8 +215,6 @@
chess = move.chess;
}
}
-
- moonfish_new(analysis, &chess);
}
else if (!strcmp(arg, "uci"))
{@@ -240,8 +236,6 @@
fflush(stdout);
}
-
- free(analysis);
return 0;
}
--- a/makefile
+++ b/makefile
@@ -2,12 +2,10 @@
# copyright 2023, 2024 zamfofex
CFLAGS ?= -ansi -O3 -Wall -Wextra -Wpedantic
-CXXFLAGS ?= -std=c++20 -O3 -Wall -Wextra -Wpedantic
PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
cc := $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)
-cxx := $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS)
moonfish_cc := $(cc) -pthread -D_POSIX_C_SOURCE=199309L
tools_cc := $(cc) -pthread -D_POSIX_C_SOURCE=200809L
@@ -37,20 +35,8 @@
uci-ugi: $(ugi_src)
$(tools_cc) -o $@ $(filter %.c,$^)
-tuner: \
- extras/texel-tuner/src/main.cpp \
- extras/texel-tuner/src/tuner.cpp \
- extras/texel-tuner/src/threadpool.cpp \
- extras/texel-tuner/src/base.h \
- extras/texel-tuner/src/threadpool.h \
- extras/texel-tuner/src/tuner.h \
- extras/moonfish.cc \
- extras/moonfish.hh \
- extras/config.h \
- chess.c moonfish.h
- $(RM) extras/texel-tuner/src/config.h
- $(cc) -c chess.c
- $(cxx) -pthread -iquote extras -o $@ $(filter %.cc %.cpp,$^) chess.o
+learn: $(tools_src) tools/learn.c
+ $(tools_cc) -Dmoonfish_learn -o $@ $(filter %.c,$^)
clean:
git clean -fdx
--- a/mini.c
+++ b/mini.c
@@ -11,16 +11,12 @@
{static char line[2048];
- struct moonfish_analysis *analysis;
struct moonfish_move move;
char name[6];
int our_time, their_time, time;
- int score;
struct moonfish_chess chess;
char *arg;
- analysis = moonfish_analysis(NULL);
-
for (;;)
{fgets(line, sizeof line, stdin);
@@ -38,15 +34,7 @@
their_time = time;
}
- score = moonfish_best_move_clock(analysis, &move, our_time, their_time);
-
- printf("info depth 4 ");-
- if (score >= moonfish_omega || score <= -moonfish_omega)
- printf("score mate %d\n", moonfish_countdown(score));- else
- printf("score cp %d\n", score);-
+ moonfish_best_move_clock(&chess, &move, our_time, their_time);
moonfish_to_uci(&chess, &move, name);
printf("bestmove %s\n", name);}
@@ -59,13 +47,11 @@
arg = strtok(arg, " ");
- while ((arg = strtok(NULL, "\r\n\t ")) != NULL)
+ while (arg = strtok(NULL, "\n "))
{moonfish_from_uci(&chess, &move, arg);
chess = move.chess;
}
-
- moonfish_new(analysis, &chess);
}
else if (!strcmp(line, "uci"))
printf("uciok\n");@@ -76,6 +62,4 @@
fflush(stdout);
}
-
- return 0;
}
--- a/minify.sh
+++ b/minify.sh
@@ -5,15 +5,30 @@
set -e
-# for every C source file
+# for each C source file
cat moonfish.h chess.c search.c mini.c |
-# remove the '#' from system '#include'
-sed 's/^#\(include <\)/\1/g' |
+# replace 'unsigned char' with 'int'
+sed 's/\bunsigned char\b/int/g' |
-# remove top-level 'static'
+# remove 'signed' and 'unsigned'
+sed 's/\tsigned /\t/g' |
+sed 's/\tunsigned /\t/g' |
+
+# remove 'long'
+sed 's/\blong\b \?//g' |
+
+# remove top-level 'static', 'int' and 'void'
sed 's/^static\b//g' |
+sed 's/^int\b//g' |
+sed 's/^void\b//g' |
+#remove redundant 'int'
+sed 's/\bstatic int\b/static/g' |
+
+# remove the '#' from system '#include'
+sed 's/^#\(include <\)/\1/g' |
+
# preprocess the file, add '#' back to 'include'
# note: this materialises the whole file
gcc -E -Dinclude='#include' -Dmoonfish_mini - |
@@ -68,13 +83,13 @@
tee moonfish.c |
# and also compress it
-xz -9 -e > moonfish.c.xz
+xz -e9qFraw > moonfish.c.xz
-# also make it into a runnable program
+# finally, make it into an executable program
cat - moonfish.c.xz > moonfish.sh << END
#!/bin/sh
t=\`mktemp\`
-tail -n +5 "\$0"|xz -d|cc -march=native -O3 -o \$t -xc - -pthread
+gcc -O3 -o \$t -xc <(tail -n+5 "\$0"|unxz -Fraw)
(sleep 3;rm \$t)&exec \$t
END
chmod +x moonfish.sh
--- a/moonfish.h
+++ b/moonfish.h
@@ -52,43 +52,50 @@
/* the board is not just an 8 x 8 array because of an optisation that can be performed when generating moves */
-enum
-{- /* white pieces */
- moonfish_white_pawn = 0x11,
- moonfish_white_knight = 0x12,
- moonfish_white_bishop = 0x13,
- moonfish_white_rook = 0x14,
- moonfish_white_queen = 0x15,
- moonfish_white_king = 0x16,
-
- /* black pieces */
- moonfish_black_pawn = 0x21,
- moonfish_black_knight = 0x22,
- moonfish_black_bishop = 0x23,
- moonfish_black_rook = 0x24,
- moonfish_black_queen = 0x25,
- moonfish_black_king = 0x26,
-
- /* piece types (without colors) */
- moonfish_pawn = 1,
- moonfish_knight = 2,
- moonfish_bishop = 3,
- moonfish_rook = 4,
- moonfish_queen = 5,
- moonfish_king = 6,
-
- /* special values within the board representation */
- moonfish_outside = 0,
- moonfish_empty = 0xFF,
-
- /* constants for search */
- /* depth: the maximum depth considerable feasibly reachable (in practice, it's much lower!) */
- /* omega: high value (used as integral infinity) */
- moonfish_depth = 50,
- moonfish_omega = 5000000
-};
+/* white pieces */
+#define moonfish_white_pawn 0x11
+#define moonfish_white_knight 0x12
+#define moonfish_white_bishop 0x13
+#define moonfish_white_rook 0x14
+#define moonfish_white_queen 0x15
+#define moonfish_white_king 0x16
+
+/* black pieces */
+#define moonfish_black_pawn 0x21
+#define moonfish_black_knight 0x22
+#define moonfish_black_bishop 0x23
+#define moonfish_black_rook 0x24
+#define moonfish_black_queen 0x25
+#define moonfish_black_king 0x26
+
+/* piece types (without colors) */
+#define moonfish_pawn 1
+#define moonfish_knight 2
+#define moonfish_bishop 3
+#define moonfish_rook 4
+#define moonfish_queen 5
+#define moonfish_king 6
+
+/* special values within the board representation */
+#define moonfish_outside 0
+#define moonfish_empty 0xFF
+
+/* constants for search */
+/* depth: the maximum depth considerable feasibly reachable (in practice, it's much lower!) */
+/* omega: high value (used as integral infinity) */
+#define moonfish_depth 50
+#define moonfish_omega 5000000
+
+/* size of the PST */
+#define moonfish_size 192
+/* for tuning the PST */
+#ifdef moonfish_learn
+#define moonfish_t double
+#else
+#define moonfish_t long int
+#endif
+
/* represents a chess position */
struct moonfish_chess
{@@ -95,13 +102,12 @@
/* 10 x 12 array board representation */
unsigned char board[120];
- /* bitfield booleans representing castling rights */
- unsigned int white_oo:1, white_ooo:1;
- unsigned int black_oo:1, black_ooo:1;
-
/* PST score for the position */
- int score;
+ moonfish_t score;
+ /* booleans representing castling rights */
+ unsigned char oo[2], ooo[2];
+
/* square index of a pawn that may be captured via e.p. */
/* or zero if there is no such pawn */
unsigned char passing;
@@ -122,11 +128,11 @@
unsigned char from, to;
};
-/* opaque analysis struct */
-/* a value may be created (with "malloc") by using the functions below, and then freed by using "free" */
-/* this contains information that may be used during analysis that may be kept across evaluations of positions */
-struct moonfish_analysis;
+#ifndef moonfish_mini
+/* PST */
+extern moonfish_t moonfish_values[];
+
/* initialises the position and sets up the initial position */
/* note: this must be called *first* even if you want to use "moonfish_from_fen" */
void moonfish_chess(struct moonfish_chess *chess);
@@ -144,29 +150,19 @@
/* the move is stored in the "move" pointer, and the score for the position is returned */
/* the move found is the best for the player whose turn it is on the given position */
/* likewise, the score returned is from the perspective of the player whose turn it is */
-int moonfish_best_move_time(struct moonfish_analysis *analysis, struct moonfish_move *move, long int time);
+int moonfish_best_move_time(struct moonfish_chess *chess, struct moonfish_move *move, long int time);
/* same as above, but tries to optimises the time spent searching for the given time left on each player's clock */
-int moonfish_best_move_clock(struct moonfish_analysis *analysis, struct moonfish_move *move, long int our_time, long int their_time);
+int moonfish_best_move_clock(struct moonfish_chess *chess, struct moonfish_move *move, long int our_time, long int their_time);
+/* tries to find the best move on the given position with a given depth */
+/* similar to "moonfish_best_move_time" and "moonfish_best_move_clock" */
+int moonfish_best_move_depth(struct moonfish_chess *chess, struct moonfish_move *move, int depth);
+
/* if a score is too large (i.e. "score >= moonfish_omega"), it will instead represent a "checkmate in X" evaluation */
/* this function will obtain such "X" from the given score in that case */
int moonfish_countdown(int score);
-/* creates an analysis, which may be used to analyse many positions */
-/* note: in the future, the analysis might hold information across analyses (such as a transposition table) */
-/* but currently, that is not implemented */
-/* the analysis is created using "malloc", so don't forget to call "free" on it once you don't need it anymore */
-/* the analysis will be set up for analysing the initial position (but you may change this, see below) */
-/* the give "argv0" is used to report errors if necessary */
-/* a reference to "argv0" is kept, so it should be available for as long as the analysis is being used */
-/* on the case of an error (while creating the analysis, or even just using it), the program will be stopped with "exit" */
-struct moonfish_analysis *moonfish_analysis(char *argv0);
-
-/* sets up an existing analysis (created with the function above) to analyse the given position */
-/* a reference to the given position pointer will not be kept */
-void moonfish_new(struct moonfish_analysis *analysis, struct moonfish_chess *chess);
-
/* creates a move from UCI notation */
/* the move is stored in "move" */
/* on success, the parser will return 0, on failure, it will return 1 (and the move is unusable) */
@@ -185,12 +181,6 @@
/* returns whether player to play is in check (i.e. whether the current player's king is attacked on the given position) */
int moonfish_check(struct moonfish_chess *chess);
-
-#ifndef moonfish_mini
-
-/* tries to find the best move on the position with a given depth */
-/* similar to "moonfish_best_move_time" and "moonfish_best_move_clock" */
-int moonfish_best_move_depth(struct moonfish_analysis *analysis, struct moonfish_move *move, int depth);
/* uses the position from the given FEN, mutating the given position */
/* returns 0 if the FEN could be parsed */
--- a/rename.sh
+++ b/rename.sh
@@ -9,8 +9,8 @@
alphabet2=("${alphabet[@]}")declare -A names
-functions="main printf fprintf sscanf fgets fflush stdin stdout stderr strcmp strncmp strcpy strtok strstr strchr malloc realloc free exit errno clock_gettime timespec tv_sec tv_nsec pthread_create pthread_join pthread_t typedef moonfish_type_t"
-keywords="do while for if else switch case break continue return static struct enum unsigned signed long short int char void sizeof $functions"
+functions="main fopen fread printf fprintf sscanf fgets fflush stdin stdout stderr strcmp strncmp strcpy strtok strstr strchr malloc realloc free exit errno clock_gettime timespec tv_sec tv_nsec pthread_create pthread_join pthread_t typedef moonfish_type_t"
+keywords="do while for if else switch case break continue return extern static struct enum unsigned signed long short int char void sizeof $functions"
while read -r name
do
@@ -29,9 +29,7 @@
short="${names["$name"]}"if [[ "$short" = "" ]]
then
- if [[ "$name" = moonfish ]]
- then short=F
- elif [[ "$name" =~ ^moonfish ]]
+ if [[ "$name" =~ ^moonfish ]]
then
short="F${alphabet[0]}" alphabet=("${alphabet[@]:1}")--- a/search.c
+++ b/search.c
@@ -38,7 +38,7 @@
#else
#include <pthread.h>
-typedef void *moonfish_result_t;
+#define moonfish_result_t void *
#define moonfish_value NULL
#endif
@@ -56,7 +56,6 @@
struct moonfish_analysis
{- char *argv0;
struct moonfish_chess chess;
struct moonfish_info info[256];
int score;
@@ -66,15 +65,14 @@
#ifdef _WIN32
-static long int moonfish_clock(struct moonfish_analysis *analysis)
+static long int moonfish_clock(void)
{- (void) analysis;
return GetTickCount();
}
#else
-static long int moonfish_clock(struct moonfish_analysis *analysis)
+static long int moonfish_clock(void)
{struct timespec ts;
@@ -83,7 +81,7 @@
#else
if (clock_gettime(CLOCK_MONOTONIC, &ts))
{- perror(analysis->argv0);
+ perror(NULL);
exit(1);
}
#endif
@@ -93,35 +91,6 @@
#endif
-struct moonfish_analysis *moonfish_analysis(char *argv0)
-{- struct moonfish_analysis *analysis;
- struct moonfish_chess chess;
-
- analysis = malloc(sizeof *analysis);
-#ifndef moonfish_mini
- if (analysis == NULL)
- {- perror(argv0);
- exit(1);
- }
-#endif
-
- analysis->argv0 = argv0;
-
- moonfish_chess(&chess);
- moonfish_new(analysis, &chess);
-
- return analysis;
-}
-
-void moonfish_new(struct moonfish_analysis *analysis, struct moonfish_chess *chess)
-{- analysis->chess = *chess;
- analysis->depth = 1;
- analysis->time = -1;
-}
-
static int moonfish_search(struct moonfish_info *info, struct moonfish_chess *chess, struct moonfish_move *moves, int alpha, int beta, int depth, long int t0, long int time)
{int score;
@@ -142,7 +111,7 @@
if (score >= beta) return beta;
if (score > alpha) alpha = score;
}
- else if (info->analysis->time >= 0 && time < 0)
+ else if (info->analysis->time >= 0 && time < 5)
{depth = 0;
}
@@ -164,7 +133,7 @@
if (moves[i].chess.board[moves[i].to] == chess->board[moves[i].from])
continue;
- t1 = moonfish_clock(info->analysis);
+ t1 = moonfish_clock();
c = time * i / count - t1 + t0;
score = -moonfish_search(info, &moves[i].chess, moves + count, -beta, -alpha, depth - 1, t1, time / count + c);
@@ -176,27 +145,29 @@
return alpha;
}
+#ifndef moonfish_mini
+
int moonfish_countdown(int score)
{- score /= -moonfish_omega;
- if (score < 0) score += moonfish_depth + 1;
- else score -= moonfish_depth;
+ score /= moonfish_omega;
+ if (score < 0) score -= moonfish_depth + 1;
+ else score += moonfish_depth;
return score / 2;
}
+#endif
+
static moonfish_result_t moonfish_start_search(void *data)
{struct moonfish_info *info;
- long int time, t0;
- int depth;
info = data;
+ info->score = -moonfish_search(
+ info, &info->move.chess, info->moves,
+ -100 * moonfish_omega, 100 * moonfish_omega,
+ info->analysis->depth, moonfish_clock(), info->analysis->time
+ );
- depth = info->analysis->depth;
- t0 = moonfish_clock(info->analysis);
- time = info->analysis->time;
-
- info->score = -moonfish_search(info, &info->move.chess, info->moves, -100 * moonfish_omega, 100 * moonfish_omega, depth, t0, time);
return moonfish_value;
}
@@ -246,7 +217,7 @@
#ifndef moonfish_mini
if (result)
{- fprintf(stderr, "%s: %s\n", analysis->argv0, strerror(result));
+ fprintf(stderr, "%s\n", strerror(result));
exit(1);
}
#endif
@@ -263,7 +234,7 @@
#ifndef moonfish_mini
if (result)
{- fprintf(stderr, "%s: %s\n", analysis->argv0, strerror(result));
+ fprintf(stderr, "%s\n", strerror(result));
exit(1);
}
#endif
@@ -278,31 +249,38 @@
#ifndef moonfish_mini
-int moonfish_best_move_depth(struct moonfish_analysis *analysis, struct moonfish_move *best_move, int depth)
+int moonfish_best_move_depth(struct moonfish_chess *chess, struct moonfish_move *best_move, int depth)
{- analysis->depth = depth;
- analysis->time = -1;
- moonfish_iteration(analysis, best_move);
- return analysis->score;
+ static struct moonfish_analysis analysis;
+
+ analysis.chess = *chess;
+ analysis.depth = depth;
+ analysis.time = -1;
+ moonfish_iteration(&analysis, best_move);
+ return analysis.score;
}
#endif
-int moonfish_best_move_time(struct moonfish_analysis *analysis, struct moonfish_move *best_move, long int time)
+int moonfish_best_move_time(struct moonfish_chess *chess, struct moonfish_move *best_move, long int time)
{+ static struct moonfish_analysis analysis;
+
+ analysis.chess = *chess;
time -= 125;
if (time < 10) time = 10;
- analysis->depth = 16;
- analysis->time = time;
- moonfish_iteration(analysis, best_move);
- return analysis->score;
+ analysis.depth = 16;
+ analysis.time = time;
+ moonfish_iteration(&analysis, best_move);
+ return analysis.score;
}
-int moonfish_best_move_clock(struct moonfish_analysis *analysis, struct moonfish_move *best_move, long int our_time, long int their_time)
+int moonfish_best_move_clock(struct moonfish_chess *chess, struct moonfish_move *best_move, long int our_time, long int their_time)
{long int time0, time1;
+
time0 = our_time / 16;
time1 = our_time - time0 - their_time * 7 / 8;
if (time1 < 0) time1 = 0;
- return moonfish_best_move_time(analysis, best_move, time0 + time1);
+ return moonfish_best_move_time(chess, best_move, time0 + time1);
}
--- /dev/null
+++ b/tools/learn.c
@@ -1,0 +1,153 @@
+/* moonfish is licensed under the AGPL (v3 or later) */
+/* copyright 2024 zamfofex */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../moonfish.h"
+#include "tools.h"
+
+static double moonfish_next_line(char *argv0, char *line, FILE *file)
+{+ char *arg, *end;
+ double score;
+
+ errno = 0;
+ if (fgets(line, 2048, file) == NULL)
+ {+ if (errno)
+ {+ perror(argv0);
+ exit(1);
+ }
+
+ errno = 0;
+ rewind(file);
+ if (errno)
+ {+ perror(argv0);
+ exit(1);
+ }
+ }
+
+ arg = strrchr(line, ' ');
+ if (arg == NULL)
+ {+ fprintf(stderr, "%s: improper FEN line\n", argv0);
+ exit(1);
+ }
+
+ errno = 0;
+ score = strtod(arg + 1, &end);
+ if (errno != 0 || (*end != 0 && *end != '\n') || score > 10000 || score < -10000)
+ {+ fprintf(stderr, "%s: unexpected score\n", argv0);
+ exit(1);
+ }
+
+ return score;
+}
+
+static double moonfish_gradient(double *gradient, double score0, char *fen)
+{+ int i;
+ double prev;
+ double score, error;
+ struct moonfish_chess chess;
+
+ moonfish_chess(&chess);
+ moonfish_from_fen(&chess, fen);
+ score = chess.score;
+ error = score - score0;
+
+ for (i = 0 ; i < moonfish_size ; i++)
+ {+ prev = moonfish_values[i];
+ moonfish_values[i] += 1.0 / 256 / 256;
+ moonfish_from_fen(&chess, fen);
+ gradient[i] += (chess.score - score) * 256 * 256 * error;
+ moonfish_values[i] = prev;
+ }
+
+ if (error < 0) error *= -1;
+ return error;
+}
+
+static double moonfish_step(char *argv0, FILE *file, double *gradient)
+{+ static char line[2048];
+
+ int i;
+ double score;
+ double error;
+
+ error = 0;
+
+ for (i = 0 ; i < moonfish_size ; i++) gradient[i] = 0;
+
+ for (i = 0 ; i < 2048 ; i++)
+ {+ score = moonfish_next_line(argv0, line, file);
+ error += moonfish_gradient(gradient, score, line);
+ }
+
+ for (i = 0 ; i < moonfish_size ; i++)
+ moonfish_values[i] -= gradient[i] / 2048;
+
+ return error;
+}
+
+int main(int argc, char **argv)
+{+ static double gradient[moonfish_size];
+
+ FILE *file;
+ int i;
+ double error;
+ int iteration;
+
+ if (argc != 2)
+ {+ if (argc > 0) fprintf(stderr, "usage: %s <file-name>\n", argv[0]);
+ return 1;
+ }
+
+ file = fopen(argv[1], "r");
+ if (file == NULL)
+ {+ perror(argv[0]);
+ return 1;
+ }
+
+ errno = 0;
+ rewind(file);
+ if (errno)
+ {+ perror(argv[0]);
+ return 1;
+ }
+
+ iteration = 0;
+
+ for (;;)
+ {+ if (iteration++ > 0x1000) return 0;
+
+ error = moonfish_step(argv[0], file, gradient);
+
+ printf("\n");+ for (i = 0 ; i < moonfish_size ; i++)
+ printf("%.0f,", moonfish_values[i]);+ printf("\n");+
+ printf("iteration: %d\n", iteration);+ printf("current error: ");+ if (error > 10000 * 1000)
+ printf("%.0fM\n", error / 1000 / 1000);+ else if (error > 10000)
+ printf("%.0fK\n", error / 1000);+ else
+ printf("%.0f\n", error);+ }
+}
--- a/tools/lichess.c
+++ b/tools/lichess.c
@@ -400,19 +400,19 @@
invalid = moonfish_from_fen(&chess, fen->valuestring);
if (!invalid)
- if (chess.white_oo || chess.white_ooo)
+ if (chess.oo[0] || chess.ooo[0])
if (chess.board[25] != moonfish_white_king)
invalid = 1;
if (!invalid)
- if (chess.black_oo || chess.black_ooo)
+ if (chess.oo[1] || chess.ooo[1])
if (chess.board[95] != moonfish_black_king)
invalid = 1;
- if (!invalid && chess.white_ooo && chess.board[21] != moonfish_white_rook) invalid = 1;
- if (!invalid && chess.white_oo && chess.board[28] != moonfish_white_rook) invalid = 1;
- if (!invalid && chess.black_ooo && chess.board[91] != moonfish_black_rook) invalid = 1;
- if (!invalid && chess.black_oo && chess.board[98] != moonfish_black_rook) invalid = 1;
+ if (!invalid && chess.oo[0] && chess.board[28] != moonfish_white_rook) invalid = 1;
+ if (!invalid && chess.oo[1] && chess.board[98] != moonfish_black_rook) invalid = 1;
+ if (!invalid && chess.ooo[0] && chess.board[21] != moonfish_white_rook) invalid = 1;
+ if (!invalid && chess.ooo[1] && chess.board[91] != moonfish_black_rook) invalid = 1;
if (invalid)
{--
⑨