Skip to content

Commit 1acb488

Browse files
committed
test
1 parent cdd863f commit 1acb488

2 files changed

Lines changed: 127 additions & 5 deletions

File tree

.github/workflows/games.yml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ jobs:
132132
-engine cmd=base-engine/$OUTPUT_EXEC name=base \
133133
-openings file=tools/UHO_Lichess_4852_v1.epd format=epd order=random \
134134
-each tc=$TC \
135-
-rounds 1 \
135+
-rounds 1500 \
136136
-concurrency $(nproc) \
137137
-pgnout notation=san nodes=true \
138138
file=games_${{ matrix.shard }}.pgn \
@@ -171,10 +171,14 @@ jobs:
171171
run: |
172172
pip install chess scipy
173173
git clone https://github.com/jdart1/stats.git
174-
python stats/sprt.py \
175-
--elo0 "$ELO0" \
176-
--elo1 "$ELO1" --alpha 0.05 --beta 0.05 --results $(
177-
python extract_ptnml.py shard-*/*.pgn | tee results.txt | tail -n 1)> sprt.txt
174+
RESULTS=$(python extract_ptnml.py shard-*/*.pgn | tee results.txt | tail -n1)
175+
python -m stats.sprt \
176+
--elo0 "$ELO0" \
177+
--elo1 "$ELO1" \
178+
--alpha 0.05 \
179+
--beta 0.05 \
180+
--results "$RESULTS"
181+
178182
- uses: actions/upload-artifact@v4
179183
with:
180184
name: results

extract_ptnml.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#!/usr/bin/env python3
2+
3+
import argparse
4+
import glob
5+
from collections import defaultdict
6+
from itertools import chain
7+
import chess.pgn
8+
9+
# [LL, LD/DL, WL/DD/LW, WD/DW, WW]
10+
PTNML_INDEX = {-2: 0, -1: 1, 0: 2, 1: 3, 2: 4}
11+
12+
13+
def score_from_new(headers):
14+
result = headers["Result"]
15+
16+
if result == "1/2-1/2":
17+
return 0
18+
19+
new_is_white = headers["White"] == "new"
20+
21+
if new_is_white:
22+
return 1 if result == "1-0" else -1
23+
else:
24+
return 1 if result == "0-1" else -1
25+
26+
27+
def main():
28+
parser = argparse.ArgumentParser(
29+
description="Extract WDL and pentanomial statistics from fastchess PGNs"
30+
)
31+
parser.add_argument("pgns", nargs="+")
32+
args = parser.parse_args()
33+
34+
pairs = defaultdict(list)
35+
36+
# WDL = [loss, draw, win]
37+
wdl = [0, 0, 0]
38+
games = 0
39+
40+
for filename in chain.from_iterable(glob.glob(p) for p in args.pgns):
41+
with open(filename, encoding="utf-8") as f:
42+
while (game := chess.pgn.read_game(f)) is not None:
43+
headers = game.headers
44+
45+
score = score_from_new(headers)
46+
47+
games += 1
48+
if score < 0:
49+
wdl[0] += 1
50+
elif score == 0:
51+
wdl[1] += 1
52+
else:
53+
wdl[2] += 1
54+
55+
fen = headers.get("FEN")
56+
round_id = headers.get("Round")
57+
58+
if fen is None or round_id is None:
59+
raise RuntimeError(
60+
f"{filename}: missing FEN or Round tag"
61+
)
62+
63+
# Include filename because each shard starts rounds again
64+
key = (
65+
filename,
66+
round_id,
67+
fen,
68+
)
69+
70+
pairs[key].append(score)
71+
72+
ptnml = [0] * 5
73+
pairs_count = 0
74+
75+
for key, scores in pairs.items():
76+
if len(scores) != 2:
77+
print(
78+
f"Skipping incomplete pair {key}: got {len(scores)} games"
79+
)
80+
continue
81+
82+
# Make sure the two games are the repeat pair
83+
if scores[0] + scores[1] not in PTNML_INDEX:
84+
raise RuntimeError("Invalid pair score")
85+
86+
ptnml[PTNML_INDEX[scores[0] + scores[1]]] += 1
87+
pairs_count += 1
88+
89+
print(f"Games: {games}")
90+
print(f"Pairs: {pairs_count}")
91+
92+
print()
93+
print("WDL:")
94+
print(f" Loss: {wdl[0]}")
95+
print(f" Draw: {wdl[1]}")
96+
print(f" Win : {wdl[2]}")
97+
print()
98+
print(wdl)
99+
100+
print()
101+
print("PTNML:")
102+
names = [
103+
"LL",
104+
"LD",
105+
"WL/DD",
106+
"WD",
107+
"WW",
108+
]
109+
110+
for name, count in zip(names, ptnml):
111+
print(f" {name:10}: {count}")
112+
113+
print()
114+
print(ptnml)
115+
116+
117+
if __name__ == "__main__":
118+
main()

0 commit comments

Comments
 (0)