diff -r 114e764fbae5 -r 1a84ee6b4bf0 src/chess/rules.c --- a/src/chess/rules.c Fri Jun 12 14:33:42 2026 +0200 +++ b/src/chess/rules.c Fri Jun 12 15:28:00 2026 +0200 @@ -412,6 +412,7 @@ /* find kings for check validation */ uint8_t piececolor = (move->piece & COLOR_MASK); + uint8_t oppcolor = opponent_color(piececolor); uint8_t mykingfile = 0, mykingrow = 0, opkingfile = 0, opkingrow = 0; for (uint8_t row = 0 ; row < 8 ; row++) { @@ -429,9 +430,7 @@ } /* don't move into or stay in check position */ - if (is_covered(&simulation, mykingrow, mykingfile, - opponent_color(piececolor))) { - + if (is_covered(&simulation, mykingrow, mykingfile, oppcolor)) { gamestate_cleanup(&simulation); if ((move->piece & PIECE_MASK) == KING) { return KING_MOVES_INTO_CHECK; @@ -455,20 +454,27 @@ for (int df = -1 ; df <= 1 && !canescape ; df++) { if (!(dr == 0 && df == 0) && isidx(opkingrow + dr) && isidx(opkingfile + df)) { - - /* escape field neither blocked nor covered */ - if ((simulation.board[opkingrow + dr][opkingfile + df] - & COLOR_MASK) != opponent_color(piececolor)) { - canescape |= !is_covered(&simulation, + /* escape field neither occupied nor covered */ + canescape = + !simulation.board[opkingrow + dr][opkingfile + df] && + !is_covered(&simulation, opkingrow + dr, opkingfile + df, piececolor); - } } } } /* can't escape, can he capture? */ if (!canescape && threatcount == 1) { - canescape = is_attacked(&simulation, threats[0].fromrow, - threats[0].fromfile, opponent_color(piececolor)); + /* TODO: this is bugged - we actually need distinguish two cases + * 1. another piece can rescue the king + * (this is what is implemented now) + * 2. the king can kill the attacker + * - in this case, the threatcount is irrelevant, because + * the king moves out of the current threat + * - we must verify that the king can actually kill the + * attacker without running into a new check + */ + canescape = is_attacked(&simulation, + threats[0].fromrow, threats[0].fromfile, oppcolor); } /* can't capture, can he block? */ @@ -486,7 +492,7 @@ while (!canescape && file != threat->tofile - d) { file += d; canescape |= is_protected(&simulation, - threat->torow, file, opponent_color(piececolor)); + threat->torow, file, oppcolor); } } else if (threat->fromfile == threat->tofile) { /* rook aspect (on file) */ @@ -495,7 +501,7 @@ while (!canescape && row != threat->torow - d) { row += d; canescape |= is_protected(&simulation, - row, threat->tofile, opponent_color(piececolor)); + row, threat->tofile, oppcolor); } } else { /* bishop aspect */ @@ -509,14 +515,14 @@ row += dr; file += df; canescape |= is_protected(&simulation, row, file, - opponent_color(piececolor)); + oppcolor); } } } } if (!canescape) { - gamestate->checkmate = 1; + gamestate->checkmate = true; } }