shithub: moonfish

Download patch

ref: fbfe92f5e4eab6b340c56403b9bf15d26323abcf
parent: e5ea84bb37694b5474fbf6073cc5852a14d68f8b
author: zamfofex <zamfofex@twdb.moe>
date: Wed Oct 18 21:59:44 EDT 2023

replace NNUE with HCE (PST)

--- a/.gitignore
+++ b/.gitignore
@@ -3,11 +3,8 @@
 !/README.md
 !/makefile
 !/.build.yml
-!/*.c
 !/moonfish.h
-!/convert.py
+!/*.c
 !/tools
 !/tools/tools.h
 !/tools/*.c
-!/net
-!/net/*.c
--- a/chess.c
+++ b/chess.c
@@ -1,5 +1,64 @@
 #include "moonfish.h"
 
+static int moonfish_piece_scores[] = {100, 320, 330, 500, 900, 599900};
+
+static signed char moonfish_piece_square_scores[] =
+{
+	0, 0, 0, 0,
+	50, 50, 50, 50,
+	30, 20, 10, 10,
+	25, 10, 5, 5,
+	20, 0, 0, 0,
+	0, -10, -5, 5,
+	-20, 10, 10, 5,
+	0, 0, 0, 0,
+	
+	-30, -30, -40, -50,
+	5, 0, -20, -40,
+	15, 10, 5, -30,
+	20, 15, 0, -30,
+	20, 15, 0, -30,
+	15, 10, 5, -30,
+	5, 0, -20, -40,
+	-30, -30, -40, -50,
+	
+	-10, -10, -10, -20,
+	0, 0, 0, -10,
+	10, 5, 0, -10,
+	10, 5, 5, -10,
+	10, 10, 0, -10,
+	10, 10, 10, -10,
+	0, 0, 5, -10,
+	-10, -10, -10, -20,
+	
+	0, 0, 0, 0,
+	10, 10, 10, 5,
+	0, 0, 0, -5,
+	0, 0, 0, -5,
+	0, 0, 0, -5,
+	0, 0, 0, -5,
+	0, 0, 0, -5,
+	5, 0, 0, 0,
+	
+	-5, -10, -10, -20,
+	0, 0, 0, -10,
+	5, 5, 0, -10,
+	5, 5, 0, -5,
+	5, 5, 0, -5,
+	5, 5, 0, -10,
+	0, 0, 0, -10,
+	-5, -10, -10, -20,
+	
+	-50, -40, -40, -30,
+	-50, -40, -40, -30,
+	-50, -40, -40, -30,
+	-50, -40, -40, -30,
+	-40, -30, -30, -20,
+	-20, -20, -20, -10,
+	0, 0, 20, 20,
+	0, 10, 30, 20,
+};
+
 static struct moonfish_move *moonfish_create_move(struct moonfish_chess *chess, struct moonfish_move **moves, unsigned char from, unsigned char to)
 {
 	(*moves)->from = from;
@@ -8,6 +67,7 @@
 	(*moves)->promotion = chess->board[from];
 	(*moves)->captured = chess->board[to];
 	(*moves)->castle = chess->castle;
+	(*moves)->score = chess->score;
 	return (*moves)++;
 }
 
@@ -225,6 +285,7 @@
 	moonfish_flip_vertically(chess);
 	
 	chess->white ^= 1;
+	chess->score *= -1;
 	
 	for (y = 0 ; y < 8 ; y++)
 	for (x = 0 ; x < 8 ; x++)
@@ -234,10 +295,39 @@
 	}
 }
 
+static int moonfish_table(int from, unsigned char piece)
+{
+	int x, y;
+	unsigned char type, color;
+	int score;
+	
+	if (piece == moonfish_empty) return 0;
+	
+	x = from % 10 - 1;
+	y = from / 10 - 2;
+	
+	type = (piece & 0xF) - 1;
+	color = (piece >> 4) - 1;
+	
+	if (color == 0) y = 7 - y;
+	
+	if (x < 4) x = 4 - x;
+	else x %= 4;
+	
+	score = moonfish_piece_scores[type] + moonfish_piece_square_scores[x + y * 4 + type * 20];
+	if (color != 0) score *= -1;
+	
+	return score;
+}
+
 void moonfish_play(struct moonfish_chess *chess, struct moonfish_move *move)
 {
 	int x0, x1;
 	
+	chess->score -= moonfish_table(move->from, move->piece);
+	chess->score += moonfish_table(move->to, move->piece);
+	chess->score -= moonfish_table(move->to, move->captured);
+	
 	chess->board[move->from] = moonfish_empty;
 	chess->board[move->to] = move->promotion;
 	
@@ -244,7 +334,10 @@
 	if (move->piece == moonfish_our_pawn)
 	if ((move->to - move->from) % 10)
 	if (move->captured == moonfish_empty)
+	{
+		chess->score -= moonfish_table(move->to - 10, moonfish_their_pawn);
 		chess->board[move->to - 10] = moonfish_empty;
+	}
 	
 	if (move->piece == moonfish_our_king)
 	{
@@ -253,7 +346,13 @@
 		if (move->from == 24 && move->to == 26) x0 = 8, x1 = 5;
 		if (move->from == 25 && move->to == 27) x0 = 8, x1 = 6;
 		if (move->from == 25 && move->to == 23) x0 = 1, x1 = 4;
-		if (x0) chess->board[x0 + 20] = moonfish_empty, chess->board[x1 + 20] = moonfish_our_rook;
+		if (x0)
+		{
+			chess->score -= moonfish_table(x0 + 20, moonfish_our_rook);
+			chess->score += moonfish_table(x1 + 20, moonfish_our_rook);
+			chess->board[x0 + 20] = moonfish_empty;
+			chess->board[x1 + 20] = moonfish_our_rook;
+		}
 		
 		if (chess->white)
 		{
@@ -307,6 +406,7 @@
 	chess->board[move->from] = move->piece;
 	chess->board[move->to] = move->captured;
 	chess->castle = move->castle;
+	chess->score = move->score;
 	
 	if (move->piece == moonfish_our_king)
 	{
@@ -359,6 +459,8 @@
 	move->piece = chess->board[move->from];
 	move->captured = chess->board[move->to];
 	move->promotion = move->piece;
+	move->castle = chess->castle;
+	move->score = chess->score;
 	
 	if (name[4] == 'q') move->promotion = moonfish_our_queen;
 	if (name[4] == 'r') move->promotion = moonfish_our_rook;
@@ -423,6 +525,7 @@
 	chess->castle.white_ooo = 0;
 	chess->castle.black_oo = 0;
 	chess->castle.black_ooo = 0;
+	chess->score = 0;
 	
 	for (;;)
 	{
@@ -459,6 +562,8 @@
 		if (ch == 'k') type = 6;
 		
 		chess->board[(x + 1) + (9 - y) * 10] = type | color;
+		
+		chess->score += moonfish_table((x + 1) + (9 - y) * 10, type | color);
 		
 		x++;
 	}
--- a/convert.py
+++ /dev/null
@@ -1,22 +1,0 @@
-import pickle, sys
-
-if len(sys.argv) != 2:
-   print("usage: python3 " + sys.argv[0] + " <file-name>", file = sys.stderr)
-   exit(1)
-
-input_name = sys.argv[1]
-output_name = sys.argv[1].removesuffix(".pickle") + ".moon"
-
-model = pickle.load(open(input_name, "rb"))
-
-file = open(output_name, "wb")
-
-file.write(b"\x00Lun")
-file.write(model["ars"][0])
-file.write(model["ars"][1])
-file.write(model["ars"][3])
-file.write(model["ars"][4])
-file.write(model["ars"][5])
-file.write(bytearray([int(model["scale"] * 256)]))
-
-file.close()
--- a/main.c
+++ b/main.c
@@ -1,6 +1,7 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>
+#include <stdio.h>
 
 #include "moonfish.h"
 
@@ -7,7 +8,6 @@
 int main(int argc, char **argv)
 {
 	static char line[2048];
-	FILE *file;
 	struct moonfish *ctx;
 	char *arg;
 	struct moonfish_move move;
@@ -14,31 +14,12 @@
 	char name[6];
 	int time;
 	
-	if (argc < 1) return 1;
-	
-#ifdef MOONFISH_INBUILT_NET
-	
-	if (argc > 2)
+	if (argc > 1)
 	{
-		fprintf(stderr, "usage: %s [<file-name>]\n", argv[0]);
+		if (argc > 0) fprintf(stderr, "usage: %s\n", argv[0]);
 		return 1;
 	}
 	
-	if (argc >= 2) file = fopen(argv[1], "rb");
-	else file = fmemopen(moonfish_network, 1139, "rb");
-	
-#else
-	
-	if (argc != 2)
-	{
-		fprintf(stderr, "usage: %s <file-name>\n", argv[0]);
-		return 1;
-	}
-	
-	file = fopen(argv[1], "rb");
-	
-#endif
-	
 	ctx = malloc(sizeof *ctx);
 	if (ctx == NULL)
 	{
@@ -45,23 +26,6 @@
 		perror(argv[0]);
 		return 1;
 	}
-	
-	if (file == NULL)
-	{
-		perror(argv[0]);
-		free(ctx);
-		return 1;
-	}
-	
-	if (moonfish_nnue(&ctx->nnue, file))
-	{
-		fprintf(stderr, "%s: could not parse network\n", argv[0]);
-		fclose(file);
-		free(ctx);
-		return 1;
-	}
-	
-	fclose(file);
 	
 	printf("   (moonfish by zamfofex)\n");
 	printf("   (inspired by sunfish by tahle)\n");
--- a/makefile
+++ b/makefile
@@ -11,23 +11,8 @@
 
 all: moonfish play lichess analyse
 
-ifeq ($(inbuilt_network),yes)
-
-src += net/tanh.c tanh.o
-moonfish_cc += -D_POSIX_C_SOURCE=200809L -DMOONFISH_INBUILT_NET
-
-tanh.o: tanh.moon
-	$(LD) -r -b binary -o tanh.o tanh.moon
-
-tanh.moon: tanh.pickle
-	python3 convert.py tanh.pickle
-
-endif
-
 ifneq ($(has_pthread),no)
-
 moonfish_cc += -DMOONFISH_HAS_PTHREAD -pthread
-
 endif
 
 moonfish: moonfish.h $(src)
@@ -43,4 +28,4 @@
 	$(tools_cc) -o analyse tools/analyse.c tools/utils.c chess.c
 
 clean:
-	$(RM) moonfish play lichess analyse tanh.moon tanh.o
+	$(RM) moonfish play lichess analyse
--- a/math.c
+++ /dev/null
@@ -1,35 +1,0 @@
-#include "moonfish.h"
-
-/*
-our approximation:
-tanh(x) ~ (x**5/945 + x**3/9 + x)/(x**4/63 + (4 * x**2)/9 + 1)
-*/
-
-int moonfish_tanh(int x)
-{
-	long int x5, x4, x3, x2, x1, r;
-	
-	x5 = 1, x4 = 1, x3 = 1, x2 = 1, x1 = 1;
-	
-	x5 *= x; x5 *= x; x5 *= x; x5 *= x; x5 *= x;
-	x4 *= x; x4 *= x; x4 *= x; x4 *= x;
-	x3 *= x; x3 *= x; x3 *= x;
-	x2 *= x; x2 *= x;
-	x1 *= x;
-	
-	x5 /= 945;
-	x4 /= 63;
-	x3 /= 9;
-	x2 *= 4;
-	x2 /= 9;
-	x1 *= 127;
-	
-	x5 /= 127 * 127 * 127;
-	x4 /= 127 * 127 * 127;
-	x3 /= 127;
-	x2 /= 127;
-	
-	r = (x5 + x3 + x1) / (x4 + x2 + 127);
-	if (r > 127) return 127;
-	return r;
-}
--- a/moonfish.h
+++ b/moonfish.h
@@ -1,12 +1,6 @@
 #ifndef MOONFISH
 #define MOONFISH
 
-#include <stdio.h>
-
-#ifdef MOONFISH_HAS_PTHREAD
-#include <pthread.h>
-#endif
-
 enum
 {
 	moonfish_our_pawn = 0x11,
@@ -29,15 +23,6 @@
 	moonfish_omega = 5000000
 };
 
-struct moonfish_nnue
-{
-	int values0[6][64][10];
-	int values[2][6][64][10];
-	signed char pst0[64 * 6], pst1[10 * 6 * 6], pst3[10 * 10 * 2];
-	signed char layer1[180], layer2[10];
-	signed char scale;
-};
-
 struct moonfish_castle
 {
 	unsigned int white_oo:1, white_ooo:1;
@@ -49,11 +34,11 @@
 	unsigned char board[120];
 	unsigned char white;
 	struct moonfish_castle castle;
+	int score;
 };
 
 struct moonfish
 {
-	struct moonfish_nnue nnue;
 	struct moonfish_chess chess;
 	char *argv0;
 };
@@ -65,10 +50,9 @@
 	unsigned char promotion;
 	unsigned char captured;
 	struct moonfish_castle castle;
+	int score;
 };
 
-int moonfish_nnue(struct moonfish_nnue *nnue, FILE *file);
-
 void moonfish_chess(struct moonfish_chess *chess);
 void moonfish_fen(struct moonfish_chess *chess, char *fen);
 
@@ -77,8 +61,6 @@
 void moonfish_play(struct moonfish_chess *chess, struct moonfish_move *move);
 void moonfish_unplay(struct moonfish_chess *chess, struct moonfish_move *move);
 
-int moonfish_tanh(int value);
-
 int moonfish_best_move(struct moonfish *ctx, struct moonfish_move *move, int time);
 
 void moonfish_from_uci(struct moonfish_chess *chess, struct moonfish_move *move, char *name);
@@ -86,7 +68,5 @@
 
 int moonfish_validate(struct moonfish_chess *chess);
 int moonfish_check(struct moonfish_chess *chess);
-
-extern char *moonfish_network;
 
 #endif
--- a/net/tanh.c
+++ /dev/null
@@ -1,6 +1,0 @@
-#include <stdlib.h>
-
-#include "../moonfish.h"
-
-extern char _binary_tanh_moon_start[];
-char *moonfish_network = _binary_tanh_moon_start;
--- a/nnue.c
+++ /dev/null
@@ -1,79 +1,0 @@
-#include "moonfish.h"
-
-static int moonfish_read_array(signed char *array, unsigned int length, FILE *file)
-{
-	unsigned int i;
-	int ch;
-	
-	for (i = 0 ; i < length ; i++)
-	{
-		ch = fgetc(file);
-		if (ch == EOF) return 1;
-		array[i] = ch;
-	}
-	
-	return 0;
-}
-
-static int moonfish_read_nnue(struct moonfish_nnue *nnue, FILE *file)
-{
-	int ch;
-	unsigned int i, j;
-	signed char v;
-	
-	if (fgetc(file) != 0) return 1;
-	if (fgetc(file) != 'L') return 1;
-	if (fgetc(file) != 'u') return 1;
-	if (fgetc(file) != 'n') return 1;
-	if (moonfish_read_array(nnue->pst0, sizeof nnue->pst0, file)) return 1;
-	if (moonfish_read_array(nnue->pst1, sizeof nnue->pst1, file)) return 1;
-	if (moonfish_read_array(nnue->pst3, sizeof nnue->pst3, file)) return 1;
-	if (moonfish_read_array(nnue->layer1, sizeof nnue->layer1, file)) return 1;
-	if (moonfish_read_array(nnue->layer2, sizeof nnue->layer2, file)) return 1;
-	
-	for (i = 0 ; i < 4 ; i++)
-	for (j = 0 ; j < 6 * 8 ; j++)
-	{
-		v = nnue->pst0[i * 6 * 8 + j];
-		nnue->pst0[i * 6 * 8 + j] = nnue->pst0[(7 - i) * 6 * 8 + j];
-		nnue->pst0[(7 - i) * 6 * 8 + j] = v;
-	}
-	
-	ch = fgetc(file);
-	if (ch == EOF) return 1;
-	nnue->scale = ch;
-	
-	if (fgetc(file) != EOF) return 1;
-	
-	return 0;
-}
-
-int moonfish_nnue(struct moonfish_nnue *nnue, FILE *file)
-{
-	int p, s, d, o, c, value;
-	
-	if (moonfish_read_nnue(nnue, file)) return 1;
-	
-	for (p = 0 ; p < 6 ; p++)
-	for (s = 0 ; s < 64 ; s++)
-	for (o = 0 ; o < 10 ; o++)
-	{
-		value = 0;
-		for (d = 0 ; d < 6 ; d++)
-			value += nnue->pst0[s * 6 + d] * nnue->pst1[o * 6 * 6 + d * 6 + p];
-		nnue->values0[p][s][o] = value / 127;
-	}
-	
-	for (c = 0 ; c < 2 ; c++)
-	for (p = 0 ; p < 6 ; p++)
-	for (s = 0 ; s < 64 ; s++)
-	for (o = 0 ; o < 10 ; o++)
-	{
-		value = 0;
-		for (d = 0 ; d < 10 ; d++)
-			value += nnue->values0[p][s][d] * nnue->pst3[o * 10 * 2 + d * 2 + c];
-		nnue->values[c][p][s][o] = value / 127;
-	}
-	
-	return 0;
-}
--- a/search.c
+++ b/search.c
@@ -2,57 +2,9 @@
 
 #include "moonfish.h"
 
-static int moonfish_evaluate(struct moonfish_chess *chess, struct moonfish_nnue *nnue)
+static int moonfish_search(struct moonfish_chess *chess, int alpha, int beta, int depth)
 {
-	int features[18] = {0};
 	int x, y;
-	int i, j;
-	unsigned char piece, color, type;
-	int scale;
-	int *white_values, *black_values;
-	int hidden[10], score;
-	
-	scale = 0;
-	
-	for (y = 0 ; y < 8 ; y++)
-	for (x = 0 ; x < 8 ; x++)
-	{
-		piece = chess->board[(x + 1) + (y + 2) * 10];
-		if (piece == moonfish_empty) continue;
-		
-		color = (piece >> 4) - 1;
-		type = (piece & 0xF) - 1;
-		
-		white_values = nnue->values[color][type][63 - (x + y * 8)];
-		black_values = nnue->values[color ^ 1][type][x + y * 8];
-		
-		scale += white_values[0];
-		scale -= black_values[0];
-		
-		for (i = 0 ; i < 9 ; i++)
-		{
-			features[i] += white_values[i + 1];
-			features[i + 9] += black_values[i + 1];
-		}
-	}
-	
-	for (i = 0 ; i < 10 ; i++)
-	{
-		hidden[i] = 0;
-		for (j = 0 ; j < 18 ; j++)
-			hidden[i] += nnue->layer1[i * 18 + j] * moonfish_tanh(features[j]) / 127;
-	}
-	
-	score = 0;
-	for (i = 0 ; i < 10 ; i++)
-		score += moonfish_tanh(hidden[i]) * nnue->layer2[i] / 127;
-	
-	return score * 360 + scale * nnue->scale * 360 / 256;
-}
-
-static int moonfish_search(struct moonfish_chess *chess, struct moonfish_nnue *nnue, int alpha, int beta, int depth)
-{
-	int x, y;
 	struct moonfish_move moves[32];
 	struct moonfish_move *move;
 	int score;
@@ -59,11 +11,10 @@
 	
 	if (depth <= 0)
 	{
-		score = moonfish_evaluate(chess, nnue);
-		if (depth <= -3) return score;
+		if (depth <= -3) return chess->score;
 		
-		if (score >= beta) return beta;
-		if (score > alpha) alpha = score;
+		if (chess->score >= beta) return beta;
+		if (chess->score > alpha) alpha = chess->score;
 	}
 	
 	for (y = 0 ; y < 8 ; y++)
@@ -77,7 +28,7 @@
 			if (move->captured == moonfish_their_king) return moonfish_omega * (depth + 10);
 			
 			moonfish_play(chess, move);
-			score = -moonfish_search(chess, nnue, -beta, -alpha, depth - 1);
+			score = -moonfish_search(chess, -beta, -alpha, depth - 1);
 			moonfish_unplay(chess, move);
 			
 			if (score >= beta) return beta;
@@ -88,10 +39,13 @@
 	return alpha;
 }
 
+
 #ifdef MOONFISH_HAS_PTHREAD
 
+#include <pthread.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdio.h>
 
 struct moonfish_search_info
 {
@@ -98,7 +52,6 @@
 	pthread_t thread;
 	struct moonfish_move move;
 	struct moonfish_chess chess;
-	struct moonfish_nnue *nnue;
 	int depth;
 	int score;
 };
@@ -107,7 +60,7 @@
 {
 	struct moonfish_search_info *info;
 	info = data;
-	info->score = -moonfish_search(&info->chess, info->nnue, -100 * moonfish_omega, 100 * moonfish_omega, info->depth);
+	info->score = -moonfish_search(&info->chess, -100 * moonfish_omega, 100 * moonfish_omega, info->depth);
 	return NULL;
 }
 
@@ -141,7 +94,6 @@
 			
 			infos[count].move = *move;
 			infos[count].chess = ctx->chess;
-			infos[count].nnue = &ctx->nnue;
 			infos[count].depth = depth;
 			
 			result = pthread_create(&infos[count].thread, NULL, &moonfish_start_search, infos + count);
@@ -205,7 +157,7 @@
 				continue;
 			}
 			
-			score = -moonfish_search(&ctx->chess, &ctx->nnue, -100 * moonfish_omega, 100 * moonfish_omega, depth);
+			score = -moonfish_search(&ctx->chess, -100 * moonfish_omega, 100 * moonfish_omega, depth);
 			moonfish_unplay(&ctx->chess, move);
 			
 			if (score > best_score)
--