fix regression: pieces could not threaten fields when pinned

Sun, 02 Aug 2026 15:08:43 +0200

author
Mike Becker <universe@uap-core.de>
date
Sun, 02 Aug 2026 15:08:43 +0200
changeset 167
fd1d3f0a7a73
parent 166
1a9b662bc201
child 168
663676cfef6e

fix regression: pieces could not threaten fields when pinned

relates to #960

src/chess/rules.c file | annotate | diff | comparison | revisions
src/chess/rules.h file | annotate | diff | comparison | revisions
--- a/src/chess/rules.c	Sat Aug 01 11:26:48 2026 +0200
+++ b/src/chess/rules.c	Sun Aug 02 15:08:43 2026 +0200
@@ -142,6 +142,7 @@
                     piece_color(move->piece), candidates, &ccount)) {
                 unsigned int ambrows = 0, ambfiles = 0, ambpiece = 0;
                 for (size_t i = 0 ; i < ccount ; i++) {
+                    // TODO: check if we need to discard pinned pieces here
                     if (candidates[i].piece == move->piece) {
                         ambpiece++;
                         if (candidates[i].fromrow == move->fromrow) {
@@ -548,11 +549,15 @@
             return INVALID_MOVE_SYNTAX;
     }
 
-    /* cancel processing to save resources */
-    if (!chkrules) {
-        return RULES_VIOLATED;
+    return chkrules ? VALID_MOVE_SEMANTICS : RULES_VIOLATED;
+}
+
+int validate_move(const GameState *gamestate, const Move *move) {
+    int result = validate_move_rules(gamestate, move);
+    if (result != VALID_MOVE_SEMANTICS) {
+        return result;
     }
-    
+
     /* test if the move would expose our own king */
     GameState simulation = gamestate_copy_sim(gamestate);
     Move simmove = *move;
@@ -570,9 +575,7 @@
             }
         }
     }
-    int result = VALID_MOVE_SEMANTICS;
     if (is_covered(&simulation, kingrow, kingfile, oppcolor)) {
-        gamestate_cleanup(&simulation);
         if (piece_type(move->piece) == KING) {
             result = KING_MOVES_INTO_CHECK;
         } else {
@@ -585,15 +588,6 @@
     }
     gamestate_cleanup(&simulation);
 
-    return result;
-}
-
-int validate_move(const GameState *gamestate, const Move *move) {
-    int result = validate_move_rules(gamestate, move);
-    if (result != VALID_MOVE_SEMANTICS) {
-        return result;
-    }
-
     /* validate check and checkmate flags */
     int cocm = determine_check_or_checkmate(gamestate, move);
     if (cocm == 2) {
@@ -609,7 +603,6 @@
     } else if (move->check) {
         return INVALID_CHECK;
     }
-
     
     return VALID_MOVE_SEMANTICS;
 }
@@ -675,6 +668,7 @@
         Color color, Move *threats, size_t *threatcount) {
 
     /* simulate a capturing move on the target position */
+    // TODO: this does NOT disregard the pin, as stated in the spec!
     Color opcolor = opponent_color(color);
     GameState simulation = gamestate_copy_sim(gamestate);
     if (piece_color(piece_at(&simulation, row, file)) != opcolor) {
--- a/src/chess/rules.h	Sat Aug 01 11:26:48 2026 +0200
+++ b/src/chess/rules.h	Sun Aug 02 15:08:43 2026 +0200
@@ -288,7 +288,9 @@
 }
 
 /**
- * Determines a list of possible moves to the specified field.
+ * Determines a list of theoretically possible moves to the specified field.
+ *
+ * This will also list moves for pieces that are actually pinned.
  *
  * The out-parameters may both be NULL, but if any of them is set, the other
  * must be set, too.
@@ -301,7 +303,7 @@
  * (must be large enough, 16 is always enough)
  * @param movecount a pointer where the number of moves is stored
  * @return true, if any piece of the specified color can move to the specified
- * field
+ * field regardless of being pinned
  */
 bool get_candidates(const GameState *gamestate, Row row, File file,
         Color color, Move* moves, size_t* movecount);

mercurial