88 lines
3.2 KiB
Python
88 lines
3.2 KiB
Python
# Relit dans GNU Backgammon de référence les parties exportées en SGF par
|
|
# Ustagammon (app/src/domain/game/sgf.ts) et vérifie qu'il y retrouve les
|
|
# positions du journal.
|
|
#
|
|
# Ce script s'exécute DANS gnubg (scripting Python intégré), dans l'image
|
|
# Docker ustagammon/gnubg-reference : voir tests/test_web.sh. Le dossier
|
|
# SGF_DIR contient, pour chaque partie, <nom>.sgf et <nom>.json (écrits par
|
|
# app/tests/tools/sgf-samples.ts) :
|
|
# after : après chaque coup du journal, la position vue de celui qui a
|
|
# alors la main ;
|
|
# result : le résultat de la partie ({winner, points}) ou null.
|
|
#
|
|
# Pour chaque partie, gnubg charge le fichier (load game), puis avance
|
|
# enregistrement par enregistrement (next) : après chaque coup, sa position
|
|
# doit être celle du journal. Une position de départ mal posée, un coup mal
|
|
# écrit ou refusé changent donc la suite des positions. Le résultat (RE)
|
|
# doit aussi être celui du journal. Code de sortie : 0 si tout concorde.
|
|
|
|
import glob
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
import gnubg
|
|
|
|
FOLDER = os.environ.get("SGF_DIR", "/sgf")
|
|
|
|
|
|
def check(path):
|
|
"""Les écarts entre gnubg et le journal pour une partie (liste vide si
|
|
tout concorde)."""
|
|
with open(path[:-4] + ".json") as f:
|
|
expected = json.load(f)
|
|
gnubg.command("load game " + path)
|
|
games = gnubg.match(analysis=0, boards=0, statistics=0, verbose=0)["games"]
|
|
if len(games) != 1:
|
|
return ["gnubg n'a pas chargé la partie"]
|
|
game = games[0]
|
|
records = list(game["game"])
|
|
|
|
# Le premier « next » applique le premier enregistrement.
|
|
gnubg.command("first move")
|
|
after = []
|
|
for record in records:
|
|
gnubg.command("next")
|
|
if record["action"] == "move":
|
|
after.append(gnubg.positionid())
|
|
|
|
errors = []
|
|
if len(after) != len(expected["after"]):
|
|
errors.append("%d coups lus, %d attendus" % (len(after), len(expected["after"])))
|
|
for i, (got, want) in enumerate(zip(after, expected["after"])):
|
|
if got != want:
|
|
errors.append("après le coup %d : gnubg %s, journal %s" % (i + 1, got, want))
|
|
break
|
|
|
|
# Dans gnubg, X est le joueur 0 (W, l'ordinateur) et O le joueur 1 (B).
|
|
info = game["info"]
|
|
result = expected["result"]
|
|
if result is None:
|
|
if info.get("winner") is not None:
|
|
errors.append("gnubg voit une partie finie : %s" % info)
|
|
else:
|
|
winner = "O" if result["winner"] == "player" else "X"
|
|
if (info.get("winner"), info.get("points-won")) != (winner, result["points"]):
|
|
errors.append("résultat : gnubg %s, journal %s" % (info, result))
|
|
return errors
|
|
|
|
|
|
failures = 0
|
|
paths = sorted(glob.glob(os.path.join(FOLDER, "*.sgf")))
|
|
for path in paths:
|
|
errors = check(path)
|
|
name = os.path.basename(path)
|
|
if errors:
|
|
failures += 1
|
|
print("ÉCHEC %s : %s" % (name, " ; ".join(errors)))
|
|
else:
|
|
print("OK %s" % name)
|
|
|
|
if not paths:
|
|
print("aucun SGF dans %s" % FOLDER)
|
|
failures += 1
|
|
sys.stdout.flush()
|
|
# Un script --python de gnubg ne transmet pas son code de sortie : la
|
|
# dernière ligne le donne au script shell.
|
|
print("SGF-RESULTAT %s" % ("OK" if failures == 0 else "ECHEC"))
|