shithub: moonfish

Download patch

ref: 0a01d63f476aa04ecbfd563044288b3d605f6456
parent: 9235e718b5bca7692fea883a24daa21867c61fcd
author: zamfofex <zamfofex@twdb.moe>
date: Mon Oct 16 13:50:05 EDT 2023

add WDL support, SAN, and annotations to ‘analyse’ + bug fixes

--- a/chess.c
+++ b/chess.c
@@ -241,6 +241,11 @@
 	chess->board[move->from] = moonfish_empty;
 	chess->board[move->to] = move->promotion;
 	
+	if (move->piece == moonfish_our_pawn)
+	if ((move->to - move->from) % 10)
+	if (move->captured == moonfish_empty)
+		chess->board[move->to - 10] = moonfish_empty;
+	
 	if (move->piece == moonfish_our_king)
 	{
 		x0 = 0;
@@ -325,9 +330,8 @@
 	moonfish_fen(chess, "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq");
 }
 
-void moonfish_play_uci(struct moonfish_chess *chess, char *name)
+void moonfish_from_uci(struct moonfish_chess *chess, struct moonfish_move *move, char *name)
 {
-	struct moonfish_move move;
 	int x, y;
 	
 	x = name[0] - 'a';
@@ -339,7 +343,7 @@
 		y = 7 - y;
 	}
 	
-	move.from = (x + 1) + (y + 2) * 10;
+	move->from = (x + 1) + (y + 2) * 10;
 	
 	x = name[2] - 'a';
 	y = name[3] - '1';
@@ -350,23 +354,16 @@
 		y = 7 - y;
 	}
 	
-	move.to = (x + 1) + (y + 2) * 10;
+	move->to = (x + 1) + (y + 2) * 10;
 	
-	move.piece = chess->board[move.from];
-	move.captured = chess->board[move.to];
-	move.promotion = move.piece;
+	move->piece = chess->board[move->from];
+	move->captured = chess->board[move->to];
+	move->promotion = move->piece;
 	
-	if (move.piece == moonfish_our_pawn)
-	if ((move.to - move.from) % 10)
-	if (move.captured == moonfish_empty)
-		chess->board[move.to - 10] = moonfish_empty;
-	
-	if (name[4] == 'q') move.promotion = moonfish_our_queen;
-	if (name[4] == 'r') move.promotion = moonfish_our_rook;
-	if (name[4] == 'b') move.promotion = moonfish_our_bishop;
-	if (name[4] == 'n') move.promotion = moonfish_our_knight;
-	
-	moonfish_play(chess, &move);
+	if (name[4] == 'q') move->promotion = moonfish_our_queen;
+	if (name[4] == 'r') move->promotion = moonfish_our_rook;
+	if (name[4] == 'b') move->promotion = moonfish_our_bishop;
+	if (name[4] == 'n') move->promotion = moonfish_our_knight;
 }
 
 void moonfish_to_uci(char *name, struct moonfish_move *move, int white)
--- a/main.c
+++ b/main.c
@@ -167,7 +167,10 @@
 			if (arg != NULL && !strcmp(arg, "moves"))
 			{
 				while ((arg = strtok(NULL, "\r\n\t ")) != NULL)
-					moonfish_play_uci(&ctx->chess, arg);
+				{
+					moonfish_from_uci(&ctx->chess, &move, arg);
+					moonfish_play(&ctx->chess, &move);
+				}
 			}
 		}
 		else if (!strcmp(arg, "uci"))
--- a/moonfish.h
+++ b/moonfish.h
@@ -80,7 +80,7 @@
 
 int moonfish_best_move(struct moonfish *ctx, struct moonfish_move *move, int time);
 
-void moonfish_play_uci(struct moonfish_chess *chess, char *name);
+void moonfish_from_uci(struct moonfish_chess *chess, struct moonfish_move *move, char *name);
 void moonfish_to_uci(char *name, struct moonfish_move *move, int white);
 
 int moonfish_validate(struct moonfish_chess *chess);
--- a/tools/analyse.c
+++ b/tools/analyse.c
@@ -13,7 +13,7 @@
 {
 	struct moonfish_chess chess;
 	char name[6];
-	char san[12];
+	char san[16];
 	int white, black, draw;
 	int score;
 	int checkmate;
@@ -168,14 +168,49 @@
 
 static void moonfish_scoresheet_move(struct moonfish_fancy *fancy, int i)
 {
+	struct moonfish_ply *ply;
+	int checkmate;
+	int score;
+	
+	ply = fancy->plies + i;
+	
 	if (i >= fancy->count) 
 	{
-		printf("%11s", "");
+		printf("%10s", "");
 		return;
 	}
+	
 	if (i == fancy->i) printf("\x1B[48;5;248m\x1B[38;5;235m");
-	printf(" %-7s   ", fancy->plies[i].san);
-	if (i == fancy->i) printf("\x1B[0m");
+	printf(" %s", ply->san);
+	
+	if (ply->checkmate)
+	{
+		checkmate = ply->checkmate;
+		if (checkmate < 0) checkmate *= -1;
+		
+		printf("\x1B[38;5;162m#");
+		
+		if (ply->checkmate > 0) printf("+");
+		else printf("-");
+		
+		if (checkmate < 10)
+			printf("%d", checkmate);
+		else
+			printf("X");
+	}
+	else if (i > 0)
+	{
+		score = ply->score + fancy->plies[i - 1].score;
+		if (fancy->plies[i - 1].checkmate || score > 200) printf("\x1B[38;5;124m?? ");
+		else if (score > 100) printf("\x1B[38;5;173m?  ");
+		else printf("   ");
+	}
+	else
+	{
+		printf("   ");
+	}
+	
+	printf("%*s\x1B[0m", 6 - (int) strlen(ply->san), "");
 }
 
 static void moonfish_scoresheet(struct moonfish_fancy *fancy)
@@ -243,23 +278,117 @@
 	moonfish_evaluation(fancy);
 	
 	printf("\x1B[%d;24H", fancy->oy + 7);
-	printf("best:%s\n", fancy->pv);
+	printf("best:%s%32s\n", fancy->pv, "");
 	
 	fflush(stdout);
 }
 
+static void moonfish_to_san(struct moonfish_chess *chess, char *name, struct moonfish_move *move)
+{
+	static char names[] = "NBRQK";
+	
+	int x, y;
+	struct moonfish_move moves[32];
+	struct moonfish_move *other_move;
+	char file_ambiguity, rank_ambiguity, ambiguity;
+	int to_x, to_y;
+	int from_x, from_y;
+	
+	from_x = move->from % 10 - 1;
+	from_y = move->from / 10 - 2;
+	
+	to_x = move->to % 10 - 1;
+	to_y = move->to / 10 - 2;
+	
+	if (!chess->white)
+	{
+		from_x = 7 - from_x;
+		from_y = 7 - from_y;
+		to_x = 7 - to_x;
+		to_y = 7 - to_y;
+	}
+	
+	if (move->piece == moonfish_our_pawn)
+	{
+		if (from_x != to_x)
+		{
+			*name++ = from_x + 'a';
+			*name++ = 'x';
+		}
+		
+		*name++ = to_x + 'a';
+		*name++ = to_y + '1';
+		
+		if (move->promotion != moonfish_our_pawn)
+		{
+			*name++ = '=';
+			*name++ = names[(move->promotion & 0xF) - 2];
+		}
+		
+		*name = 0;
+		
+		return;
+	}
+	
+	file_ambiguity = 0;
+	rank_ambiguity = 0;
+	ambiguity = 0;
+	
+	for (y = 0 ; y < 8 ; y++)
+	for (x = 0 ; x < 8 ; x++)
+	{
+		if ((x + 1) + (y + 2) * 10 == move->from) continue;
+		moonfish_moves(chess, moves, (x + 1) + (y + 2) * 10);
+		
+		for (other_move = moves ; other_move->piece != moonfish_outside ; other_move++)
+		{
+			if (other_move->to != move->to) continue;
+			if (other_move->piece != move->piece) continue;
+			
+			ambiguity = 1;
+			if (other_move->from % 10 - 1 == from_x) file_ambiguity = 1;
+			if (other_move->from / 10 - 2 == from_y) rank_ambiguity = 1;
+		}
+	}
+	
+	*name++ = names[(move->piece & 0xF) - 2];
+	
+	if (ambiguity)
+	{
+		if (file_ambiguity)
+		{
+			if (rank_ambiguity)
+				*name++ = from_x + 'a';
+			*name++ = from_y + '1';
+		}
+		else
+		{
+			*name++ = from_x + 'a';
+		}
+	}
+	
+	if (move->captured != moonfish_empty)
+		*name++ = 'x';
+		
+	*name++ = to_x + 'a';
+	*name++ = to_y + '1';
+	
+	*name = 0;
+}
+
 static void *moonfish_start(void *data)
 {
 	static char line[2048];
+	static struct moonfish_ply ply;
+	static char san[16];
 	
 	struct moonfish_fancy *fancy;
 	char *arg;
 	int score;
 	char *buffer;
-	struct moonfish_ply *ply;
-	int depth;
 	struct pollfd fds;
 	unsigned int i, length;
+	struct moonfish_move move;
 	
 	fancy = data;
 	
@@ -293,8 +422,8 @@
 		arg = strtok_r(line, "\r\n\t ", &buffer);
 		if (arg == NULL) continue;
 		
-		ply = fancy->plies + fancy->i;
-		depth = 0;
+		ply = fancy->plies[fancy->i];
+		ply.depth = 0;
 		
 		for (;;)
 		{
@@ -301,10 +430,13 @@
 			arg = strtok_r(NULL, "\r\n\t ", &buffer);
 			if (arg == NULL) break;
 			
+			if (!strcmp(arg, "lowerbound")) break;
+			if (!strcmp(arg, "upperbound")) break;
+			
 			if (!strcmp(arg, "depth"))
 			{
 				arg = strtok_r(NULL, "\r\n\t ", &buffer);
-				if (arg == NULL || sscanf(arg, "%d", &depth) != 1)
+				if (arg == NULL || sscanf(arg, "%d", &ply.depth) != 1)
 				{
 					fprintf(stderr, "%s: malformed 'depth' in 'info' command\n", fancy->argv0);
 					exit(1);
@@ -320,18 +452,59 @@
 				{
 					arg = strtok_r(NULL, "\r\n\t ", &buffer);
 					if (arg == NULL) break;
-					length = strlen(arg);
+					moonfish_from_uci(&ply.chess, &move, arg);
+					moonfish_to_san(&ply.chess, san, &move);
+					length = strlen(san);
 					if (i + length > sizeof fancy->pv - 2) break;
+					moonfish_play(&ply.chess, &move);
 					fancy->pv[i++] = ' ';
-					strcpy(fancy->pv + i, arg);
+					strcpy(fancy->pv + i, san);
 					i += length;
 				}
 				
-				fancy->pv[i] = 0;
+				fancy->plies[fancy->i].score = ply.score;
+				fancy->plies[fancy->i].white = ply.white;
+				fancy->plies[fancy->i].black = ply.black;
+				fancy->plies[fancy->i].draw = ply.draw;
+				fancy->plies[fancy->i].checkmate = ply.checkmate;
+				fancy->plies[fancy->i].depth = ply.depth;
 				
 				break;
 			}
 			
+			if (!strcmp(arg, "wdl"))
+			{
+				arg = strtok_r(NULL, "\r\n\t ", &buffer);
+				if (arg == NULL || sscanf(arg, "%d", &ply.white) != 1)
+				{
+					fprintf(stderr, "%s: malformed 'wdl' win in 'info' command\n", fancy->argv0);
+					exit(1);
+				}
+				arg = strtok_r(NULL, "\r\n\t ", &buffer);
+				if (arg == NULL || sscanf(arg, "%d", &ply.draw) != 1)
+				{
+					fprintf(stderr, "%s: malformed 'wdl' draw in 'info' command\n", fancy->argv0);
+					exit(1);
+				}
+				arg = strtok_r(NULL, "\r\n\t ", &buffer);
+				if (arg == NULL || sscanf(arg, "%d", &ply.black) != 1)
+				{
+					fprintf(stderr, "%s: malformed 'wdl' loss in 'info' command\n", fancy->argv0);
+					exit(1);
+				}
+				
+				ply.checkmate = 0;
+				
+				if (!ply.chess.white)
+				{
+					score = ply.white;
+					ply.white = ply.black;
+					ply.black = score;
+				}
+				
+				continue;
+			}
+			
 			if (strcmp(arg, "score")) continue;
 			
 			arg = strtok_r(NULL, "\r\n\t ", &buffer);
@@ -346,21 +519,20 @@
 					exit(1);
 				}
 				
-				ply->score = score;
-				ply->white = 100;
-				ply->black = 100;
-				ply->depth = depth;
-				ply->draw = 0;
-				ply->checkmate = 0;
+				ply.score = score;
+				ply.white = 100;
+				ply.black = 100;
+				ply.draw = 0;
+				ply.checkmate = 0;
 				
-				if (score > 0) ply->white += score;
-				else ply->black -= score;
+				if (score > 0) ply.white += score;
+				else ply.black -= score;
 				
-				if (!ply->chess.white)
+				if (!ply.chess.white)
 				{
-					score = ply->white;
-					ply->white = ply->black;
-					ply->black = score;
+					score = ply.white;
+					ply.white = ply.black;
+					ply.black = score;
 				}
 				
 				continue;
@@ -375,14 +547,13 @@
 					exit(1);
 				}
 				
-				if (!ply->chess.white) score *= -1;
+				if (!ply.chess.white) score *= -1;
 				
-				ply->white = 0;
-				ply->black = 0;
-				ply->draw = 0;
-				ply->checkmate = score;
-				ply->score = 0;
-				ply->depth = depth;
+				ply.white = 0;
+				ply.black = 0;
+				ply.draw = 0;
+				ply.checkmate = score;
+				ply.score = 0;
 				
 				continue;
 			}
@@ -751,9 +922,10 @@
 				fancy->count = fancy->i + 1;
 				fancy->plies[fancy->i] = fancy->plies[fancy->i - 1];
 				fancy->plies[fancy->i].depth = 0;
+				fancy->plies[fancy->i].score *= -1;
 				
 				moonfish_to_uci(fancy->plies[fancy->i].name, &move, fancy->plies[fancy->i].chess.white);
-				strcpy(fancy->plies[fancy->i].san, fancy->plies[fancy->i].name);
+				moonfish_to_san(&fancy->plies[fancy->i].chess, fancy->plies[fancy->i].san, &move);
 				
 				moonfish_play(&fancy->plies[fancy->i].chess, &move);
 				fancy->x = 0;
--- a/tools/play.c
+++ b/tools/play.c
@@ -264,6 +264,7 @@
 {
 	int white_time, black_time;
 	char *arg;
+	struct moonfish_move move;
 	
 	if (fancy->white == fancy->chess.white)
 	{
@@ -295,7 +296,8 @@
 	strcpy(name, arg);
 	
 	pthread_mutex_lock(fancy->mutex);
-	moonfish_play_uci(&fancy->chess, arg);
+	moonfish_from_uci(&fancy->chess, &move, arg);
+	moonfish_play(&fancy->chess, &move);
 }
 
 int main(int argc, char **argv)
--- a/tools/utils.c
+++ b/tools/utils.c
@@ -2,6 +2,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <fcntl.h>
 
 #include "tools.h"
 
@@ -8,7 +9,7 @@
 int moonfish_spawn(char *argv0, char **argv, int *in, int *out)
 {
 	int p1[2], p2[2];
-	int pid;
+	int pid, fd;
 	
 	if (pipe(p1) == -1) return 1;
 	if (pipe(p2) == -1) return 1;
@@ -25,8 +26,16 @@
 		return 0;
 	}
 	
+	fd = open("/dev/null", O_RDONLY);
+	if (fd < 0)
+	{
+		fprintf(stderr, "%s: %s: %s\n", argv0, argv[0], strerror(errno));
+		exit(1);
+	}
+	
 	dup2(p1[0], 0);
 	dup2(p2[1], 1);
+	dup2(p2[1], 2);
 	
 	close(p1[0]);
 	close(p1[1]);
--