Skip to content

Commit ad27916

Browse files
committed
Detect impossible check due to en passant
1 parent dd759f2 commit ad27916

3 files changed

Lines changed: 28 additions & 10 deletions

File tree

chess/__init__.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3356,12 +3356,21 @@ def status(self) -> Status:
33563356
# More than the maximum number of possible checkers in the variant.
33573357
checkers = self.checkers_mask()
33583358
our_kings = self.kings & self.occupied_co[self.turn] & ~self.promoted
3359-
if popcount(checkers) > 2:
3360-
errors |= STATUS_TOO_MANY_CHECKERS
3361-
elif popcount(checkers) == 2 and ray(lsb(checkers), msb(checkers)) & our_kings:
3362-
errors |= STATUS_IMPOSSIBLE_CHECK
3363-
elif valid_ep_square is not None and any(ray(checker, valid_ep_square) & our_kings for checker in scan_reversed(checkers)):
3364-
errors |= STATUS_IMPOSSIBLE_CHECK
3359+
if checkers:
3360+
if popcount(checkers) > 2:
3361+
errors |= STATUS_TOO_MANY_CHECKERS
3362+
3363+
if valid_ep_square is not None:
3364+
pushed_to = valid_ep_square ^ A2
3365+
pushed_from = valid_ep_square ^ A4
3366+
occupied_before = (self.occupied & ~BB_SQUARES[pushed_to]) | BB_SQUARES[pushed_from]
3367+
if popcount(checkers) > 1 or (
3368+
msb(checkers) != pushed_to and
3369+
self._attacked_for_king(our_kings, occupied_before)):
3370+
errors |= STATUS_IMPOSSIBLE_CHECK
3371+
else:
3372+
if popcount(checkers) > 2 or (popcount(checkers) == 2 and ray(lsb(checkers), msb(checkers)) & our_kings):
3373+
errors |= STATUS_IMPOSSIBLE_CHECK
33653374

33663375
return errors
33673376

chess/variant.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,8 @@ def status(self) -> chess.Status:
320320
status &= ~chess.STATUS_NO_BLACK_KING
321321
if chess.popcount(self.checkers_mask()) <= 14:
322322
status &= ~chess.STATUS_TOO_MANY_CHECKERS
323-
status &= ~chess.STATUS_IMPOSSIBLE_CHECK
323+
if self._valid_ep_square() is None:
324+
status &= ~chess.STATUS_IMPOSSIBLE_CHECK
324325
return status
325326

326327

@@ -409,7 +410,7 @@ def has_insufficient_material(self, color: chess.Color) -> bool:
409410
def status(self) -> chess.Status:
410411
status = super().status()
411412
if self.is_check():
412-
status |= chess.STATUS_RACE_CHECK | chess.STATUS_TOO_MANY_CHECKERS
413+
status |= chess.STATUS_RACE_CHECK | chess.STATUS_TOO_MANY_CHECKERS | chess.STATUS_IMPOSSIBLE_CHECK
413414
if self.turn == chess.BLACK and all(self.occupied_co[co] & self.kings & chess.BB_RANK_8 for co in chess.COLORS):
414415
status |= chess.STATUS_RACE_OVER
415416
if self.pawns:

test.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,7 @@ def test_status(self):
994994

995995
# Triple check.
996996
board = chess.Board("4k3/5P2/3N4/8/8/8/4R3/4K3 b - - 0 1")
997-
self.assertEqual(board.status(), chess.STATUS_TOO_MANY_CHECKERS)
997+
self.assertEqual(board.status(), chess.STATUS_TOO_MANY_CHECKERS | chess.STATUS_IMPOSSIBLE_CHECK)
998998

999999
# Impossible checker alignment.
10001000
board = chess.Board("3R4/8/q4k2/2B5/1NK5/3b4/8/8 w - - 0 1")
@@ -1675,6 +1675,14 @@ def test_king_captures_unmoved_rook(self):
16751675
board.push(move)
16761676
self.assertEqual(board.fen(), "8/8/8/B2p3Q/2qPp1P1/b7/2P2P1P/4K2k w - - 0 2")
16771677

1678+
def test_impossible_check_due_to_en_passant(self):
1679+
board = chess.Board("rnbqk1nr/bb3p1p/1q2r3/2pPp3/3P4/7P/1PP1NpPP/R1BQKBNR w KQkq c6")
1680+
self.assertEqual(board.status(), chess.STATUS_IMPOSSIBLE_CHECK)
1681+
self.assertEqual(board.ep_square, chess.C6)
1682+
self.assertTrue(board.has_pseudo_legal_en_passant())
1683+
self.assertFalse(board.has_legal_en_passant())
1684+
self.assertEqual(len(list(board.legal_moves)), 2)
1685+
16781686

16791687
class LegalMoveGeneratorTestCase(unittest.TestCase):
16801688

@@ -4279,7 +4287,7 @@ def test_legal_moves_after_end(self):
42794287
def test_racing_kings_status_with_check(self):
42804288
board = chess.variant.RacingKingsBoard("8/8/8/8/R7/8/krbnNB1K/qrbnNBRQ b - - 1 1")
42814289
self.assertFalse(board.is_valid())
4282-
self.assertEqual(board.status(), chess.STATUS_RACE_CHECK | chess.STATUS_TOO_MANY_CHECKERS)
4290+
self.assertEqual(board.status(), chess.STATUS_RACE_CHECK | chess.STATUS_TOO_MANY_CHECKERS | chess.STATUS_IMPOSSIBLE_CHECK)
42834291

42844292

42854293
class HordeTestCase(unittest.TestCase):

0 commit comments

Comments
 (0)