3

I want to read a PGN file and play those moves on my chess application. For example, the PGN structure that I have to read looks like this:

1. e4 {[%clk 0:01:00]} 1... g6 {[%clk 0:01:00]} 
2. e5 {[%clk 0:00:59.2]} 2... Bg7 {[%clk 0:00:59.9]} 
3. f4 {[%clk 0:00:58.4]} 3... d6 {[%clk 0:00:59.8]}

So the first move is e4 by white. As human I can look at a chess board and tell that the only piece that can go to e4 is the pawn currently on e2.

But how do you know this when reading a PGN file?

I need to feed my chess applications moves like e2-e4. As in, what ever piece is on e2, move it to e4. (By the notation I can at least tell that the piece is a pawn)

So basically I need to know the starting position of the piece e2, and on what square it wants to land, e4.

Is there a way to get this information from a PGN file? The only way I can think of is brute forcing to identify the only piece that can move to the location.

3 Answers 3

7

You can use a python chess library to parse the moves of a game in a pgn file.

Code

"""
pip install chess
"""

import chess.pgn

def parse_pgn(inpgn):
    with open(inpgn, encoding='utf-8') as h:
        while True:
            game = chess.pgn.read_game(h)
            if game is None:
                break

            for node in game.mainline():
                move = node.move 
                pnode = node.parent
                board = pnode.board()

                move_from_sq = move.from_square
                move_to_sq = move.to_square

                print(board)
                print(board.fen())
                print(f'move: {move}')
                print(f'move_from: {move_from_sq}')
                print(f'move_from_name: {chess.SQUARE_NAMES[move_from_sq]}')
                print(f'move_to: {move_to_sq}')
                print(f'move_to_name: {chess.SQUARE_NAMES[move_to_sq]}')
                print(f'{chess.SQUARE_NAMES[move_from_sq]}-{chess.SQUARE_NAMES[move_to_sq]}')
                print(f'piece: {board.piece_at(move.from_square).symbol()}')
                print()

def main():
    inpgn = 'sample.pgn'
    parse_pgn(inpgn)

main()

sample.pgn

[Result "*"]

1. e4 {[%clk 0:01:00]} 1... g6 {[%clk 0:01:00]} 
2. e5 {[%clk 0:00:59.2]} 2... Bg7 {[%clk 0:00:59.9]} 
3. f4 {[%clk 0:00:58.4]} 3... d6 {[%clk 0:00:59.8]}

Sample output

r n b q k b n r
p p p p p p p p
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
P P P P P P P P
R N B Q K B N R
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
move: e2e4
move_from: 12
move_from_name: e2
move_to: 28
move_to_name: e4
e2-e4
piece: P

r n b q k b n r
p p p p p p p p
. . . . . . . .
. . . . . . . .
. . . . P . . .
. . . . . . . .
P P P P . P P P
R N B Q K B N R
rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1
move: g7g6
move_from: 54
move_from_name: g7
move_to: 46
move_to_name: g6
g7-g6
piece: p

r n b q k b n r
p p p p p p . p
. . . . . . p .
. . . . . . . .
. . . . P . . .
. . . . . . . .
P P P P . P P P
R N B Q K B N R
rnbqkbnr/pppppp1p/6p1/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 2
move: e4e5
move_from: 28
move_from_name: e4
move_to: 36
move_to_name: e5
e4-e5
piece: P

r n b q k b n r
p p p p p p . p
. . . . . . p .
. . . . P . . .
. . . . . . . .
. . . . . . . .
P P P P . P P P
R N B Q K B N R
rnbqkbnr/pppppp1p/6p1/4P3/8/8/PPPP1PPP/RNBQKBNR b KQkq - 0 2
move: f8g7
move_from: 61
move_from_name: f8
move_to: 54
move_to_name: g7
f8-g7
piece: b

r n b q k . n r
p p p p p p b p
. . . . . . p .
. . . . P . . .
. . . . . . . .
. . . . . . . .
P P P P . P P P
R N B Q K B N R
rnbqk1nr/ppppppbp/6p1/4P3/8/8/PPPP1PPP/RNBQKBNR w KQkq - 1 3
move: f2f4
move_from: 13
move_from_name: f2
move_to: 29
move_to_name: f4
f2-f4
piece: P

r n b q k . n r
p p p p p p b p
. . . . . . p .
. . . . P . . .
. . . . . P . .
. . . . . . . .
P P P P . . P P
R N B Q K B N R
rnbqk1nr/ppppppbp/6p1/4P3/5P2/8/PPPP2PP/RNBQKBNR b KQkq - 0 3
move: d7d6
move_from: 51
move_from_name: d7
move_to: 43
move_to_name: d6
d7-d6
piece: p

Square 0 starts at lower left corner of the board or square a1.

1
  • 2
    Since OP wants "e2-e4", it might be nice to include the square names in the output instead of the square numbers: e.g.: move.square_name(move.from_square) Commented Mar 3, 2022 at 12:32
1

I'm confused by this statement:

I need to feed my chess applications moves like e2-e4.

Why? Computers that can read pgn files will understand the moves as they are formated.

If you're inputting them manually, the notation works fine too. People play entire games blindfolded on the same notation. As the you go down the list of moves, the next move is played based on the state of the board from the previous move. That is how algebraic lines have always worked.

-1

PGN files are intended to be read and used by computer programs, not humans. So, yes, the only way to do what you're asking is to brute-force search to make sure there's only one piece that can reach the destination square.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.