feat: wip SessionState, SessionView
This commit is contained in:
@@ -1,11 +1,10 @@
|
|||||||
import sys
|
import sys
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
from typing import Optional
|
from typing import Callable, Optional
|
||||||
|
|
||||||
import wx
|
import wx
|
||||||
|
from wx.lib.pubsub import pub
|
||||||
from mind_reader.core import SessionState
|
|
||||||
|
|
||||||
|
|
||||||
def enable_high_dpi_support():
|
def enable_high_dpi_support():
|
||||||
@@ -56,6 +55,172 @@ class SessionStats:
|
|||||||
return round(accuracy, 1)
|
return round(accuracy, 1)
|
||||||
|
|
||||||
|
|
||||||
|
class StepState(Enum):
|
||||||
|
WAITING_FOR_SETTER = auto()
|
||||||
|
WAITING_FOR_GUESSER = auto()
|
||||||
|
SESSION_FINISHED = auto()
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerRole(Enum):
|
||||||
|
SETTER = auto()
|
||||||
|
GUESSER = auto()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class MoveResult:
|
||||||
|
step_index: int
|
||||||
|
setter_direction: Optional[ArrowDirection] = None
|
||||||
|
setter_card_state: Optional[CardState] = None
|
||||||
|
guesser_direction: Optional[ArrowDirection] = None
|
||||||
|
guesser_card_state: Optional[CardState] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Player:
|
||||||
|
name: str
|
||||||
|
role: PlayerRole
|
||||||
|
|
||||||
|
|
||||||
|
class SessionState:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
local_player: Player,
|
||||||
|
remote_player: Player,
|
||||||
|
sequence_length: int = 20,
|
||||||
|
):
|
||||||
|
self._sequence_length = sequence_length
|
||||||
|
|
||||||
|
self._local_player = local_player
|
||||||
|
self._remote_player = remote_player
|
||||||
|
|
||||||
|
self._completed_step_count: int = 0
|
||||||
|
self._step_state: StepState = StepState.WAITING_FOR_SETTER
|
||||||
|
|
||||||
|
self._setter_moves: list[ArrowDirection] = []
|
||||||
|
self._guesser_moves: list[ArrowDirection] = []
|
||||||
|
|
||||||
|
self._stats: Optional[SessionStats] = None
|
||||||
|
|
||||||
|
def setter_move(self, direction: ArrowDirection) -> bool:
|
||||||
|
if self._step_state != StepState.WAITING_FOR_SETTER:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self._setter_moves.append(direction)
|
||||||
|
self._step_state = StepState.WAITING_FOR_GUESSER
|
||||||
|
|
||||||
|
step_index = len(self._setter_moves) - 1
|
||||||
|
result = MoveResult(
|
||||||
|
step_index=step_index,
|
||||||
|
setter_direction=direction,
|
||||||
|
setter_card_state=self.get_setter_card_state(step_index),
|
||||||
|
)
|
||||||
|
|
||||||
|
pub.sendMessage("session.setter_moved", result=result)
|
||||||
|
|
||||||
|
pub.sendMessage(
|
||||||
|
"session.step_state_changed",
|
||||||
|
step_state=self._step_state,
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def guesser_move(self, direction: ArrowDirection) -> bool:
|
||||||
|
if self._step_state != StepState.WAITING_FOR_GUESSER:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self._guesser_moves.append(direction)
|
||||||
|
self._completed_step_count += 1
|
||||||
|
|
||||||
|
step_index = len(self._guesser_moves) - 1
|
||||||
|
|
||||||
|
result = MoveResult(
|
||||||
|
step_index=step_index,
|
||||||
|
setter_direction=self._setter_moves[-1],
|
||||||
|
setter_card_state=self.get_setter_card_state(step_index),
|
||||||
|
guesser_direction=self._guesser_moves[-1],
|
||||||
|
guesser_card_state=self.get_guesser_card_state(step_index),
|
||||||
|
)
|
||||||
|
|
||||||
|
pub.sendMessage("session.guesser_moved", result=result)
|
||||||
|
|
||||||
|
if self._completed_step_count < self._sequence_length:
|
||||||
|
self._step_state = StepState.WAITING_FOR_SETTER
|
||||||
|
pub.sendMessage(
|
||||||
|
"session.step_state_changed",
|
||||||
|
step_state=self._step_state,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self._step_state = StepState.SESSION_FINISHED
|
||||||
|
pub.sendMessage("session.session_finished")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def local_move(self, direction: ArrowDirection) -> bool:
|
||||||
|
if not self.can_local_move():
|
||||||
|
return False
|
||||||
|
if self._local_player.role == PlayerRole.SETTER:
|
||||||
|
return self.setter_move(direction)
|
||||||
|
else:
|
||||||
|
return self.guesser_move(direction)
|
||||||
|
|
||||||
|
def can_local_move(self) -> bool:
|
||||||
|
match self._step_state:
|
||||||
|
case StepState.WAITING_FOR_SETTER:
|
||||||
|
return self._local_player.role == PlayerRole.SETTER
|
||||||
|
case StepState.WAITING_FOR_GUESSER:
|
||||||
|
return self._local_player.role == PlayerRole.GUESSER
|
||||||
|
case StepState.SESSION_FINISHED:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_setter_card_state(self, step_index: int) -> CardState:
|
||||||
|
setter_step_index = len(self._setter_moves) + 1
|
||||||
|
|
||||||
|
if step_index > setter_step_index:
|
||||||
|
return CardState.SETTER_NOT_SET
|
||||||
|
|
||||||
|
if step_index == setter_step_index:
|
||||||
|
if self._step_state == StepState.WAITING_FOR_GUESSER:
|
||||||
|
if self._local_player.role == PlayerRole.SETTER:
|
||||||
|
return CardState.SETTER_REVEALED
|
||||||
|
else:
|
||||||
|
return CardState.SETTER_HIDDEN
|
||||||
|
|
||||||
|
return CardState.SETTER_REVEALED
|
||||||
|
|
||||||
|
def get_guesser_card_state(self, step_index: int) -> CardState:
|
||||||
|
if step_index > self._completed_step_count:
|
||||||
|
return CardState.GUESSER_DISABLED
|
||||||
|
|
||||||
|
elif step_index == self._completed_step_count:
|
||||||
|
return CardState.GUESSER_WAITING
|
||||||
|
|
||||||
|
else:
|
||||||
|
guesser_move = self._guesser_moves[step_index]
|
||||||
|
setter_move = self._setter_moves[step_index]
|
||||||
|
if guesser_move == setter_move:
|
||||||
|
return CardState.GUESSER_CORRECT
|
||||||
|
else:
|
||||||
|
return CardState.GUESSER_WRONG
|
||||||
|
|
||||||
|
@property
|
||||||
|
def setter_name(self) -> str:
|
||||||
|
if self._local_player.role == PlayerRole.SETTER:
|
||||||
|
return self._local_player.name
|
||||||
|
else:
|
||||||
|
return self._remote_player.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def guesser_name(self) -> str:
|
||||||
|
if self._local_player.role == PlayerRole.GUESSER:
|
||||||
|
return self._local_player.name
|
||||||
|
else:
|
||||||
|
return self._remote_player.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sequence_lenght(self) -> int:
|
||||||
|
return self._sequence_length
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class SetterCardColour:
|
class SetterCardColour:
|
||||||
NOT_SET = wx.Colour(82, 97, 107)
|
NOT_SET = wx.Colour(82, 97, 107)
|
||||||
@@ -158,17 +323,15 @@ class Card(wx.Panel):
|
|||||||
|
|
||||||
|
|
||||||
class SessionPanel(wx.Panel):
|
class SessionPanel(wx.Panel):
|
||||||
def __init__(
|
def __init__(self, parent, state: SessionState):
|
||||||
self,
|
|
||||||
parent,
|
|
||||||
setter_name: str,
|
|
||||||
guesser_name: str,
|
|
||||||
sequence_length: int = 20,
|
|
||||||
):
|
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._setter_name = setter_name
|
|
||||||
self._guesser_name = guesser_name
|
self._state = state
|
||||||
self._sequence_length = sequence_length
|
|
||||||
|
self._setter_name = self._state.setter_name
|
||||||
|
self._guesser_name = self._state.guesser_name
|
||||||
|
self._sequence_length = self._state.sequence_lenght
|
||||||
|
|
||||||
self._setter_sequence: list[Card] = []
|
self._setter_sequence: list[Card] = []
|
||||||
self._guesser_sequence: list[Card] = []
|
self._guesser_sequence: list[Card] = []
|
||||||
|
|
||||||
@@ -177,6 +340,11 @@ class SessionPanel(wx.Panel):
|
|||||||
self._setup()
|
self._setup()
|
||||||
self._fit_parent_frame()
|
self._fit_parent_frame()
|
||||||
|
|
||||||
|
pub.subscribe(self._on_setter_moved, "session.setter_moved")
|
||||||
|
pub.subscribe(self._on_guesser_moved, "session.guesser_moved")
|
||||||
|
pub.subscribe(self._on_step_state_changed, "session.step_state_changed")
|
||||||
|
pub.subscribe(self._on_session_finished, "session.session_finished")
|
||||||
|
|
||||||
def _setup(self) -> None:
|
def _setup(self) -> None:
|
||||||
main_sizer = wx.BoxSizer(wx.VERTICAL)
|
main_sizer = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
|
||||||
@@ -194,7 +362,10 @@ class SessionPanel(wx.Panel):
|
|||||||
initial_card_state=CardState.GUESSER_DISABLED,
|
initial_card_state=CardState.GUESSER_DISABLED,
|
||||||
)
|
)
|
||||||
|
|
||||||
controls_sizer = self._create_controls_sizer()
|
controls_sizer = self._create_controls_sizer(
|
||||||
|
on_left=self._on_left_click,
|
||||||
|
on_right=self._on_right_click,
|
||||||
|
)
|
||||||
|
|
||||||
secondary_sizer = wx.BoxSizer(wx.VERTICAL)
|
secondary_sizer = wx.BoxSizer(wx.VERTICAL)
|
||||||
secondary_sizer.Add(setter_sizer, 0, wx.EXPAND)
|
secondary_sizer.Add(setter_sizer, 0, wx.EXPAND)
|
||||||
@@ -228,7 +399,11 @@ class SessionPanel(wx.Panel):
|
|||||||
|
|
||||||
return section_sizer
|
return section_sizer
|
||||||
|
|
||||||
def _create_controls_sizer(self) -> wx.Sizer:
|
def _create_controls_sizer(
|
||||||
|
self,
|
||||||
|
on_left: Callable[[wx.CommandEvent], None],
|
||||||
|
on_right: Callable[[wx.CommandEvent], None],
|
||||||
|
) -> wx.Sizer:
|
||||||
left = wx.Button(self, label=ArrowSymbol.LEFT, size=wx.Size(145, 55))
|
left = wx.Button(self, label=ArrowSymbol.LEFT, size=wx.Size(145, 55))
|
||||||
right = wx.Button(self, label=ArrowSymbol.RIGHT, size=wx.Size(145, 55))
|
right = wx.Button(self, label=ArrowSymbol.RIGHT, size=wx.Size(145, 55))
|
||||||
|
|
||||||
@@ -238,6 +413,9 @@ class SessionPanel(wx.Panel):
|
|||||||
left.SetFont(font)
|
left.SetFont(font)
|
||||||
right.SetFont(font)
|
right.SetFont(font)
|
||||||
|
|
||||||
|
left.Bind(wx.EVT_BUTTON, on_left)
|
||||||
|
right.Bind(wx.EVT_BUTTON, on_right)
|
||||||
|
|
||||||
controls_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
controls_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
controls_sizer.Add(left, 0, wx.RIGHT, 10)
|
controls_sizer.Add(left, 0, wx.RIGHT, 10)
|
||||||
controls_sizer.Add(right, 0, wx.LEFT, 10)
|
controls_sizer.Add(right, 0, wx.LEFT, 10)
|
||||||
@@ -276,6 +454,41 @@ class SessionPanel(wx.Panel):
|
|||||||
top_frame.SetMinSize(min_size)
|
top_frame.SetMinSize(min_size)
|
||||||
top_frame.Fit()
|
top_frame.Fit()
|
||||||
|
|
||||||
|
def _on_left_click(self, event: wx.CommandEvent) -> None:
|
||||||
|
self._handle_arrow_input(ArrowDirection.LEFT)
|
||||||
|
|
||||||
|
def _on_right_click(self, event: wx.CommandEvent) -> None:
|
||||||
|
self._handle_arrow_input(ArrowDirection.RIGHT)
|
||||||
|
|
||||||
|
def _handle_arrow_input(self, direction: ArrowDirection) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _on_setter_moved(self, result: MoveResult):
|
||||||
|
self.update_setter_card(
|
||||||
|
index=result.step_index,
|
||||||
|
state=result.setter_card_state or CardState.SETTER_NOT_SET,
|
||||||
|
direction=result.setter_direction,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _on_guesser_moved(self, result: MoveResult):
|
||||||
|
self.update_setter_card(
|
||||||
|
index=result.step_index,
|
||||||
|
state=result.setter_card_state or CardState.SETTER_NOT_SET,
|
||||||
|
direction=result.setter_direction,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.update_guesser_card(
|
||||||
|
index=result.step_index,
|
||||||
|
state=result.guesser_card_state or CardState.GUESSER_DISABLED,
|
||||||
|
direction=result.guesser_direction,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _on_step_state_changed(self, step_state: StepState):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _on_session_finished(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def update_setter_card(
|
def update_setter_card(
|
||||||
self,
|
self,
|
||||||
index: int,
|
index: int,
|
||||||
@@ -322,22 +535,23 @@ class SessionPanel(wx.Panel):
|
|||||||
class TestFrame(wx.Frame):
|
class TestFrame(wx.Frame):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(None, title="TestFrame")
|
super().__init__(None, title="TestFrame")
|
||||||
main_panel = SessionPanel(self, "Бывалый", "Балбес")
|
|
||||||
|
local = Player("Бывалый", PlayerRole.GUESSER)
|
||||||
|
remote = Player("Балбес", PlayerRole.SETTER)
|
||||||
|
session = SessionState(local, remote)
|
||||||
|
|
||||||
|
main_panel = SessionPanel(self, session)
|
||||||
main_sizer = wx.BoxSizer(wx.VERTICAL)
|
main_sizer = wx.BoxSizer(wx.VERTICAL)
|
||||||
main_sizer.Add(main_panel, 1, wx.EXPAND)
|
main_sizer.Add(main_panel, 1, wx.EXPAND)
|
||||||
self.SetSizer(main_sizer)
|
self.SetSizer(main_sizer)
|
||||||
|
|
||||||
main_panel.update_setter_card(
|
|
||||||
0, CardState.SETTER_REVEALED, ArrowDirection.LEFT
|
|
||||||
)
|
|
||||||
|
|
||||||
main_panel.update_guesser_card(
|
|
||||||
0, CardState.GUESSER_WRONG, ArrowDirection.RIGHT
|
|
||||||
)
|
|
||||||
|
|
||||||
s = SessionStats(20, 1, 0, 1, 5.1)
|
s = SessionStats(20, 1, 0, 1, 5.1)
|
||||||
main_panel.update_statusbar(None, s)
|
main_panel.update_statusbar(None, s)
|
||||||
|
|
||||||
|
session.setter_move(ArrowDirection.LEFT)
|
||||||
|
session.guesser_move(ArrowDirection.LEFT)
|
||||||
|
session.setter_move(ArrowDirection.LEFT)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
enable_high_dpi_support()
|
enable_high_dpi_support()
|
||||||
|
|||||||
Reference in New Issue
Block a user