src/chess/rules.h

changeset 163
2a6d83f4677e
parent 161
3ff96fec144a
--- a/src/chess/rules.h	Thu Jul 30 18:34:15 2026 +0200
+++ b/src/chess/rules.h	Thu Jul 30 19:17:38 2026 +0200
@@ -43,7 +43,11 @@
 #define PIECE_PINNED           5
 #define KING_IN_CHECK          6
 #define KING_MOVES_INTO_CHECK  7
-#define RULES_VIOLATED        10
+#define MISSING_CHECK          8
+#define MISSING_CHECKMATE      9
+#define INVALID_CHECK         10
+#define INVALID_CHECKMATE     11
+#define RULES_VIOLATED        32
 
 #define ENPASSANT_THREAT 0x40u
 
@@ -83,7 +87,7 @@
 
 struct movetimeval {
     uint64_t tv_sec;
-    int32_t tv_usec; // important that this is signed b/c potential carry
+    int32_t tv_usec; /* important that this is signed b/c potential carry */
 };
 
 typedef struct {
@@ -92,9 +96,11 @@
     Row fromrow;
     File tofile;
     Row torow;
-    uint8_t promotion;
-    uint8_t check;
+    Piece promotion;
+    uint8_t check; /* must always be set if checkmate is set */
+    uint8_t checkmate;
     uint8_t capture;
+    uint8_t padding[7]; /* necessary for stable ABI across networks */
     struct movetimeval timestamp;
     struct movetimeval movetime;
     char string[8];
@@ -189,7 +195,13 @@
 }
 
 static inline bool is_game_running(const GameState *gamestate) {
-    return !(gamestate->checkmate || gamestate->wresign || gamestate->bresign || gamestate->threefold || gamestate->stalemate || gamestate->remis || gamestate->review);
+    return !(gamestate->checkmate || gamestate->wresign || gamestate->bresign
+        || gamestate->threefold || gamestate->stalemate || gamestate->remis
+        || gamestate->review);
+}
+
+static inline bool is_check_position(const GameState *gamestate) {
+    return gamestate->moves[gamestate->movecount - 1].check;
 }
 
 /**
@@ -242,7 +254,7 @@
  * @param gamestate the current game state
  * @return the color of the player who is next to move
  */
-Color current_color(GameState *gamestate);
+Color current_color(const GameState *gamestate);
 
 /**
  * Returns the piece at the specified position.
@@ -276,7 +288,29 @@
 }
 
 /**
- * Checks, if a specified field is covered by a piece of a certain color.
+ * Determines a list of possible moves to the specified field.
+ *
+ * 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
+ */
+bool get_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
+ * capture an opponent piece on this field, regardless of being pinned.
  * 
  * The out-parameters may both be NULL, but if any of them is set, the other
  * must be set, too.
@@ -285,17 +319,17 @@
  * @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 threaten the field
- * @param threats the array where to store the threats (should be able to hold
- * the rare maximum of 16 elements)
+ * @param threats the array where to store the threats
+ * (must be large enough, 16 is always enough)
  * @param threatcount a pointer where the count of threats is stored
  * @return true, if any piece of the specified color threatens the specified
- * field (i.e. could capture an opponent piece)
+ * field
  */
-bool get_threats(GameState *gamestate, Row row, File file,
+bool get_threats(const GameState *gamestate, Row row, File file,
         Color color, Move* threats, size_t* threatcount);
 
 /**
- * Checks, if a specified field is covered by a piece of a certain color AND
+ * Checks, if a specified field is threatened by a piece of a certain color AND
  * if this piece is not pinned and therefore able to perform the move.
  * 
  * The out-parameters may both be NULL, but if any of them is set, the other
@@ -305,17 +339,20 @@
  * @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 threaten the field
- * @param threats the array where to store the threats (should be able to hold
- * the rare maximum of 16 elements)
+ * @param threats the array where to store the threats
+ * (must be large enough, 16 is always enough)
  * @param threatcount a pointer where the count of threats is stored
  * @return true, if any piece of the specified color threatens the specified
- * field (i.e. could capture an opponent piece)
+ * field and is not pinned
  */
-bool get_real_threats(GameState *gamestate, Row row, File file,
+bool get_real_threats(const GameState *gamestate, Row row, File file,
         Color color, Move* threats, size_t* threatcount);
 
 /**
- * Checks, if a specified field is covered by a piece of a certain color.
+ * 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
+ * capture an opponent piece on this field, regardless of being pinned.
  * 
  * @param gamestate the current game state
  * @param row row of the field to check
@@ -330,7 +367,7 @@
 /**
  * Checks, if a specified field is attacked by a piece of a certain color.
  * 
- * I.e. the field is covered by a piece AND this piece is not pinned and
+ * I.e. the field is threatened by a piece AND this piece is not pinned and
  * therefore able to perform the move.
  * 
  * @param gamestate the current game state
@@ -346,8 +383,8 @@
 /**
  * Checks, if a specified field is protected by a piece of a certain color.
  * 
- * I.e. the field is covered by a piece that is NOT the king AND this piece is
- * not pinned and therefore able to perform the move.
+ * This is the same as is_attacked(), but only considers pieces that are not
+ * the king.
  * 
  * @param gamestate the current game state
  * @param row row of the field to check
@@ -356,7 +393,7 @@
  * @return true, if any piece (excluding the king) of the specified color
  * threatens the specified field and could capture an opponent piece
  */
-bool is_protected(GameState *gamestate, Row row, File file, Color color);
+bool is_protected(const GameState *gamestate, Row row, File file, Color color);
 
 /**
  * Checks, if the specified move cannot be performed, because the piece is
@@ -372,25 +409,51 @@
  * @return true, if the move cannot be performed because the king would be in
  * check after the move
  */
-bool is_pinned(GameState *gamestate, Move *move);
+bool is_pinned(const GameState *gamestate, const Move *move);
 
 /**
  * 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.
+ * evaluating the allowed moves according to the current game state.
+ *
+ * This function expects correct notation of check and checkmate indicators.
+ * For a more lazy evaluation, use eval_move_lazy().
  *
  * 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
+ * @param color the color of the player to evaluate the move for
  * @param move a pointer to object where the move data shall be stored
- * @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 eval_move(GameState *gamestate, const char *mstr, Move *move, Color color);
+int eval_move(const GameState *gamestate,
+    const char *mstr, Color color, Move *move);
+
+/**
+ * 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
+ * evaluating the allowed moves according to the current game state.
+ *
+ * This function automatically corrects missing or incorrect check/checkmate
+ * indicators. Use eval_move() if you want to keep the original notation.
+ *
+ * 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
+ * @param color the color of the player to evaluate the move for
+ * @param move a pointer to object where the move data shall be stored
+ * @return status code (see macros in this file for the list of codes)
+ */
+int eval_move_lazy(const GameState *gamestate,
+    const char *mstr, Color color, Move *move);
 
 /**
  * Syntactically checks a move without verifying that a piece exists that is
@@ -408,7 +471,7 @@
  * @param move the move to validate
  * @return status code (see macros in this file for the list of codes)
  */
-int validate_move(GameState *gamestate, Move *move);
+int validate_move(const GameState *gamestate, const Move *move);
 
 /**
  * Applies a move and deletes captured pieces.
@@ -427,7 +490,7 @@
  * @param move_number the half-move that would now be played
  * @param replay the struct to populate with the state at the specified move
  */
-void gamestate_at_move(GameState *gamestate,
+void gamestate_at_move(const GameState *gamestate,
         unsigned move_number, GameState *replay);
 
 /**
@@ -439,7 +502,7 @@
  * @return the remaining time - if time control is disabled, this function
  * always returns zero
  */
-uint16_t remaining_movetime2(GameState *gamestate, unsigned move_number);
+uint16_t remaining_movetime2(const GameState *gamestate, unsigned move_number);
 
 /**
  * Returns the remaining time on the clock for the specified player.
@@ -449,7 +512,7 @@
  * @return the remaining time - if time control is disabled, this function
  * always returns zero
  */
-uint16_t remaining_movetime(GameState *gamestate, Color color);
+uint16_t remaining_movetime(const GameState *gamestate, Color color);
 
 /**
  * Converts clock time to string.
@@ -472,7 +535,7 @@
  * @param gamestate the current game state
  * @return true if the game is in a threefold repetition position
  */
-bool check_threefold_repetition(GameState *gamestate);
+bool check_threefold_repetition(const GameState *gamestate);
 
 #endif	/* RULES_H */
 

mercurial