Bot-Man-Toe/pyclient/__init__.py

83 lines
2.4 KiB
Python

"""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"]