fix unnecessary disambiguation + simplify get_real_threats() code default tip

Sun, 02 Aug 2026 15:19:47 +0200

author
Mike Becker <universe@uap-core.de>
date
Sun, 02 Aug 2026 15:19:47 +0200
changeset 168
663676cfef6e
parent 167
fd1d3f0a7a73

fix unnecessary disambiguation + simplify get_real_threats() code

relates to #932

src/chess/rules.c file | annotate | diff | comparison | revisions
src/chess/rules.h file | annotate | diff | comparison | revisions
--- a/src/chess/rules.c	Sun Aug 02 15:08:43 2026 +0200
+++ b/src/chess/rules.c	Sun Aug 02 15:19:47 2026 +0200
@@ -138,11 +138,10 @@
             /* resolve ambiguities, if any */
             Move candidates[16];
             size_t ccount;
-            if (get_candidates(gamestate, move->torow, move->tofile,
+            if (get_real_candidates(gamestate, move->torow, move->tofile,
                     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) {
@@ -668,7 +667,6 @@
         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) {
@@ -730,7 +728,7 @@
     Row kingrow = 0;
     for (Row row = 0 ; row < 8 ; row++) {
         for (File file = 0 ; file < 8 ; file++) {
-            if (simulation.board[row][file] == (color|KING)) {
+            if (piece_at(&simulation, row, file) == mkpiece(KING, color)) {
                 kingfile = file;
                 kingrow = row;
             }
@@ -744,6 +742,31 @@
     return covered;
 }
 
+bool get_real_candidates(const GameState *gamestate, Row row, File file,
+        Color color, Move *moves, size_t *movecount) {
+
+    if (movecount) {
+        *movecount = 0;
+    }
+
+    Move candidates[16];
+    size_t ccount;
+    if (get_candidates(gamestate, row, file, color, candidates, &ccount)) {
+        bool result = false;
+        for (size_t i = 0 ; i < ccount ; i++) {
+            if (!is_pinned(gamestate, &candidates[i])) {
+                result = true;
+                if (moves && movecount) {
+                    moves[(*movecount)++] = candidates[i];
+                }
+            }
+        }
+        return result;
+    } else {
+        return false;
+    }
+}
+
 bool get_real_threats(const GameState *gamestate, Row row, File file,
         Color color, Move *threats, size_t *threatcount) {
     
@@ -752,36 +775,17 @@
     }
 
     Move candidates[16];
-    size_t candidatecount;
-    if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) {
-        
+    size_t ccount;
+    if (get_threats(gamestate, row, file, color, candidates, &ccount)) {
         bool result = false;
-        File kingfile = 0;
-        Row kingrow = 0;
-        for (Row r = 0 ; r < 8 ; r++) {
-            for (File f = 0 ; f < 8 ; f++) {
-                if (gamestate->board[r][f] == (color|KING)) {
-                    kingfile = f;
-                    kingrow = r;
-                }
-            }
-        }
-
-        for (size_t i = 0 ; i < candidatecount ; i++) {
-            // TODO: check if we really need full-blown simulations here
-            GameState simulation = gamestate_copy_sim(gamestate);
-            Move simmove = candidates[i];
-            apply_move(&simulation, &simmove);
-            if (!is_covered(&simulation, kingrow, kingfile,
-                    opponent_color(color))) {
+        for (size_t i = 0 ; i < ccount ; i++) {
+            if (!is_pinned(gamestate, &candidates[i])) {
                 result = true;
                 if (threats && threatcount) {
                     threats[(*threatcount)++] = candidates[i];
                 }
             }
-            gamestate_cleanup(&simulation);
         }
-        
         return result;
     } else {
         return false;
--- a/src/chess/rules.h	Sun Aug 02 15:08:43 2026 +0200
+++ b/src/chess/rules.h	Sun Aug 02 15:19:47 2026 +0200
@@ -291,6 +291,7 @@
  * Determines a list of theoretically possible moves to the specified field.
  *
  * This will also list moves for pieces that are actually pinned.
+ * Use get_real_candidates() to get only moves for pieces that are not pinned.
  *
  * The out-parameters may both be NULL, but if any of them is set, the other
  * must be set, too.
@@ -309,6 +310,29 @@
         Color color, Move* moves, size_t* movecount);
 
 /**
+ * Determines a list of possible moves to the specified field.
+ *
+ * This cannot be used to check if a piece covers / threatens a field because
+ * this is also possible when the piece is pinned. Use get_candidates() for a
+ * list of possible moves regardless of pins.
+ *
+ * The out-parameters may both be NULL, but if any of them is set, the other
+ * must be set, too.
+ *
+ * @param gamestate the current game state
+ * @param row row of the field to check
+ * @param file file of the field to check
+ * @param color the color of the piece that should move to the field
+ * @param moves the array where to store the moves
+ * (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 and is not pinned
+ */
+bool get_real_candidates(const GameState *gamestate, Row row, File file,
+        Color color, Move* moves, size_t* movecount);
+
+/**
  * Checks, if a specified field is threatened by a piece of a certain color.
  *
  * A field is threatened, if there is a piece of the specified color that could

mercurial