175 lines
6.3 KiB
Python
175 lines
6.3 KiB
Python
from ..lobby.domain import Player, PlayerRole
|
|
from ..session.domain import ArrowDirection, CardState, SessionPhase
|
|
from ..session.events import (
|
|
GuesserMoveEvent,
|
|
NextStepRequestedEvent,
|
|
PlayerHelloEvent,
|
|
RevealSecretEvent,
|
|
SessionEvent,
|
|
SetterMoveEvent,
|
|
)
|
|
|
|
|
|
class SessionStateMachine:
|
|
def __init__(
|
|
self, setter: Player, guessers: set[Player], sequence_length: int = 20
|
|
):
|
|
self._setter = setter
|
|
self._guessers = guessers
|
|
|
|
self._pending_players: set[Player] = set(guessers)
|
|
self._pending_players.add(setter)
|
|
|
|
self._sequence_length = sequence_length
|
|
self._setter_moves: list[ArrowDirection] = []
|
|
self._guessers_moves: dict[Player, list[ArrowDirection]] = {
|
|
player: [] for player in guessers
|
|
}
|
|
|
|
self._phase: SessionPhase = SessionPhase.INITIALIZING
|
|
|
|
def process(self, event: SessionEvent) -> bool:
|
|
match (self._phase, event):
|
|
case (SessionPhase.INITIALIZING, PlayerHelloEvent(player)):
|
|
self._pending_players.remove(player)
|
|
if not self._pending_players:
|
|
self._phase = SessionPhase.WAITING_FOR_SETTER
|
|
self._pending_players = {self._setter}
|
|
return True
|
|
|
|
case (
|
|
SessionPhase.WAITING_FOR_SETTER,
|
|
SetterMoveEvent(player, direction),
|
|
):
|
|
self._pending_players.remove(player)
|
|
if not self._pending_players:
|
|
self._setter_moves.append(direction)
|
|
self._phase = SessionPhase.WAITING_FOR_GUESSER
|
|
self._pending_players = set(self._guessers)
|
|
return True
|
|
|
|
case (
|
|
SessionPhase.WAITING_FOR_GUESSER,
|
|
GuesserMoveEvent(player, direction),
|
|
):
|
|
self._guessers_moves[player].append(direction)
|
|
self._pending_players.remove(player)
|
|
if not self._pending_players:
|
|
self._phase = SessionPhase.WAITING_FOR_REVEAL
|
|
self._pending_players = {self._setter}
|
|
return True
|
|
|
|
case (
|
|
SessionPhase.WAITING_FOR_REVEAL,
|
|
RevealSecretEvent(player, direction),
|
|
):
|
|
self._pending_players.remove(player)
|
|
if not self._pending_players:
|
|
self._phase = SessionPhase.CHECKOUT
|
|
setter_move_index = len(self._setter_moves) - 1
|
|
self._setter_moves[setter_move_index] = direction
|
|
self._pending_players = set(self._guessers)
|
|
return True
|
|
|
|
case (SessionPhase.CHECKOUT, NextStepRequestedEvent(player)):
|
|
self._pending_players.remove(player)
|
|
if not self._pending_players:
|
|
if len(self._setter_moves) >= self._sequence_length:
|
|
self._phase = SessionPhase.FINISHED
|
|
self._pending_players.clear()
|
|
else:
|
|
self._phase = SessionPhase.WAITING_FOR_SETTER
|
|
self._pending_players = {self._setter}
|
|
return True
|
|
|
|
case _:
|
|
return False
|
|
|
|
def get_card_state(self, player: Player, index: int) -> CardState:
|
|
match player.role:
|
|
case PlayerRole.SETTER:
|
|
return self._get_setter_card_state(index)
|
|
case PlayerRole.GUESSER:
|
|
return self._get_guesser_card_state(player, index)
|
|
|
|
def _get_setter_card_state(self, index: int) -> CardState:
|
|
current_index = self.current_index
|
|
|
|
if index > current_index:
|
|
return CardState.SETTER_NOT_SET
|
|
|
|
elif index == current_index:
|
|
match self._phase:
|
|
case SessionPhase.INITIALIZING:
|
|
return CardState.SETTER_NOT_SET
|
|
case SessionPhase.WAITING_FOR_SETTER:
|
|
return CardState.SETTER_WAITING
|
|
case (
|
|
SessionPhase.WAITING_FOR_GUESSER
|
|
| SessionPhase.WAITING_FOR_REVEAL
|
|
):
|
|
if self._setter_moves[-1] == ArrowDirection.HIDDEN:
|
|
return CardState.SETTER_HIDDEN
|
|
else:
|
|
return CardState.SETTER_REVEALED
|
|
case SessionPhase.CHECKOUT | SessionPhase.FINISHED:
|
|
return CardState.SETTER_REVEALED
|
|
|
|
else:
|
|
return CardState.SETTER_REVEALED
|
|
|
|
def _get_guesser_card_state(self, player: Player, index: int) -> CardState:
|
|
def _check_direction(
|
|
self: SessionStateMachine, player: Player, index: int
|
|
) -> CardState:
|
|
if self._setter_moves[index] == self._guessers_moves[player][index]:
|
|
return CardState.GUESSER_CORRECT
|
|
else:
|
|
return CardState.GUESSER_WRONG
|
|
|
|
current_index = self.current_index
|
|
|
|
if index > current_index:
|
|
return CardState.GUESSER_DISABLED
|
|
|
|
elif index == current_index:
|
|
match self._phase:
|
|
case (
|
|
SessionPhase.INITIALIZING | SessionPhase.WAITING_FOR_SETTER
|
|
):
|
|
return CardState.GUESSER_DISABLED
|
|
case (
|
|
SessionPhase.WAITING_FOR_GUESSER
|
|
| SessionPhase.WAITING_FOR_REVEAL
|
|
):
|
|
return CardState.GUESSER_WAITING
|
|
case SessionPhase.CHECKOUT | SessionPhase.FINISHED:
|
|
return _check_direction(self, player, index)
|
|
|
|
else:
|
|
return _check_direction(self, player, index)
|
|
|
|
def get_setter_move(self, index: int) -> ArrowDirection | None:
|
|
try:
|
|
return self._setter_moves[index]
|
|
except IndexError:
|
|
return None
|
|
|
|
def get_guesser_move(
|
|
self, player: Player, index: int
|
|
) -> ArrowDirection | None:
|
|
try:
|
|
return self._guessers_moves[player][index]
|
|
except IndexError:
|
|
return None
|
|
|
|
@property
|
|
def current_index(self) -> int:
|
|
setter_step_number = len(self._setter_moves)
|
|
if setter_step_number:
|
|
if self._phase == SessionPhase.WAITING_FOR_SETTER:
|
|
return setter_step_number
|
|
else:
|
|
return setter_step_number - 1
|
|
return 0
|