Build PyClient turn generator
parent
17e12a12ab
commit
10e808751a
|
|
@ -1,6 +1,6 @@
|
|||
"""Public client entry points."""
|
||||
|
||||
from typing import List, Optional
|
||||
from typing import Any, Generator, List, Optional
|
||||
|
||||
import requests
|
||||
|
||||
|
|
@ -39,12 +39,28 @@ class PyClient:
|
|||
except (requests.exceptions.RequestException, ValueError):
|
||||
return None
|
||||
|
||||
def play_game(self, name : str, game, timeout : float = 1.0):
|
||||
def gen_game(self, name : str, game : Any, urls : list[str], timeout : float = 1.0, move_default_if_nonexistent : bool = False) -> Generator[tuple[int, dict[str, Any], Any], None, None]:
|
||||
"""
|
||||
Play a given game. Ask the registered agents to participate.
|
||||
Play game. Return the results as they've been calculated.
|
||||
|
||||
:param name: Unique identifier string name for the game
|
||||
:type name: str
|
||||
:param game: Game to be played
|
||||
:type game: Any
|
||||
:param urls: List of URLs where players are located
|
||||
:type urls: list[str]
|
||||
:param timeout: Maximum time in seconds to wait for a player to respond
|
||||
:type timeout: float
|
||||
:param move_default_if_nonexistent: If a required player doesn't exist, raise an error. When this is set to true, however, the program will instead assume a player that always takes the default option.
|
||||
:type move_default_if_nonexistent: bool
|
||||
:return: Generator of each turn consisting of a player, what action it took and what that resulted in.
|
||||
:rtype: Generator[tuple[int, dict[str, Any], Any], None, None]
|
||||
:raises KeyError: The number of URLs provided is too low, the game requires more players.
|
||||
"""
|
||||
agents = [ agent for agent in self.agents if name in agent.games ]
|
||||
states = []
|
||||
agents = [
|
||||
ServerAgent(url=url, name="", games={}, debug=self.debug)
|
||||
for url in urls
|
||||
]
|
||||
|
||||
current_state = game.empty()
|
||||
|
||||
|
|
@ -52,25 +68,38 @@ class PyClient:
|
|||
player : int = current_state.player_to_move()
|
||||
|
||||
if len(agents) < player:
|
||||
raise KeyError(
|
||||
f"{player} players for game {name}, found only {len(agents)}"
|
||||
if not move_default_if_nonexistent:
|
||||
raise KeyError(
|
||||
f"Game requires at least {player} players to exist, found only {len(agents)}"
|
||||
)
|
||||
|
||||
current_state = current_state.move_default()
|
||||
|
||||
yield player, {}, current_state
|
||||
|
||||
else:
|
||||
agent = agents[player-1]
|
||||
payload = agent.poll(
|
||||
game=(name + "/" + current_state.action_name()).strip("/"),
|
||||
payload=current_state.as_seen_by(player),
|
||||
timeout=timeout,
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# Calculate move
|
||||
current_state = current_state.move(payload)
|
||||
yield player, payload or {}, current_state
|
||||
|
||||
# Save the results
|
||||
states.append((player, payload, current_state))
|
||||
def play_game(self, name : str, game, timeout : float = 1.0) -> list[tuple[int, dict[str, Any], Any]]:
|
||||
"""
|
||||
Play a given game. Ask the registered agents to participate.
|
||||
"""
|
||||
urls = [ agent.url for agent in self.agents if name in agent.games ]
|
||||
|
||||
return states
|
||||
return list(self.gen_game(
|
||||
name=name, game=game, urls=urls, timeout=timeout,
|
||||
move_default_if_nonexistent=False,
|
||||
))
|
||||
|
||||
def verify_host(self, url: str) -> bool:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -169,8 +169,8 @@ class TicTacToe:
|
|||
f"Index to write to should be 1-9, not {index}"
|
||||
)
|
||||
|
||||
def action_name(self):
|
||||
return "/tic-tac-toe"
|
||||
def action_name(self) -> str:
|
||||
return ""
|
||||
|
||||
def as_seen_by(self, player : int) -> Dict[str, Any]:
|
||||
"""
|
||||
|
|
|
|||
Loading…
Reference in New Issue