Allow EloTracker to run matches for multiple games

bram/mute
Bram van den Heuvel 2026-07-01 17:23:14 +02:00
parent e2daa9a205
commit ca7bfdc50a
2 changed files with 32 additions and 14 deletions

8
elo.py
View File

@ -3,7 +3,7 @@
"""
from elo_tracker import EloTracker
from pyclient.games import TicTacToe
from pyclient.games import RoyalGameOfUr, TicTacToe
GAME_FILE = "games.jsonl"
PLAYER_FILE = "known_players.json"
@ -21,6 +21,12 @@ def main() -> int:
player_count=2,
)
tracker.start_periodic_matches(
game=RoyalGameOfUr.empty(),
interval_seconds=9 * 60,
player_count=2,
)
try:
tracker.start_server(import_name=__name__)
except KeyboardInterrupt:

View File

@ -16,6 +16,7 @@ from typing import Any, Sequence
import agents
import pyclient
import time
from pyclient.games import FinishState, Game
@ -280,7 +281,7 @@ class EloTracker:
# Threading variables
self.__lock = threading.RLock()
self.__scheduler_stop = threading.Event()
self.__scheduler_thread: threading.Thread | None = None
self.__scheduler_threads: list[threading.Thread] = []
# Immutable values
self.debug: bool = debug
@ -551,7 +552,11 @@ class EloTracker:
:rtype: bool
"""
with self.__lock:
return self.__scheduler_thread is not None and self.__scheduler_thread.is_alive()
for thread in self.__scheduler_threads:
if thread.is_alive():
return True
else:
return False
def load_players(self) -> None:
"""
@ -665,33 +670,40 @@ class EloTracker:
raise ValueError("player_count must be greater than one.")
with self.__lock:
if self.is_running_periodic_matches():
self.stop_periodic_matches()
self.__scheduler_stop.clear()
self.__scheduler_thread = threading.Thread(
thread = threading.Thread(
target=self.__scheduler_loop,
args=(game, interval_seconds, player_count),
daemon=True,
)
self.__scheduler_thread.start()
self.__scheduler_threads.append(thread)
thread.start()
def stop_periodic_matches(self) -> None:
"""
Stop the periodic match scheduler and wait briefly for it to exit.
"""
thread: threading.Thread | None
max_wait_time_s = 5
now = time.time()
time_left = lambda : max(0.1, now + max_wait_time_s - time.time())
to_remove : list[threading.Thread] = []
# Announce that all threads need to be stopped
with self.__lock:
self.__scheduler_stop.set()
thread = self.__scheduler_thread
to_remove = [ thread for thread in self.__scheduler_threads ]
if thread is not None:
thread.join(timeout=5)
# Then, quietly remove all existing threads
for thread in self.__scheduler_threads:
if thread is not None:
thread.join(timeout=time_left())
# Remove all stopped threads
# Keep in mind that another threads might've added new threads in the
# meantime.
with self.__lock:
if self.__scheduler_thread is thread:
self.__scheduler_thread = None
for thread in to_remove:
self.__scheduler_threads.remove(thread)
def get_json_players(self, game_name : str) -> list[dict[str, Any]]:
"""