Skip to content

Commit 29a1477

Browse files
committed
Introduce is_irreversible
1 parent 59b92cb commit 29a1477

4 files changed

Lines changed: 30 additions & 10 deletions

File tree

chess/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2820,6 +2820,20 @@ def is_zeroing(self, move):
28202820
"""Checks if the given pseudo-legal move is a capture or pawn move."""
28212821
return BB_SQUARES[move.from_square] & self.pawns or BB_SQUARES[move.to_square] & self.occupied_co[not self.turn]
28222822

2823+
def is_irreversible(self, move):
2824+
"""
2825+
Checks if the given pseudo-legal move is irreversible.
2826+
2827+
In standard chess pawn moves, captures and moves that destroy castling
2828+
rights are irreversible.
2829+
"""
2830+
backrank = BB_RANK_1 if self.turn == WHITE else BB_RANK_8
2831+
castling_rights = self.clean_castling_rights() & backrank
2832+
return (self.is_zeroing(move) or
2833+
castling_rights and BB_SQUARES[move.from_square] & self.kings & ~self.promoted or
2834+
castling_rights & BB_SQUARES[move.from_square] or
2835+
castling_rights & BB_SQUARES[move.to_square])
2836+
28232837
def is_castling(self, move):
28242838
"""Checks if the given pseudo-legal move is a castling move."""
28252839
if self.kings & BB_SQUARES[move.from_square]:

chess/uci.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,7 @@ def position(self, board, async_callback=None):
10941094
move = board.pop()
10951095
switchyard.append(move)
10961096

1097-
if board.is_zeroing(move):
1097+
if board.is_irreversible(move):
10981098
break
10991099

11001100
# Validate castling rights.

chess/variant.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -684,8 +684,12 @@ def can_claim_fifty_moves(self):
684684
def is_seventyfive_moves(self):
685685
return False
686686

687-
def is_zeroing(self, move):
688-
return False
687+
def is_irreversible(self, move):
688+
backrank = chess.BB_RANK_1 if self.turn == chess.WHITE else chess.BB_RANK_8
689+
castling_rights = self.clean_castling_rights() & backrank
690+
return (castling_rights and chess.BB_SQUARES[move.from_square] & self.kings & ~self.promoted or
691+
castling_rights & chess.BB_SQUARES[move.from_square] or
692+
castling_rights & chess.BB_SQUARES[move.to_square])
689693

690694
def legal_drop_squares_mask(self):
691695
king = self.king(self.turn)

test.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3123,7 +3123,7 @@ def test_lichess_pgn(self):
31233123
with open("data/pgn/saturs-jannlee-zh-lichess.pgn") as pgn:
31243124
game = chess.pgn.read_game(pgn)
31253125
final_board = game.end().board()
3126-
self.assertEqual(final_board.fen(), "r4r2/ppp2ppk/pb1p1pNp/K2NpP2/3qn3/1B3b2/PP5P/8[QRRBNPP] w - - 122 62")
3126+
self.assertEqual(final_board.fen(), "r4r2/ppp2ppk/pb1p1pNp/K2NpP2/3qn3/1B3b2/PP5P/8[QRRBNPP] w - - 8 62")
31273127
self.assertTrue(final_board.is_valid())
31283128

31293129
with open("data/pgn/knightvuillaume-jannlee-zh-lichess.pgn") as pgn:
@@ -3135,21 +3135,23 @@ def test_pawns_in_pocket(self):
31353135
board.push_san("d4")
31363136
board.push_san("exd4")
31373137
board.push_san("cxd4")
3138-
self.assertEqual(board.fen(), "r2q1rk1/ppp2pp1/1bnp3p/3B4/3PP1b1/4PN2/PP4PP/R2Q1RK1[BNPnp] b - - 25 13")
3138+
self.assertEqual(board.fen(), "r2q1rk1/ppp2pp1/1bnp3p/3B4/3PP1b1/4PN2/PP4PP/R2Q1RK1[BNPnp] b - - 0 13")
31393139
board.push_san("@e6")
3140-
self.assertEqual(board.fen(), "r2q1rk1/ppp2pp1/1bnpp2p/3B4/3PP1b1/4PN2/PP4PP/R2Q1RK1[BNPn] w - - 26 14")
3140+
self.assertEqual(board.fen(), "r2q1rk1/ppp2pp1/1bnpp2p/3B4/3PP1b1/4PN2/PP4PP/R2Q1RK1[BNPn] w - - 1 14")
31413141

31423142
def test_capture(self):
31433143
board = chess.variant.CrazyhouseBoard("4k3/8/8/1n6/8/3B4/8/4K3 w - - 0 1")
31443144
board.push_san("Bxb5+")
3145-
self.assertEqual(board.fen(), "4k3/8/8/1B6/8/8/8/4K3[N] b - - 1 1")
3145+
self.assertEqual(board.fen(), "4k3/8/8/1B6/8/8/8/4K3[N] b - - 0 1")
31463146
board.pop()
31473147
self.assertEqual(board.fen(), "4k3/8/8/1n6/8/3B4/8/4K3[] w - - 0 1")
31483148

31493149
def test_capture_with_promotion(self):
31503150
board = chess.variant.CrazyhouseBoard("4k3/8/8/8/8/8/1p6/2R1K3 b - - 0 1")
3151-
board.push_san("bxc1=Q")
3152-
self.assertEqual(board.fen(), "4k3/8/8/8/8/8/8/2q~1K3[r] w - - 1 2")
3151+
move = board.parse_san("bxc1=Q")
3152+
self.assertFalse(board.is_irreversible(move))
3153+
board.push(move)
3154+
self.assertEqual(board.fen(), "4k3/8/8/8/8/8/8/2q~1K3[r] w - - 0 2")
31533155
board.pop()
31543156
self.assertEqual(board.fen(), "4k3/8/8/8/8/8/1p6/2R1K3[] b - - 0 1")
31553157

@@ -3188,7 +3190,7 @@ def test_push_pop_ep(self):
31883190
fen = "rnbqkb1r/ppp1pppp/5n2/3pP3/8/8/PPPP1PPP/RNBQKBNR[] w KQkq d6 0 3"
31893191
board = chess.variant.CrazyhouseBoard(fen)
31903192
board.push_san("exd6")
3191-
self.assertEqual(board.fen(), "rnbqkb1r/ppp1pppp/3P1n2/8/8/8/PPPP1PPP/RNBQKBNR[P] b KQkq - 1 3")
3193+
self.assertEqual(board.fen(), "rnbqkb1r/ppp1pppp/3P1n2/8/8/8/PPPP1PPP/RNBQKBNR[P] b KQkq - 0 3")
31923194
self.assertEqual(board.pop(), chess.Move.from_uci("e5d6"))
31933195
self.assertEqual(board.fen(), fen)
31943196

0 commit comments

Comments
 (0)