我们将实现 4 个与国际象棋数据分析相关的函数,帮助朋友 Binh 分析 lichess.org 的数据。数据采用 PGN 格式,表示一盘棋的元信息与走法。以下是每一部分的解释:
✅ Part 1: read_pgn(file_name: str) -> list[dict]
目标: 读取一个
.pgn
文件,输出一个包含棋局信息的字典列表,每个字典对应一局棋。输入:
.pgn
文件路径输出: 包含如下 key 的字典列表:
- 元信息字段(7 个):
event
,white
,black
,result
,whiteelo
,blackelo
,opening
- 走法字段(40 个):
w1
到w20
,b1
到b20
细节说明:
- 如果某一回合没有白棋或黑棋走子,用
'-'
占位。
- 所有 40 个字段都必须存在(即使游戏早就结束)。
具体细节:
❓:.png
文件的格式是怎样的?
- 每一场游戏以换行间隔
- 每场游戏又分为两个部分:
赛事基本信息
以及下棋详细步骤
, 也已换行间隔
- 每场游戏的具体细节:
- 赛事基本信息:
- 以
[ ]
包裹每条信息 ➡️ .strip() - 每条信息的名称和内容用空格分割 ➡️ .split()
- 信息的type ➡️ …(自己想吧。在 part1 就想好, part2 3 4 就不用想了)
每场游戏具体长什么样子:
可以观察到的特点:
❓:要求的list格式是怎样的?
- list的结构:
list [ dict { str: str } ]
思考:dict 的 value 一定要是 str 吗?
- keys:
❓:具体实操细节?
- 注意换行分割的内容有什么不同?
- 注意key的大小写?
- 文件中赛事具体细节中每一条的内容已经包含了
”
?
✅ Part 2: win_loss_by_opening(games: list[dict]) -> dict
目标: 统计每种开局的胜负情况。
输入: 上一步生成的棋局字典列表。
输出: 一个字典,
key = opening name
,value = (白胜场数, 黑胜场数)
判断胜负的方法:
result == '1-0'
表示白胜
result == '0-1'
表示黑胜
result == '1/2-1/2'
表示平局(忽略)
具体细节:
注意:
- 返回的dict结构:
dict{str: tuple}
result
有几种情况?思考:只有两种吗?面对不同result
统计时应该怎样加分?
✅ Part 3: win_loss_by_elo(games: list[dict], lower: int, upper: int) -> tuple[int, int]
目标: 在某个 ELO 差距区间内,统计低分选手 vs 高分选手 的胜负场数。
输入:
games
: 棋局列表
lower
,upper
: ELO 差值区间(lower < |elo1 - elo2| < upper)
输出:
(低分胜场, 高分胜场)
细节说明:
- 需要跳过
whiteelo
或blackelo
为'?'
的记录
- 比较两个数值,找出低分和高分选手,看谁赢了
具体细节:
注意:
- 返回的tuple结构:
tuple[int, int]
- 注意elo差值上下限?
- 要求的返回类型是tuple,一开始就一定要定义返回类型为tuple吗?
✅ Part 4: win_loss_by_moves(games: list[dict], moves: list[str]) -> tuple[int, int]
目标: 给定一个走法序列(从开局开始),统计这种局面下白胜和黑胜的数量。
输入:
games
: 棋局列表
moves
: 走法列表,如:['e4', 'e5', 'Nf3']
输出:
(白胜场数, 黑胜场数)
具体细节:
注意:
- 返回的tuple结构:
tuple[int, int]
- 要求的返回类型是tuple,一开始就一定要定义返回类型为tuple吗?
- 怎么判断
moves
是否为 某场游戏的步骤 的子集?这是否涉及到对于遍历字典时,不知道下一个key具体是什么的情况下, 访问value?如果不涉及到这个问题,还能怎么做?