使用Python中的国际象棋库从 PGN 文件中提取数据
在本文中,我们将了解如何使用Python中的国际象棋库从 PGN 文件中提取数据。
借助Python中的国际象棋库,我们可以执行多种操作,例如验证移动、提取数据,甚至在棋盘上移动。在本文中,我们将使用 python-chess 库从 PGN 文件或 PGN字符串中提取数据。
安装库:在命令提示符下输入以下命令。
pip install chess
什么是 PGN 文件?
PGN 代表便携式游戏符号。它是一种标准格式,用于记录棋手在棋局中的走法。通过使用 PGN 格式,我们可以将游戏动作记录并存储在常规文本文件中。
每当我们在 https://chess.com 或 https://lichess.org 等热门网站上在线下棋时,这些网站都会自动生成我们游戏的 PGN 文件。我们将来可以使用这些文件来观看和分析我们的游戏。我们将使用这些 PGN 文件,以便使用Python中的国际象棋库从我们的国际象棋游戏中提取数据。
让我们看一下 PGN 文件的内容,以便了解文件的内容。
[Event "Live Chess"]
[Site "Chess.com"]
[Date "2021.08.05"]
[Round "-"]
[White "urvishmhjn"]
[Black "yannickhs"]
[Result "1-0"]
[CurrentPosition "r1b1q1r1/p2nbk2/4pp1Q/1p1p3B/2pP3N/1PP1P3/P4PPP/R4RK1 b - -"]
[Timezone "UTC"]
[ECO "A45"]
[UTCDate "2021.08.05"]
[UTCTime "09:25:32"]
[WhiteElo "1220"]
[BlackElo "1140"]
[TimeControl "900+10"]
[Termination "urvishmhjn won by resignation"]
1. d4 Nf6 2. Bf4 e6 3. e3 d5 4. Bd3 c5 5. c3 c4 6. Be2 Nc6
7. Nf3 Be7 8. Nbd2 O-O 9. O-O Nh5 10. Be5 Nxe5 11. Nxe5 Nf6
12. b3 b5 13. Qc2 Nd7 14. Ndf3 f6 15. Ng4 h5 16. Nh6+ gxh6
17. Qg6+ Kh8 18. Qxh6+ Kg8 19. Qxh5 Qe8 20. Qg4+ Kf7
21. Nh4 Rg8 22. Qh5+ Kf8 23. Qh6+ Kf7 24. Bh5+ 1-0
在上面的文件中,我们可以看到一些文本写在方括号内。这些方括号称为标签对。标签对中的内容为我们提供了有关游戏和玩游戏的玩家的基本信息。例如,标签对告诉我们每个玩家的用户名、玩游戏的日期、游戏的时间格式、赢得游戏的玩家等等。
我们还可以看到没有方括号的文本。此文本表示每个玩家所玩的动作。数字1.、2.、3 . 等表示移动编号。文本d4、Nf6、Bh+等是表示棋盘上棋子移动的标准方式。文件末尾的文本1-0表示白方赢得了比赛。 0-1表示黑方获胜,1/2-1/2表示平局。
执行
现在我们了解了 PGN 文件是什么,我们将导入国际象棋库并调用Board()函数来创建虚拟棋盘。
我们还需要导入chess.pgn来对 pgn 文件/字符串执行操作。
Python3
import chess
import chess.pgn
# creating a virtual chessboard
board = chess.Board()
print(board)
Python3
# We need to convert the PGN string into a StringIO object
# to use a string in python-chess
from io import StringIO
# Paste your PGN string here
pgn_string = """[Event "Live Chess"]
[Site "Chess.com"]
[Date "2021.08.05"]
[Round "-"]
[White "urvishmhjn"]
[Black "yannickhs"]
[Result "1-0"]
[CurrentPosition "r1b1q1r1/p2nbk2/4pp1Q/1p1p3B/2pP3N/1PP1P3/P4PPP/R4RK1 b - -"]
[Timezone "UTC"]
[ECO "A45"]
[UTCDate "2021.08.05"]
[UTCTime "09:25:32"]
[WhiteElo "1220"]
[BlackElo "1140"]
[TimeControl "900+10"]
[Termination "urvishmhjn won by resignation"]
1. d4 Nf6 2. Bf4 e6 3. e3 d5 4. Bd3 c5 5. c3 c4 6. Be2 Nc6
7. Nf3 Be7 8. Nbd2 O-O 9. O-O Nh5 10. Be5 Nxe5 11. Nxe5 Nf6
12. b3 b5 13. Qc2 Nd7 14. Ndf3 f6 15. Ng4 h5 16. Nh6+ gxh6
17. Qg6+ Kh8 18. Qxh6+ Kg8 19. Qxh5 Qe8 20. Qg4+ Kf7
21. Nh4 Rg8 22. Qh5+ Kf8 23. Qh6+ Kf7 24. Bh5+ 1-0
"""
# Converting the string into StringIO object
pgn = StringIO(pgn_string)
# Reading the game
game = chess.pgn.read_game(pgn)
Python3
# username of the player playing with white
white_username = game.headers['White']
# username of the player playing with black
black_username = game.headers['Black']
time_control = game.headers['TimeControl']
# time format of the game
# who won the game
game_result = game.headers['Result']
# Make sure that each header name
# used above is present in the PGN
print("White's chess.com Username:", white_username)
print("Black's chess.com Username:", black_username)
print("Game's Time Control:", time_control, "seconds")
print("Game Result:", game_result)
# If white wins: 1-0
# If black wins: 0-1
# If game drawn: 1/2-1/2
Python3
# The move number for which we want the FEN
move_number = 8
# Go through each move in the game until
# we reach the required move number
for number, move in enumerate(game.mainline_moves()):
# It copies the move played by each
# player on the virtual board
board.push(move)
# Remember that number starts from 0
if number == move_number:
break
fen = board.fen()
print(fen)
Python3
print(board)
Python3
display(board)
输出:
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
如果您有要从中提取数据的.pgn文件,请使用以下代码。如果您在上述网站下棋,您可以从这些网站下载您游戏的 PGN 文件。
pgn = open(“your-pgn-file.pgn”) # opening the file in python
game = chess.pgn.read_game(pgn) # reading the game present in file
如果您有一个包含 pgn 文件数据的字符串,则需要将该字符串转换为StringIO对象,因为国际象棋库仅支持StringIO对象。您可以使用以下代码。
Python3
# We need to convert the PGN string into a StringIO object
# to use a string in python-chess
from io import StringIO
# Paste your PGN string here
pgn_string = """[Event "Live Chess"]
[Site "Chess.com"]
[Date "2021.08.05"]
[Round "-"]
[White "urvishmhjn"]
[Black "yannickhs"]
[Result "1-0"]
[CurrentPosition "r1b1q1r1/p2nbk2/4pp1Q/1p1p3B/2pP3N/1PP1P3/P4PPP/R4RK1 b - -"]
[Timezone "UTC"]
[ECO "A45"]
[UTCDate "2021.08.05"]
[UTCTime "09:25:32"]
[WhiteElo "1220"]
[BlackElo "1140"]
[TimeControl "900+10"]
[Termination "urvishmhjn won by resignation"]
1. d4 Nf6 2. Bf4 e6 3. e3 d5 4. Bd3 c5 5. c3 c4 6. Be2 Nc6
7. Nf3 Be7 8. Nbd2 O-O 9. O-O Nh5 10. Be5 Nxe5 11. Nxe5 Nf6
12. b3 b5 13. Qc2 Nd7 14. Ndf3 f6 15. Ng4 h5 16. Nh6+ gxh6
17. Qg6+ Kh8 18. Qxh6+ Kg8 19. Qxh5 Qe8 20. Qg4+ Kf7
21. Nh4 Rg8 22. Qh5+ Kf8 23. Qh6+ Kf7 24. Bh5+ 1-0
"""
# Converting the string into StringIO object
pgn = StringIO(pgn_string)
# Reading the game
game = chess.pgn.read_game(pgn)
我们已经定义了一个名为game 的变量。它包含有关整个游戏的信息。
现在让我们来了解一下游戏的一些细节。
Python3
# username of the player playing with white
white_username = game.headers['White']
# username of the player playing with black
black_username = game.headers['Black']
time_control = game.headers['TimeControl']
# time format of the game
# who won the game
game_result = game.headers['Result']
# Make sure that each header name
# used above is present in the PGN
print("White's chess.com Username:", white_username)
print("Black's chess.com Username:", black_username)
print("Game's Time Control:", time_control, "seconds")
print("Game Result:", game_result)
# If white wins: 1-0
# If black wins: 0-1
# If game drawn: 1/2-1/2
输出:
White's chess.com Username: urvishmhjn
Black's chess.com Username: yannickhs
Game's Time Control: 900+10 seconds
Game Result: 1-0
我们可以使用以下代码在游戏中的任何位置获取FEN (FEN 是一种文本符号,用于显示游戏中任何给定时刻每个棋子的位置)。
Python3
# The move number for which we want the FEN
move_number = 8
# Go through each move in the game until
# we reach the required move number
for number, move in enumerate(game.mainline_moves()):
# It copies the move played by each
# player on the virtual board
board.push(move)
# Remember that number starts from 0
if number == move_number:
break
fen = board.fen()
print(fen)
输出:
r1bq1rk1/pp2bppp/4p3/3pn2n/2pP4/2P1PN2/PP1NBPPP/R2Q1RK1 w – – 0 11
如果你想可视化棋盘,你可以在终端上打印棋盘。
Python3
print(board)
输出:
r n b q k b . r
p p . . . p p p
. . . . p n . .
. . p p . . . .
. . . P . B . .
. . P B P . . .
P P . . . P P P
R N . Q K . N R
注意:如果您想要真正可视化棋盘,而不是在终端上打印输出,请使用Jupyter Notebook 。 Jupyter Notebook 中的输出将是这样的。
Python3
display(board)