python-chess icon indicating copy to clipboard operation
python-chess copied to clipboard

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

Open SylviaStout opened this issue 1 year ago • 1 comments

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 avatar Jun 18 '24 14:06 SylviaStout

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.

SylviaStout avatar Jun 20 '24 01:06 SylviaStout

The behavior of .attackers() is intended as is, but detecting X-ray attacks seems very useful indeed. With 63aac2ec65860a64256a190220b793e80b132b50 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 avatar Jul 19 '24 14:07 niklasf

...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 :-)

SylviaStout avatar Jul 19 '24 15:07 SylviaStout