"""Public client entry points.""" from typing import List, Optional import requests from .poll import ServerAgent class PyClient: """Host games between discovered server agents.""" def __init__(self, hosts: List[str], debug : bool = False) -> None: """ Create a PyClient. :param hosts: URLs of servers that can participate. :type hosts: List[str] :raises ValueError: If no reachable servers are provided. """ self.agents: List[ServerAgent] = [] self.debug = debug self.hosts: List[str] = [] for host in hosts: agent = self.__discover_host(host) if agent is not None: self.agents.append(agent) self.hosts.append(agent.url) if len(self.hosts) <= 0: raise ValueError( "No valid hosts found! Check your internet connection or verify the URLs are correct." ) def __discover_host(self, url: str) -> Optional[ServerAgent]: try: return ServerAgent.from_url(url, debug=self.debug) except (requests.exceptions.RequestException, ValueError): return None def play_game(self, name : str, game, timeout : float = 1.0): """ Play a given game. Ask the registered agents to participate. """ agents = [ agent for agent in self.agents if name in agent.games ] states = [] current_state = game.empty() while current_state.winner() is None: player : int = current_state.player_to_move() if len(agents) < player: raise KeyError( f"{player} players for game {name}, found only {len(agents)}" ) # Ask for move agent = agents[player-1] payload = agent.poll( game=current_state.action_name(), payload=current_state.as_seen_by(player), timeout=timeout, ) # Calculate move current_state = current_state.move(payload) # Save the results states.append((player, payload, current_state)) return states def verify_host(self, url: str) -> bool: """ Verify whether the URL seems to contain a link to a playable server. """ return self.__discover_host(url) is not None __all__ = ["PyClient", "ServerAgent"]