multi_game.py
python · 22 lines · Exact bytes
Version & provenance · service-gpu-c205ec8f7f77
Recorded SHA-256 effecdaf5dfcd998dcf8fab6e78ae9a2eda69791ca0fad8ea86d8d88dc064f36Rendered SHA-256 effecdaf5dfcd998dcf8fab6e78ae9a2eda69791ca0fad8ea86d8d88dc064f36
Apache-2.0 for original LittlePly code, declared by the project owner on 2026-10-28. Historical source bytes and hashes are unchanged. Third-party components retain their own licenses; Lichess data remain CC0-1.0. License notes. Line links are stable within this snapshot. Exact allowlisted source from immutable live GPU release 6133648b2926-c205ec8f7f77, verified against release manifest SHA-256 a1cdc3f5f55c96b3164bc6fd78cb37308d547b2d7f07865dd37ad1448f2f3a1e. Runtime owner confirmed GPU serving, event-stream/model warmup, BOT identity and zero restarts on 2026-10-28. Capacity is up to four casual standard games, with bullet games alone; UltraBullet, correspondence and variants are unsupported. Checkpoint remains 6133648b2926b38542ee3ee1251a1ba111d61da9a8ea69d1c5f0559b09933643. app_multi.py is the multi-game controller; app.py is its shared base, whose legacy standalone admission differs. This is a source subset; host configuration, launcher, state, secrets and private games are excluded. This is a serving change, not a new model or evaluation.
1"""Same authoritative PGN/journal logic with all real-time clock validation."""
2import json,re
3from pathlib import Path
4import chess
5from core import Game,identity,reconstruct
6from scheduler import realtime_reason
7
8class RealtimeGame(Game):
9 def __init__(self,full,bot,directory):
10 if full.get('variant',{}).get('key')!='standard' or full.get('rated') is not False:raise ValueError('non-casual or variant game')
11 if full.get('initialFen') not in ('startpos',chess.STARTING_FEN):raise ValueError('nonstandard start')
12 players=[identity(full[x]) for x in ('white','black')]
13 if players.count(bot.lower())!=1:raise ValueError('wrong bot identity')
14 clock=full.get('clock',{})
15 if realtime_reason({'type':'clock','limit':clock.get('initial',-1000)//1000,'increment':clock.get('increment',-1000)//1000}):raise ValueError('unsupported clock')
16 self.id=full['id']
17 if not re.fullmatch('[A-Za-z0-9]{8}',self.id):raise ValueError('invalid game id')
18 self.color=players[0]==bot.lower();self.full=full
19 self.directory=Path(directory)/self.id;self.directory.mkdir(parents=True,exist_ok=True)
20 path=self.directory/'journal.json';self.journal=json.loads(path.read_text()) if path.exists() else {'decisions':{},'events':[]}
21 self.state=full['state'];self.board=reconstruct(self.state['moves']);self.save()
22