Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not seeing x-ray defenders by calling board.attackers() #1090

Closed
SylviaStout opened this issue Jun 18, 2024 · 3 comments
Closed

Not seeing x-ray defenders by calling board.attackers() #1090

SylviaStout opened this issue Jun 18, 2024 · 3 comments

Comments

@SylviaStout
Copy link

SylviaStout commented Jun 18, 2024

I’m working with checkmate patterns, so one thing is to enumerate the defenders of the adjacent-winning-color-pieces in the pattern.

In the test case below, the losing king would escape checkmate by fleeing (capturing white’s f5-pawn while fleeing). But the f5-pawn is x-ray-defended by white’s f8-rook.

I’m not seeing x-ray defenders by calling board.attackers()

If there is a workaround, please let me know. I totally apologize if I messed up on anything.

The 1st five asserts just verify test-case validity. It’s the last and 6th assert showing the issue (likely too obvious to mention, sorry).

import chess

board = chess.Board()
board.set_epd('5R2/1p4p1/2pK1kPp/3p1P2/3r2nP/8/1P6/8 b - -')

assert board.is_checkmate() is True
winning_color = board.outcome().winner
assert chess.WHITE == winning_color

rook_defending_pawn = board.piece_at(chess.F8)
losing_king = board.piece_at(chess.F6)
pawn_defended_by_rook = board.piece_at(chess.F5)

assert 'R' == board.piece_at(chess.F8).symbol()  # This rook
assert 'k' == board.piece_at(chess.F6).symbol()  # x-rays through this king
assert 'P' == board.piece_at(chess.F5).symbol()  # thereby defending this pawn

f5_pawn_defenders = list(board.attackers(winning_color, chess.F5))
num_f5_pawn_defenders = len(f5_pawn_defenders)  # Debugger shows this value is 0
assert 1 == num_f5_pawn_defenders
@SylviaStout
Copy link
Author

SylviaStout commented Jun 20, 2024

Looking into this a little more, using the excellent lichess puzzle database, I found that of about 997,000 puzzles that end in mate, about 283,000 (28%) hit this issue, but when the x-rayed square is empty. Like a back-rank mate where the king is on g8, and the mating R is on e8, and e8R x-rays right through g8K to prevent K from fleeing onto empty h8.
28% isn't any kind of majority. Non-trivial minority.
It's about 6,400 puzzles that hit this issue when the square being x-rayed is occupied by a win-side piece. Less than 1%, not a lot.

@niklasf
Copy link
Owner

niklasf commented Jul 19, 2024

The behavior of .attackers() is intended as is, but detecting X-ray attacks seems very useful indeed. With 63aac2e it is now possible via:

board.attackers(winning_color, chess.F5, board.occupied ^ board.pieces_mask(chess.KING, board.turn))

With your second comment, do you mean there's a bug in the Lichess puzzle generator missing or misclassifying some positions due to this, or just that this is a common pattern?

@niklasf niklasf closed this as completed Jul 19, 2024
@SylviaStout
Copy link
Author

SylviaStout commented Jul 19, 2024

...do you mean there's a bug in the Lichess puzzle generator missing or misclassifying some positions...
No, I didn't mean to suggest anything about any lichess bug.
I was just surprised to see a data point where these x-rays happened 28 times more frequently with empty x-rayed squares than with occupied x-rayed squares.
Thanks very much for the fix :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants