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);
--
⑨