--- a/src/chess/king.c Thu Sep 03 15:28:54 2026 +0200 +++ b/src/chess/king.c Thu Sep 03 16:18:24 2026 +0200 @@ -30,62 +30,57 @@ #include "rules.h" #include "king.h" -static bool king_castling_chkmoved( - const GameState *gamestate, File file, Rank rank) { - - for (unsigned i = 0; i < gamestate->movecount; i++) { - if (gamestate->moves[i].fromfile == file - && gamestate->moves[i].fromrank == rank) { - return true; - } - } - - return false; -} - 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 { + } else if (move->fromrank == move->torank) { /* castling */ - if (move->fromrank == move->torank && - move->fromrank == (piece_color(move->piece) == WHITE ? 0 : 7) && - move->fromfile == fileidx('e') && - (move->tofile == fileidx('c') || move->tofile == fileidx('g'))) { - - return !king_castling_chkmoved(gamestate, - move->fromfile, move->fromrank) && - !king_castling_chkmoved(gamestate, - move->tofile == fileidx('c') ? 0 : 7, move->fromrank); + 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 { - return false; + 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) { - - Color op_color = opponent_color(piece_color(move->piece)); - - /* being in check does not "block" the king, so don't test it here */ - bool blocked = false; - /* just test, if castling move is blocked */ if (abs(move->tofile - move->fromfile) == 2) { if (move->tofile == fileidx('c')) { - blocked |= gamestate->board[move->torank][fileidx('b')]; + /* 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; - bool incheck = false; - if (gamestate->movecount > 0) { - incheck = is_check_position(gamestate); + if (gamestate->board[move->torank][midfile]) { + return true; } - blocked |= incheck || gamestate->board[move->torank][midfile] || - is_covered(gamestate, midfile, move->torank, op_color); + /* 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 blocked; + return false; } size_t king_moves(const GameState *gamestate,