shithub: moonfish

Download patch

ref: 0f58da9b6912afba632ed5aa39976406b519216d
parent: 37c75f1e19c18e7783e9715b388a851ea4071f36
author: zamfofex <zamfofex@twdb.moe>
date: Sat Oct 7 07:18:23 EDT 2023

castling and quiescence search

--- a/README.md
+++ b/README.md
@@ -18,12 +18,10 @@
 These are things that I plan to fix eventually.
 
 - the bot will never make certain moves
-  - no castling
   - no en passant
   - no underpromotion
 - the TUI will also prevent you from making those kinds of moves
 - the TUI does not detect when the game has ended due to stalemate or checkmate
-- no quiescence search
 - no iterative deepening
 - no transposition table
 - no good move ordering heuristic
--- a/chess.c
+++ b/chess.c
@@ -11,6 +11,7 @@
 	(*moves)->piece = ctx->board[from];
 	(*moves)->promotion = ctx->board[from];
 	(*moves)->captured = ctx->board[*to];
+	(*moves)->castle = ctx->castle;
 	(*moves)++;
 	
 	if (ctx->board[*to] != moonfish_empty) return 0;
@@ -64,6 +65,57 @@
 	moonfish_move_bishop(ctx, moves, from);
 }
 
+static char moonfish_attacked(struct moonfish *ctx, unsigned char from, unsigned char to)
+{
+	int check;
+	ctx->board[from] = moonfish_empty;
+	ctx->board[to] = moonfish_our_king;
+	check = moonfish_check(ctx);
+	ctx->board[from] = moonfish_our_king;
+	ctx->board[to] = moonfish_empty;
+	return check;
+}
+
+static void moonfish_castle_low(struct moonfish *ctx, struct moonfish_move **moves, unsigned char from)
+{
+	int to;
+	
+	for (to = 22 ; to != from ; to++)
+		if (ctx->board[to] != moonfish_empty)
+			return;
+	
+	if (moonfish_check(ctx)) return;
+	if (moonfish_attacked(ctx, from, from - 1)) return;
+	
+	(*moves)->from = from;
+	(*moves)->to = from - 2;
+	(*moves)->piece = moonfish_our_king;
+	(*moves)->promotion = moonfish_our_king;
+	(*moves)->captured = moonfish_empty;
+	(*moves)->castle = ctx->castle;
+	(*moves)++;
+}
+
+static void moonfish_castle_high(struct moonfish *ctx, struct moonfish_move **moves, unsigned char from)
+{
+	int to;
+	
+	for (to = 27 ; to != from ; to--)
+		if (ctx->board[to] != moonfish_empty)
+			return;
+	
+	if (moonfish_check(ctx)) return;
+	if (moonfish_attacked(ctx, from, from + 1)) return;
+	
+	(*moves)->from = from;
+	(*moves)->to = from + 2;
+	(*moves)->piece = moonfish_our_king;
+	(*moves)->promotion = moonfish_our_king;
+	(*moves)->captured = moonfish_empty;
+	(*moves)->castle = ctx->castle;
+	(*moves)++;
+}
+
 static void moonfish_move_king(struct moonfish *ctx, struct moonfish_move **moves, unsigned char from)
 {
 	moonfish_jump(ctx, moves, from, 1 + 10);
@@ -74,6 +126,17 @@
 	moonfish_jump(ctx, moves, from, -10);
 	moonfish_jump(ctx, moves, from, 1);
 	moonfish_jump(ctx, moves, from, -1);
+	
+	if (from == 24)
+	{
+		if (ctx->castle.black_oo) moonfish_castle_low(ctx, moves, from);
+		if (ctx->castle.black_ooo) moonfish_castle_high(ctx, moves, from);
+	}
+	if (from == 25)
+	{
+		if (ctx->castle.white_oo) moonfish_castle_high(ctx, moves, from);
+		if (ctx->castle.white_ooo) moonfish_castle_low(ctx, moves, from);
+	}
 }
 
 static void moonfish_move_pawn(struct moonfish *ctx, struct moonfish_move **moves, unsigned char from)
@@ -90,6 +153,7 @@
 		(*moves)->captured = moonfish_empty;
 		(*moves)->from = from;
 		(*moves)->to = from + 10;
+		(*moves)->castle = ctx->castle;
 		(*moves)++;
 				
 		if (from < 40)
@@ -101,6 +165,7 @@
 				(*moves)->piece = moonfish_our_pawn;
 				(*moves)->promotion = moonfish_our_pawn;
 				(*moves)->captured = moonfish_empty;
+				(*moves)->castle = ctx->castle;
 				(*moves)++;
 			}
 		}
@@ -114,6 +179,7 @@
 		(*moves)->captured = ctx->board[from + 9];
 		(*moves)->from = from;
 		(*moves)->to = from + 9;
+		(*moves)->castle = ctx->castle;
 		(*moves)++;
 	}
 	
@@ -125,6 +191,7 @@
 		(*moves)->captured = ctx->board[from + 11];
 		(*moves)->from = from;
 		(*moves)->to = from + 11;
+		(*moves)->castle = ctx->castle;
 		(*moves)++;
 	}
 }
@@ -198,16 +265,57 @@
 
 void moonfish_play(struct moonfish *ctx, struct moonfish_move *move)
 {
+	int x0, x1;
+	
 	ctx->board[move->from] = moonfish_empty;
 	ctx->board[move->to] = move->promotion;
+	
+	if (move->piece == moonfish_our_king)
+	{
+		x0 = 0;
+		if (move->from == 24 && move->to == 22) x0 = 1, x1 = 3, ctx->castle.black_oo = 0;
+		if (move->from == 24 && move->to == 26) x0 = 8, x1 = 5, ctx->castle.black_ooo = 0;
+		if (move->from == 25 && move->to == 27) x0 = 8, x1 = 6, ctx->castle.white_oo = 0;
+		if (move->from == 25 && move->to == 23) x0 = 1, x1 = 4, ctx->castle.white_ooo = 0;
+		if (x0) ctx->board[x0 + 20] = moonfish_empty, ctx->board[x1 + 20] = moonfish_our_rook;
+	}
+	
+	if (move->piece == moonfish_our_rook)
+	{
+		if (move->from == 28)
+		{
+			if (ctx->white) ctx->castle.white_ooo = 0;
+			else ctx->castle.black_oo = 0;
+		}
+		if (move->from == 21)
+		{
+			if (ctx->white) ctx->castle.white_oo = 0;
+			else ctx->castle.black_opo = 0;
+		}
+	}
+	
 	moonfish_rotate(ctx);
 }
 
 void moonfish_unplay(struct moonfish *ctx, struct moonfish_move *move)
 {
+	int x0, x1;
+	
 	moonfish_rotate(ctx);
+	
 	ctx->board[move->from] = move->piece;
 	ctx->board[move->to] = move->captured;
+	ctx->castle = move->castle;
+	
+	if (move->piece == moonfish_our_king)
+	{
+		x0 = 0;
+		if (move->from == 42 && move->to == 22) x0 = 1, x1 = 3;
+		if (move->from == 42 && move->to == 62) x0 = 8, x1 = 5;
+		if (move->from == 52 && move->to == 72) x0 = 8, x1 = 6;
+		if (move->from == 52 && move->to == 32) x0 = 1, x1 = 4;
+		if (x0) ctx->board[x1 + 20] = moonfish_empty, ctx->board[x0 + 20] = moonfish_our_rook;
+	}
 }
 
 void moonfish_chess(struct moonfish *ctx)
@@ -232,6 +340,10 @@
 	}
 	
 	ctx->white = 1;
+	ctx->castle.white_oo = 1;
+	ctx->castle.white_ooo = 1;
+	ctx->castle.black_oo = 1;
+	ctx->castle.black_ooo = 1;
 }
 
 void moonfish_show(struct moonfish *ctx)
@@ -298,20 +410,6 @@
 	move.captured = ctx->board[move.to];
 	move.promotion = move.piece;
 	
-	if (move.piece == moonfish_our_king && move.from == 0x25)
-	{
-		if (move.to == 0x23)
-		{
-			ctx->board[0x21] = moonfish_empty;
-			ctx->board[0x24] = moonfish_our_rook;
-		}
-		if (move.to == 0x27)
-		{
-			ctx->board[0x28] = moonfish_empty;
-			ctx->board[0x26] = moonfish_our_rook;
-		}
-	}
-	
 	if (move.piece == moonfish_our_pawn)
 	if ((move.to - move.from) % 10)
 	if (move.captured == moonfish_empty)
@@ -377,10 +475,17 @@
 	x = 0;
 	y = 0;
 	
+	ctx->white = 1;
+	ctx->castle.white_oo = 0;
+	ctx->castle.white_ooo = 0;
+	ctx->castle.black_oo = 0;
+	ctx->castle.black_ooo = 0;
+	
 	for (;;)
 	{
 		ch = *fen++;
 		
+		if (ch == 0) return;
 		if (ch == ' ') break;
 		
 		if (ch == '/')
@@ -415,14 +520,25 @@
 		x++;
 	}
 	
-	ctx->white = 1;
-	if (*fen == 'b') moonfish_rotate(ctx);
+	if (*fen++ == 'b') moonfish_rotate(ctx);
+	if (*fen++ != ' ') return;
+	
+	for (;;)
+	{
+		ch = *fen++;
+		if (ch == 0) return;
+		if (ch == ' ') break;
+		if (ch == 'K') ctx->castle.white_oo = 1;
+		if (ch == 'Q') ctx->castle.white_ooo = 1;
+		if (ch == 'k') ctx->castle.black_oo = 1;
+		if (ch == 'q') ctx->castle.black_ooo = 1;
+	}
 }
 
 int moonfish_validate(struct moonfish *ctx)
 {
 	int x, y;
-	struct moonfish_move moves[512];
+	struct moonfish_move moves[32];
 	struct moonfish_move *move;
 	
 	for (y = 0 ; y < 8 ; y++)
@@ -435,4 +551,25 @@
 	}
 	
 	return 1;
+}
+
+int moonfish_check(struct moonfish *ctx)
+{
+	int valid;
+	struct moonfish_castle castle;
+	
+	castle = ctx->castle;
+	
+	ctx->castle.white_oo = 0;
+	ctx->castle.white_ooo = 0;
+	ctx->castle.black_oo = 0;
+	ctx->castle.black_ooo = 0;
+	
+	moonfish_rotate(ctx);
+	valid = moonfish_validate(ctx);
+	moonfish_rotate(ctx);
+	
+	ctx->castle = castle;
+	
+	return valid ? 0 : 1;
 }
--- a/moonfish.h
+++ b/moonfish.h
@@ -31,14 +31,21 @@
 	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];
-	char scale;
+	signed char scale;
 };
 
+struct moonfish_castle
+{
+	unsigned int white_oo:1, white_ooo:1;
+	unsigned int black_oo:1, black_ooo:1;
+};
+
 struct moonfish
 {
 	struct moonfish_nnue nnue;
 	unsigned char board[120];
-	char white;
+	unsigned char white;
+	struct moonfish_castle castle;
 };
 
 struct moonfish_move
@@ -47,6 +54,7 @@
 	unsigned char piece;
 	unsigned char promotion;
 	unsigned char captured;
+	struct moonfish_castle castle;
 };
 
 int moonfish_nnue(struct moonfish *ctx, FILE *file);
@@ -69,5 +77,6 @@
 void moonfish_to_uci(char *name, struct moonfish_move *move, int white);
 
 int moonfish_validate(struct moonfish *ctx);
+int moonfish_check(struct moonfish *ctx);
 
 #endif
--- a/search.c
+++ b/search.c
@@ -48,7 +48,6 @@
 	return score * 360 + scale * ctx->nnue.scale * 360 / 256;
 }
 
-/*
 static int moonfish_quiesce(struct moonfish *ctx, int alpha, int beta, int depth)
 {
 	int x, y;
@@ -70,7 +69,7 @@
 		for (move = moves ; move->piece != moonfish_outside ; move++)
 		{
 			if (move->captured == moonfish_empty) continue;
-			if (move->captured == moonfish_their_king) return moonfish_omega * depth;
+			if (move->captured == moonfish_their_king) return moonfish_omega * (4 + depth);
 			
 			moonfish_play(ctx, move);
 			score = -moonfish_quiesce(ctx, -beta, -alpha, depth - 1);
@@ -83,7 +82,6 @@
 	
 	return alpha;
 }
-*/
 
 static int moonfish_search(struct moonfish *ctx, int alpha, int beta, int depth)
 {
@@ -92,8 +90,7 @@
 	struct moonfish_move *move;
 	int score;
 	
-	/* if (depth == 0) return moonfish_quiesce(ctx, alpha, beta, 6); */
-	if (depth == 0) return moonfish_evaluate(ctx);
+	if (depth == 0) return moonfish_quiesce(ctx, alpha, beta, 2);
 	
 	for (y = 0 ; y < 8 ; y++)
 	for (x = 0 ; x < 8 ; x++)
@@ -133,6 +130,13 @@
 		for (move = moves ; move->piece != moonfish_outside ; move++)
 		{
 			moonfish_play(ctx, move);
+			
+			if (!moonfish_validate(ctx))
+			{
+				moonfish_unplay(ctx, move);
+				continue;
+			}
+			
 			score = -moonfish_search(ctx, -10 * moonfish_omega, 10 * moonfish_omega, 4);
 			moonfish_unplay(ctx, move);
 			
--