# HG changeset patch # User Mike Becker # Date 1785676787 -7200 # Node ID 663676cfef6ecbd1dc32ced4ab89c6fcdacdced4 # Parent fd1d3f0a7a7345ea34462a076cdc4594fd87ed25 fix unnecessary disambiguation + simplify get_real_threats() code relates to #932 diff -r fd1d3f0a7a73 -r 663676cfef6e src/chess/rules.c --- 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; diff -r fd1d3f0a7a73 -r 663676cfef6e src/chess/rules.h --- 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