src/chess/rules.c

changeset 139
fa10bee331ac
parent 137
43d1b3c33369
--- a/src/chess/rules.c	Sat Jun 13 13:24:54 2026 +0200
+++ b/src/chess/rules.c	Sat Jun 13 13:45:19 2026 +0200
@@ -264,6 +264,7 @@
     }
 }
 
+// TODO: check if we really need this "simulate" flag for performance
 static void apply_move_impl(GameState *gamestate, Move *move, bool simulate) {
     /* format move before moving (s.t. ambiguities can be resolved) */
     if (!simulate) {
@@ -452,28 +453,44 @@
         bool canescape = false;
         for (int dr = -1 ; dr <= 1 && !canescape ; dr++) {
             for (int df = -1 ; df <= 1 && !canescape ; df++) {
-                if (!(dr == 0 && df == 0)  &&
-                        isidx(opkingrow + dr) && isidx(opkingfile + df)) {
-                    /* escape field neither occupied nor covered */
-                    canescape =
-                        !simulation.board[opkingrow + dr][opkingfile + df] &&
-                        !is_covered(&simulation,
-                            opkingrow + dr, opkingfile + df, piececolor);
+                if (dr == 0 && df == 0) continue;
+                if (!isidx(opkingrow + dr)) continue;
+                if (!isidx(opkingfile + df)) continue;
+                uint8_t er = opkingrow + dr;
+                uint8_t ef = opkingfile + df;
+
+                /* check if escape field is already covered (threatened) */
+                if (is_covered(&simulation, er, ef, piececolor))
+                    continue;
+
+                /* check if piece of the king's color blocks the field */
+                if ((simulation.board[er][ef] & COLOR_MASK) == oppcolor)
+                    continue;
+
+                /* check if an attacking piece blocks the field */
+                if ((simulation.board[er][ef] & COLOR_MASK) == piececolor) {
+                    /* test if the king can fight back */
+                    GameState sim_retaliate = gamestate_copy_sim(&simulation);
+                    Move move_retaliate = {0};
+                    move_retaliate.piece = (oppcolor|KING);
+                    move_retaliate.fromrow = opkingrow;
+                    move_retaliate.fromfile = opkingfile;
+                    move_retaliate.torow = er;
+                    move_retaliate.tofile = ef;
+                    move_retaliate.capture = 1;
+                    apply_move_impl(&sim_retaliate, &move_retaliate, true);
+                    canescape = !is_covered(&sim_retaliate, er, ef, piececolor);
+                    gamestate_cleanup(&sim_retaliate);
+                } else {
+                    /* the field is not covered and unoccupied */
+                    canescape = true;
                 }
             }
         }
-        /* can't escape, can he capture? */
+
+        /* can't escape, can the king be rescued? */
         if (!canescape && threatcount == 1) {
-            /* 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,
+            canescape = is_protected(&simulation,
                     threats[0].fromrow, threats[0].fromfile, oppcolor);
         }
         

mercurial