📜  使用Python中的国际象棋库从 PGN 文件中提取数据

📅  最后修改于: 2022-05-13 01:55:51.760000             🧑  作者: Mango

使用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 文件数据的字符串,则需要将该字符串转换为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)

输出:

如果你想可视化棋盘,你可以在终端上打印棋盘。

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)

Jupyter Notebook 中的棋盘