Slice of a game between two moves
Hello,
First of all, thank you for this great python library!
My problem is simple: I would like to extract a subgame between the $i$-th move and the $j$-th move.
For example, if the PGN is: 1. e4 e5 2. Nf3 (2. Nc3 d6) 2... d5 3. a4 a5 4. b4 b5, I want to extract a slice between the second move for White (2. Nf3) and the third move for Black (3... a5), so to obtain 2. Nf3 (2. Nc3 d6) 2... d5 3. a4 a5.
I was able to print all the moves in between with a subclass of Visitor (*) but I don't know how to preserve the right numbering? I'm trying to use visit_board and board.fullmove_number but I suppose I need to restore the board as mentioned in the doc:
The board state must be restored before the traversal continues.
How can I fix it?
(*) Actually the code below is not completely satisfying since we could have repeated moves... that's why I'm actually looking for all the moves between two nodes in the main line.
import io
import chess
import chess.pgn
class SubPartVisitor(chess.pgn.BaseVisitor):
def __init__(self, start_move, end_move):
self.start_move = start_move
self.end_move = end_move
self.moves = []
self.in_subpart = False
self.numbering = 0
def visit_move(self, board, move):
if not self.in_subpart and move == self.start_move:
self.in_subpart = True
self.numbering = 1
if self.in_subpart:
move_str = f"{self.numbering}. {board.san(move)}"
self.moves.append(move_str)
if move == self.end_move:
self.in_subpart = False
return False
def begin_variation(self):
self.moves.append("(")
def end_variation(self):
self.moves.append(")")
def visit_board(self, board):
self.numbering = board.fullmove_number
def result(self):
return self.moves
if __name__ == "__main__":
pgn_text = "1. e4 e5 2. Nf3 (2. Nc3 d6) 2... d5 3. a4 a5 4. b4 b5"
start_move = chess.Move.from_uci("g1f3") # 2. Nf3
end_move = chess.Move.from_uci("a7a5") # 3. a5
pgn = io.StringIO(pgn_text)
game = chess.pgn.read_game(pgn)
subpart_visitor = SubPartVisitor(start_move, end_move)
game.accept(subpart_visitor)
moves_in_subpart = subpart_visitor.result()
print(" ".join(moves_in_subpart))
Output: 1. Nf3 ( 2. Nc3 2. d6 ) 3. d5 3. a4 3. a5
Otherwise I found a way to visit recursively the nodes as follows:
def traverse(node):
while node:
board = node.board()
if len(node.variations)==1:
if node.turn()==False:
print(str(board.fullmove_number) + '.')
print(node.san())
else:
print(node.san())
for child in node.variations[1:]:
node = node.next()
board = node.board()
print(board.fullmove_number)
print(node.san())
print("(")
traverse(child)
print(")")
node = node.next()
The structure is OK but I have also a problem with the numbering...