shithub: moonfish

Download patch

ref: 9571174370478fb8beb2b3319142b60986ab2252
parent: e0986d0fbef869b5d2fc13bd135d8950ce7b4d37
author: zamfofex <zamfofex@twdb.moe>
date: Sat Dec 16 08:58:40 EST 2023

allow accepting challenges from position on Lichess

--- a/chess.c
+++ b/chess.c
@@ -411,25 +411,23 @@
 
 void moonfish_from_uci(struct moonfish_chess *chess, struct moonfish_move *move, char *name)
 {
-	int x, y;
+	int x0, y0;
+	int x1, y1;
 	unsigned char color;
 	
-	x = name[0] - 'a';
-	y = name[1] - '1';
+	x0 = name[0] - 'a';
+	y0 = name[1] - '1';
+	x1 = name[2] - 'a';
+	y1 = name[3] - '1';
 	
-	move->from = (x + 1) + (y + 2) * 10;
+	moonfish_create_move(chess, &move, (x0 + 1) + (y0 + 2) * 10, (x1 + 1) + (y1 + 2) * 10);
+	if (move->piece % 16 == moonfish_king && x0 == 4)
+	{
+		if (x1 == 0) x1 = 2;
+		if (x1 == 7) x1 = 6;
+		moonfish_create_move(chess, &move, (x0 + 1) + (y0 + 2) * 10, (x1 + 1) + (y1 + 2) * 10);
+	}
 	
-	x = name[2] - 'a';
-	y = name[3] - '1';
-	
-	move->to = (x + 1) + (y + 2) * 10;
-	
-	move->piece = chess->board[move->from];
-	move->captured = chess->board[move->to];
-	move->promotion = move->piece;
-	move->castle = chess->castle;
-	move->score = chess->score;
-	
 	color = chess->white ? 0x10 : 0x20;
 	if (name[4] == 'q') move->promotion = color | moonfish_queen;
 	if (name[4] == 'r') move->promotion = color | moonfish_rook;
@@ -464,7 +462,7 @@
 	}
 }
 
-void moonfish_fen(struct moonfish_chess *chess, char *fen)
+int moonfish_fen(struct moonfish_chess *chess, char *fen)
 {
 	int x, y;
 	unsigned char type, color;
@@ -488,7 +486,7 @@
 	{
 		ch = *fen++;
 		
-		if (ch == 0) return;
+		if (ch == 0) return 0;
 		if (ch == ' ') break;
 		
 		if (ch == '/')
@@ -526,17 +524,22 @@
 	}
 	
 	if (*fen++ == 'b') chess->white ^= 1;
-	if (*fen++ != ' ') return;
+	if (*fen++ != ' ') return 0;
 	
 	for (;;)
 	{
 		ch = *fen++;
-		if (ch == 0) return;
-		if (ch == ' ') break;
+		
+		if (ch == 0) return 0;
+		if (ch == ' ') return 0;
+		
 		if (ch == 'K') chess->castle.white_oo = 1;
 		if (ch == 'Q') chess->castle.white_ooo = 1;
 		if (ch == 'k') chess->castle.black_oo = 1;
 		if (ch == 'q') chess->castle.black_ooo = 1;
+		
+		if (ch >= 'A' && ch <= 'H') return 1;
+		if (ch >= 'a' && ch <= 'h') return 1;
 	}
 }
 
--- a/makefile
+++ b/makefile
@@ -22,8 +22,8 @@
 play: moonfish.h tools/tools.h tools/play.c tools/utils.c chess.c
 	$(tools_cc) -o play tools/play.c tools/utils.c chess.c
 
-lichess: tools/tools.h tools/lichess.c tools/utils.c
-	$(tools_cc) -std=c99 -o lichess tools/lichess.c tools/utils.c -lbearssl -lcjson
+lichess: tools/tools.h tools/lichess.c tools/utils.c chess.c
+	$(tools_cc) -std=c99 -o lichess tools/lichess.c tools/utils.c chess.c -lbearssl -lcjson
 
 analyse: tools/tools.h tools/analyse.c tools/utils.c chess.c
 	$(tools_cc) -o analyse tools/analyse.c tools/utils.c chess.c
--- a/moonfish.h
+++ b/moonfish.h
@@ -65,7 +65,7 @@
 };
 
 void moonfish_chess(struct moonfish_chess *chess);
-void moonfish_fen(struct moonfish_chess *chess, char *fen);
+int moonfish_fen(struct moonfish_chess *chess, char *fen);
 
 void moonfish_moves(struct moonfish_chess *chess, struct moonfish_move *moves, unsigned char from);
 
--- a/tools/lichess.c
+++ b/tools/lichess.c
@@ -12,6 +12,7 @@
 #include <bearssl.h>
 #include <cjson/cJSON.h>
 
+#include "../moonfish.h"
 #include "tools.h"
 
 #define moonfish_write_text(io_ctx, text) br_sslio_write_all(io_ctx, text, strlen(text))
@@ -26,6 +27,7 @@
 	char id[512];
 	char **argv;
 	char *username;
+	char fen[512];
 };
 
 static int moonfish_tcp(char *argv0, char *name, char *port)
@@ -443,18 +445,25 @@
 	exit(1);
 }
 
+static pthread_mutex_t moonfish_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 static void moonfish_handle_game_events(br_ssl_engine_context *ctx, br_sslio_context *io_ctx, struct moonfish_game *game, FILE *in, FILE *out)
 {
 	char line[4096];
-	cJSON *root, *type, *state, *white_player, *id, *moves;
+	cJSON *root, *type, *state, *white_player, *id, *moves, *fen;
 	cJSON *wtime, *btime, *winc, *binc;
 	const char *end;
 	int white;
 	int move_count, count;
 	int i;
-	char *move;
+	char *name, name0[6];
 	int done;
+	int variant;
+	struct moonfish_chess chess;
+	struct moonfish_move move;
 	
+	pthread_mutex_lock(&moonfish_mutex);
+	
 	fprintf(in, "uci\n");
 	moonfish_wait(out, "uciok");
 	
@@ -470,9 +479,12 @@
 	white = -1;
 	move_count = -1;
 	done = 0;
+	variant = 0;
 	
 	while (!done)
 	{
+		pthread_mutex_unlock(&moonfish_mutex);
+		
 		if (root != NULL)
 		{
 			cJSON_Delete(root);
@@ -480,6 +492,7 @@
 		}
 		
 		done = moonfish_tls_line(ctx, io_ctx, game->argv0, line, sizeof line);
+		pthread_mutex_lock(&moonfish_mutex);
 		if (line[0] == 0) continue;
 		
 		end = NULL;
@@ -511,6 +524,20 @@
 				if (!cJSON_IsString(id)) moonfish_json_error(game->argv0);
 				if (!strcmp(id->valuestring, game->username)) white = 1;
 			}
+			
+			fen = cJSON_GetObjectItem(root, "initialFen");
+			if (!cJSON_IsString(fen)) moonfish_json_error(game->argv0);
+			
+			if (strcmp(fen->valuestring, "startpos"))
+			{
+				strcpy(game->fen, "fen ");
+				strcat(game->fen, fen->valuestring);
+				variant = 1;
+			}
+			else
+			{
+				strcpy(game->fen, "startpos");
+			}
 		}
 		else
 		{
@@ -554,8 +581,29 @@
 		fprintf(in, "isready\n");
 		moonfish_wait(out, "readyok");
 		
-		fprintf(in, "position startpos");
-		if (count > 0) fprintf(in, " moves %s", moves->valuestring);
+		fprintf(in, "position %s", game->fen);
+		if (count > 0)
+		{
+			fprintf(in, " moves ");
+			if (!variant)
+			{
+				fprintf(in, "%s", moves->valuestring);
+			}
+			else
+			{
+				moonfish_fen(&chess, game->fen + 4);
+				name = strtok(moves->valuestring, " ");
+				for (;;)
+				{
+					moonfish_from_uci(&chess, &move, name);
+					moonfish_to_uci(name0, &move);
+					fprintf(in, "%s", name0);
+					name = strtok(NULL, " ");
+					if (name == NULL) break;
+					fprintf(in, " ");
+				}
+			}
+		}
 		fprintf(in, "\n");
 		
 		fprintf(in, "isready\n");
@@ -566,17 +614,29 @@
 		if (binc->valueint > 0) fprintf(in, " binc %d", binc->valueint);
 		fprintf(in, "\n");
 		
-		move = moonfish_wait(out, "bestmove");
-		if (move == NULL)
+		name = moonfish_wait(out, "bestmove");
+		if (name == NULL)
 		{
 			fprintf(stderr, "%s: could not find 'bestmove' command\n", game->argv0);
 			exit(1);
 		}
 		
-		snprintf(line, sizeof line, "POST /api/bot/game/%s/move/%s", game->id, move);
+		if (variant)
+		{
+			moonfish_from_uci(&chess, &move, name);
+			if (move.piece % 16 == moonfish_king)
+			{
+				if (!strcmp(name, "e1c1")) name = "e1a1";
+				else if (!strcmp(name, "e1g1")) name = "e1h1";
+				else if (!strcmp(name, "e8c8")) name = "e8a8";
+				else if (!strcmp(name, "e8g8")) name = "e8h8";
+			}
+		}
+		
+		snprintf(line, sizeof line, "POST /api/bot/game/%s/move/%s", game->id, name);
 		if (moonfish_basic_request(game->argv0, game->name, game->port, game->token, line, "", ""))
 		{
-			fprintf(stderr, "%s: could not make move '%s' in game '%s'\n", game->argv0, move, game->id);
+			fprintf(stderr, "%s: could not make move '%s' in game '%s'\n", game->argv0, name, game->id);
 			snprintf(line, sizeof line, "POST /api/bot/game/%s/resign", game->id);
 			if (moonfish_basic_request(game->argv0, game->name, game->port, game->token, line, "", ""))
 				fprintf(stderr, "%s: could not resign game '%s'\n", game->argv0, game->id);
@@ -589,6 +649,8 @@
 	fprintf(in, "quit\n");
 	fclose(in);
 	fclose(out);
+	
+	pthread_mutex_unlock(&moonfish_mutex);
 }
 
 static void *moonfish_handle_game(void *data)
@@ -681,10 +743,12 @@
 )
 {
 	static char line[8192];
-	cJSON *root, *type, *challenge, *id, *variant, *speed;
+	cJSON *root, *type, *challenge, *id, *variant, *speed, *fen;
 	const char *end;
 	struct moonfish_game *game;
 	pthread_t thread;
+	struct moonfish_chess chess;
+	int invalid;
 	
 	root = NULL;
 	
@@ -761,11 +825,41 @@
 		variant = cJSON_GetObjectItem(variant, "key");
 		if (!cJSON_IsString(variant)) moonfish_json_error(argv0);
 		
-		if (strcmp(variant->valuestring, "standard"))
+		if (!strcmp(variant->valuestring, "fromPosition"))
 		{
+			fen = cJSON_GetObjectItem(challenge, "initialFen");
+			if (!cJSON_IsString(fen)) moonfish_json_error(argv0);
+			
+			invalid = moonfish_fen(&chess, fen->valuestring);
+			
+			if (!invalid)
+			if (chess.castle.white_oo || chess.castle.white_ooo)
+			if (chess.board[25] != moonfish_white_king)
+				invalid = 1;
+			
+			if (!invalid)
+			if (chess.castle.black_oo || chess.castle.black_ooo)
+			if (chess.board[95] != moonfish_black_king)
+				invalid = 1;
+			
+			if (!invalid && chess.castle.white_ooo && chess.board[21] != moonfish_white_rook) invalid = 1;
+			if (!invalid && chess.castle.white_oo && chess.board[28] != moonfish_white_rook) invalid = 1;
+			if (!invalid && chess.castle.black_ooo && chess.board[91] != moonfish_black_rook) invalid = 1;
+			if (!invalid && chess.castle.black_oo && chess.board[98] != moonfish_black_rook) invalid = 1;
+			
+			if (invalid)
+			{
+				snprintf(line, sizeof line, "POST /api/challenge/%s/decline", id->valuestring);
+				if (moonfish_basic_request(argv0, name, port, token, line, "", "reason=standard"))
+					fprintf(stderr, "%s: could not decline challenge '%s' (chess 960 FEN)\n", argv0, id->valuestring);
+				continue;
+			}
+		}
+		else if (strcmp(variant->valuestring, "standard"))
+		{
 			snprintf(line, sizeof line, "POST /api/challenge/%s/decline", id->valuestring);
 			if (moonfish_basic_request(argv0, name, port, token, line, "", "reason=standard"))
-				fprintf(stderr, "%s: could not decline challenge '%s' (standard)\n", argv0, id->valuestring);
+				fprintf(stderr, "%s: could not decline challenge '%s' (variant)\n", argv0, id->valuestring);
 			continue;
 		}
 		
--