relax validation of premoves to allow retaking pieces

Tue, 28 Apr 2026 12:25:48 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 28 Apr 2026 12:25:48 +0200
changeset 115
206201d544be
parent 114
12df1b7c792f
child 116
4bf18d42e7ee

relax validation of premoves to allow retaking pieces

fixes #832

src/chess/rules.c file | annotate | diff | comparison | revisions
src/chess/rules.h file | annotate | diff | comparison | revisions
src/game.c file | annotate | diff | comparison | revisions
--- a/src/chess/rules.c	Mon Apr 27 18:06:00 2026 +0200
+++ b/src/chess/rules.c	Tue Apr 28 12:25:48 2026 +0200
@@ -633,7 +633,7 @@
     }
 }
 
-int eval_move(GameState *gamestate, char *mstr, Move *move, uint8_t color) {
+static int eval_move1(char *mstr, Move *move, uint8_t color) {
     memset(move, 0, sizeof(Move));
     move->fromfile = POS_UNSPECIFIED;
     move->fromrow = POS_UNSPECIFIED;
@@ -745,23 +745,41 @@
     }
 
     
-    if (move->piece) {
-        if (move->piece == PAWN
-            && move->torow == (color==WHITE?7:0)
-            && !move->promotion) {
-            return NEED_PROMOTION;
-        }
-        
-        move->piece |= color;
+    if (!move->piece) {
+        return INVALID_MOVE_SYNTAX;
+    }
+
+    if (move->piece == PAWN
+        && move->torow == (color==WHITE?7:0)
+        && !move->promotion) {
+        return NEED_PROMOTION;
+    }
+
+    move->piece |= color;
+
+    if (!chkidx_to(move)) {
+        return INVALID_POSITION;
+    }
+
+    return VALID_MOVE_SYNTAX;
+}
+
+int eval_move(GameState *gamestate, char *mstr, Move *move, uint8_t color) {
+    int result = eval_move1(mstr, move, color);
+    if (result == VALID_MOVE_SYNTAX) {
         if (move->fromfile == POS_UNSPECIFIED
             || move->fromrow == POS_UNSPECIFIED) {
             return getlocation(gamestate, move);
-        } else {
-            return chkidx(move) ? VALID_MOVE_SYNTAX : INVALID_POSITION;
+        } else if (!chkidx_from(move)) {
+            return INVALID_POSITION;
         }
-    } else {
-        return INVALID_MOVE_SYNTAX;
     }
+    return result;
+}
+
+int check_move(char *mstr, uint8_t color) {
+    Move move;
+    return eval_move1(mstr, &move, color);
 }
 
 bool is_protected(GameState *gamestate, uint8_t row, uint8_t file,
--- a/src/chess/rules.h	Mon Apr 27 18:06:00 2026 +0200
+++ b/src/chess/rules.h	Tue Apr 28 12:25:48 2026 +0200
@@ -63,8 +63,9 @@
 #define rowchr(row) (row+'1')
 #define filechr(file) (file+'a')
 
-#define chkidx(move) (isidx((move)->fromfile) && isidx((move)->fromrow) && \
-        isidx((move)->tofile) && isidx((move)->torow))
+#define chkidx_from(move) (isidx((move)->fromfile) && isidx((move)->fromrow))
+#define chkidx_to(move) (isidx((move)->tofile) && isidx((move)->torow))
+#define chkidx(move) (chkidx_from(move) && chkidx_to(move))
 
 /* secure versions - use, if index is not checked with isidx() */
 #define fileidx_s(c) (isfile(c)?fileidx(c):POS_UNSPECIFIED)
@@ -206,6 +207,12 @@
 /**
  * Evaluates a move syntactically and stores the move data in the specified
  * object.
+ *
+ * When short algebraic notation is used, the source position is determined by
+ * the evaluating the allowed moves according to the current game state.
+ *
+ * For a purely syntactic check, regardless of whether a piece exists that is
+ * allowed to move that way, use check_move().
  * 
  * @param gamestate the current game state
  * @param mstr the input string to parse
@@ -216,6 +223,16 @@
 int eval_move(GameState *gamestate, char *mstr, Move *move, uint8_t color);
 
 /**
+ * Syntactically checks a move without verifying that a piece exists that is
+ * allowed to move that way.
+ *
+ * @param mstr the input string to parse
+ * @param color the color of the player to evaluate the move for
+ * @return status code (see macros in this file for the list of codes)
+ */
+int check_move(char *mstr, uint8_t color);
+
+/**
  * Validates move by applying chess rules.
  * @param gamestate the current game state
  * @param move the move to validate
--- a/src/game.c	Mon Apr 27 18:06:00 2026 +0200
+++ b/src/game.c	Tue Apr 28 12:25:48 2026 +0200
@@ -478,8 +478,7 @@
             } else if (movestr[0] == 0) {
                 memset(gamestate->premove, 0, sizeof(gamestate->premove));
             } else {
-                Move move;
-                int res = eval_move(gamestate, movestr, &move, mycolor);
+                int res = check_move(movestr, mycolor);
                 if (res == VALID_MOVE_SYNTAX) {
                     strncpy(gamestate->premove, movestr, 8);
                     memset(movestr, 0, MOVESTR_BUFLEN);

mercurial