Files
cpl_cpp-project/Tests/puzzlerating.py
2022-10-27 13:07:24 +02:00

90 lines
2.8 KiB
Python
Executable File

#!/usr/bin/env python3
from puzzledb import PuzzleDb
from puzzlerunner import run_puzzle
import argparse
from pathlib import Path
from random import Random
import glicko2
def select_puzzles(player, puzzle_db, num_puzzles, played_puzzles, random):
rd = player.rd
candidates = []
while len(candidates) < num_puzzles:
candidates = puzzle_db \
.filter(lambda p: p.rating >= player.rating - 2 * rd) \
.filter(lambda p: p.rating <= player.rating + 2 * rd) \
.filter(lambda p: p not in played_puzzles) \
.collect()
rd += 50
return sorted(random.sample(candidates, num_puzzles),
key=lambda p: p.rating)
def play_round(player, puzzle_db, num_puzzles, engine,
timeout, played_puzzles, random):
puzzles = select_puzzles(player, puzzle_db, num_puzzles,
played_puzzles, random)
played_puzzles.update(puzzles)
outcomes = []
for puzzle in puzzles:
print(f'Running puzzle {puzzle.puzzle_id} '
f'with rating {puzzle.rating}... ',
end='', flush=True)
result = run_puzzle(puzzle, engine, timeout)
success = result.is_success()
outcomes.append(success)
if success:
print('OK')
else:
print('FAIL')
ratings = [p.rating for p in puzzles]
rds = [p.rd for p in puzzles]
player.update_player(ratings, rds, outcomes)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--engine', type=Path, required=True)
parser.add_argument('--timeout', type=float, default=60)
parser.add_argument('--min-plays', type=int, default=500)
parser.add_argument('--min-popularity', type=int, default=50)
parser.add_argument('--rounds', type=int, default=20)
parser.add_argument('--puzzles-per-round', type=int, default=5)
parser.add_argument('--random-seed', type=int, default=0)
parser.add_argument('--puzzle-db', type=Path, required=True)
args = parser.parse_args()
with args.puzzle_db.open(newline='') as f:
puzzle_db = PuzzleDb.from_csv(f) \
.filter(lambda p: p.num_plays >= args.min_plays) \
.filter(lambda p: p.popularity >= args.min_popularity) \
.sorted(key=lambda p: p.rating)
player = glicko2.Player()
played_puzzles = set()
random = Random(args.random_seed)
for current_round in range(1, args.rounds + 1):
print(f'=== Round {current_round}/{args.rounds}, '
f'current rating: {round(player.rating)} '
f'(rd: {round(player.rd)}) ===')
play_round(player, puzzle_db, args.puzzles_per_round,
args.engine, args.timeout, played_puzzles, random)
print(f'Final rating: {round(player.rating)} (rd: {round(player.rd)})')
if __name__ == '__main__':
main()