Thu, 03 Sep 2026 16:18:24 +0200
make castling rights part of the game state
required for issue #939
because creating a state from FEN
will not contain a move history
bonus: make is_check_position() robust
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2016 Mike Becker. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "rules.h" #include "king.h" bool king_chkrules(const GameState *gamestate, const Move* move) { if (abs(move->torank - move->fromrank) <= 1 && abs(move->tofile - move->fromfile) <= 1) { return true; } else if (move->fromrank == move->torank) { /* castling */ Rank backrank; bool k_allowed, q_allowed; if (piece_color(move->piece) == WHITE) { backrank = rankidx('1'); k_allowed = !gamestate->castling.K; q_allowed = !gamestate->castling.Q; } else { backrank = rankidx('8'); k_allowed = !gamestate->castling.k; q_allowed = !gamestate->castling.q; } bool castle_q = false, castle_k = false; if (move->fromrank == backrank && move->fromfile == fileidx('e')) { castle_q = move->tofile == fileidx('c'); castle_k = move->tofile == fileidx('g'); } /* note that here we do not consider threats! * that is what king_isblocked() does */ return (castle_q && q_allowed) || (castle_k && k_allowed); } else { return false; } } bool king_isblocked(const GameState *gamestate, const Move *move) { /* just test, if castling move is blocked */ if (abs(move->tofile - move->fromfile) == 2) { if (move->tofile == fileidx('c')) { /* check if rook can travel the queen-side */ if (gamestate->board[move->torank][fileidx('b')]) { return true; } } /* check if new field for the rook is free */ File midfile = (move->tofile+move->fromfile)/2; if (gamestate->board[move->torank][midfile]) { return true; } /* check if the king or the target field for the rook is threatened */ if (is_check_position(gamestate) || is_covered(gamestate, midfile, move->torank, opponent_color(piece_color(move->piece)))) { return true; } } return false; } size_t king_moves(const GameState *gamestate, Color c, File f, Rank r, Move *moves) { size_t count = 0; Piece king = mkpiece(KING, c); for (int dr = -1 ; dr <= 1 ; dr++) { for (int df = -1 ; df <= 1 ; df++) { if (dr == 0 && df == 0) { continue; } Rank torank = r + dr; File tofile = f + df; if (!isidx(torank) || !isidx(tofile)) { continue; } moves[count] = (Move){0}; moves[count].piece = king; moves[count].fromrank = r; moves[count].fromfile = f; moves[count].torank = torank; moves[count].tofile = tofile; moves[count].capture = piece_at(gamestate, tofile, torank) != 0; count++; } } Rank homerank = c == WHITE ? 0 : 7; if (r == homerank && f == fileidx('e')) { moves[count] = (Move){0}; moves[count].piece = king; moves[count].fromrank = r; moves[count].fromfile = f; moves[count].torank = r; moves[count].tofile = fileidx('c'); count++; moves[count] = (Move){0}; moves[count].piece = king; moves[count].fromrank = r; moves[count].fromfile = f; moves[count].torank = r; moves[count].tofile = fileidx('g'); count++; } return count; }