refactor: разделение кода в session_view.py

This commit is contained in:
2026-08-14 02:42:18 +03:00
parent c657415bf0
commit e3f5828334
5 changed files with 290 additions and 311 deletions
+65
View File
@@ -0,0 +1,65 @@
from dataclasses import dataclass
from enum import Enum, auto
from typing import Optional
class CardState(Enum):
SETTER_NOT_SET = auto()
SETTER_HIDDEN = auto()
SETTER_REVEALED = auto()
GUESSER_DISABLED = auto()
GUESSER_WAITING = auto()
GUESSER_CORRECT = auto()
GUESSER_WRONG = auto()
class ArrowDirection(Enum):
LEFT = auto()
RIGHT = auto()
@dataclass
class SessionStats:
total: int
setted: int
correct: int
wrong: int
taken_time: float
@property
def accuracy(self) -> float:
accuracy: float
if self.total == 0:
accuracy = 0.0
accuracy = (self.correct / self.total) * 100
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 CardData:
direction: Optional[ArrowDirection]
state: CardState
@dataclass(frozen=True)
class StepData:
index: int
setter: CardData
guesser: CardData
@dataclass
class Player:
name: str
role: PlayerRole
+3
View File
@@ -0,0 +1,3 @@
from .session_state import SessionState
__all__ = ["SessionState"]
+194
View File
@@ -0,0 +1,194 @@
from wx.lib.pubsub import pub
from mind_reader.domain import (
ArrowDirection,
CardData,
CardState,
Player,
PlayerRole,
StepData,
StepState,
)
class SessionState:
def __init__(
self,
local_player: Player,
remote_player: Player,
sequence_length: int = 20,
):
self._local_player = local_player
self._remote_player = remote_player
self._sequence_length = sequence_length
self._setter_moves: list[ArrowDirection] = []
self._guesser_moves: list[ArrowDirection] = []
self._step_state: StepState = StepState.WAITING_FOR_SETTER
@property
def _completed_move_count(self):
return len(self._guesser_moves)
def _get_setter_card_state(self, index: int) -> CardState:
current_index = len(self._setter_moves)
if index > current_index:
return CardState.SETTER_NOT_SET
elif index == current_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, index: int) -> CardState:
completed_move_count = self._completed_move_count
if index > completed_move_count:
return CardState.GUESSER_DISABLED
elif index == completed_move_count:
if self._step_state == StepState.WAITING_FOR_GUESSER:
return CardState.GUESSER_WAITING
else:
return CardState.GUESSER_DISABLED
else:
setter_move = self._setter_moves[index]
guesser_move = self._guesser_moves[index]
if setter_move == guesser_move:
return CardState.GUESSER_CORRECT
else:
return CardState.GUESSER_WRONG
def start_session(self) -> None:
index = 0
pub.sendMessage(
"session.session_started",
step=StepData(
index=index,
setter=CardData(
direction=None,
state=self._get_setter_card_state(index),
),
guesser=CardData(
direction=None,
state=self._get_guesser_card_state(index),
),
),
)
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
index = len(self._setter_moves) - 1
pub.sendMessage(
"session.setter_moved",
step=StepData(
index=index,
setter=CardData(
direction=direction,
state=self._get_setter_card_state(index),
),
guesser=CardData(
direction=direction,
state=self._get_guesser_card_state(index),
),
),
)
return True
def guesser_move(self, direction: ArrowDirection) -> bool:
if self._step_state != StepState.WAITING_FOR_GUESSER:
return False
self._guesser_moves.append(direction)
if self._completed_move_count < self._sequence_length:
self._step_state = StepState.WAITING_FOR_SETTER
else:
self._step_state = StepState.SESSION_FINISHED
index = len(self._guesser_moves) - 1
pub.sendMessage(
"session.guesser_moved",
step=StepData(
index=index,
setter=CardData(
direction=self._setter_moves[index],
state=self._get_setter_card_state(index),
),
guesser=CardData(
direction=self._guesser_moves[index],
state=self._get_guesser_card_state(index),
),
),
)
next = index + 1
pub.sendMessage(
"session.step_closed",
step=StepData(
index=next,
setter=CardData(
direction=None,
state=self._get_setter_card_state(next),
),
guesser=CardData(
direction=None,
state=self._get_guesser_card_state(next),
),
),
)
if 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
@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_length(self) -> int:
return self._sequence_length
+3 -4
View File
@@ -1,5 +1,4 @@
from mind_reader.ui.views.lobby_view import LobbyPanel from .lobby_view import LobbyPanel
from .session_view import SessionPanel
__all__ = [ __all__ = ["LobbyPanel", "SessionPanel"]
"LobbyPanel",
]
+25 -307
View File
@@ -1,280 +1,12 @@
import sys import sys
from dataclasses import dataclass from dataclasses import dataclass
from enum import Enum, auto
from typing import Callable, Optional from typing import Callable, Optional
import wx import wx
from wx.lib.pubsub import pub from wx.lib.pubsub import pub
from mind_reader.domain import ArrowDirection, CardState, SessionStats, StepData
def enable_high_dpi_support(): from mind_reader.state import SessionState
if sys.platform == "win32":
try:
import ctypes
ctypes.windll.shcore.SetProcessDpiAwareness(2)
except Exception:
try:
import ctypes
ctypes.windll.user32.SetProcessDPIAware()
except Exception:
pass
class CardState(Enum):
SETTER_NOT_SET = auto()
SETTER_HIDDEN = auto()
SETTER_REVEALED = auto()
GUESSER_DISABLED = auto()
GUESSER_WAITING = auto()
GUESSER_CORRECT = auto()
GUESSER_WRONG = auto()
class ArrowDirection(Enum):
LEFT = auto()
RIGHT = auto()
@dataclass
class SessionStats:
total: int
setted: int
correct: int
wrong: int
taken_time: float
@property
def accuracy(self) -> float:
accuracy: float
if self.total == 0:
accuracy = 0.0
accuracy = (self.correct / self.total) * 100
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: ArrowDirection
setter_card_state: CardState
guesser_direction: Optional[ArrowDirection] = None
guesser_card_state: Optional[CardState] = None
@dataclass(frozen=True)
class CardData:
direction: Optional[ArrowDirection]
state: CardState
@dataclass(frozen=True)
class StepData:
index: int
setter: CardData
guesser: CardData
@dataclass
class Player:
name: str
role: PlayerRole
class SessionState:
def __init__(
self,
local_player: Player,
remote_player: Player,
sequence_length: int = 20,
):
self._local_player = local_player
self._remote_player = remote_player
self._sequence_length = sequence_length
self._setter_moves: list[ArrowDirection] = []
self._guesser_moves: list[ArrowDirection] = []
self._step_state: StepState = StepState.WAITING_FOR_SETTER
@property
def _completed_move_count(self):
return len(self._guesser_moves)
def _get_setter_card_state(self, index: int) -> CardState:
current_index = len(self._setter_moves)
if index > current_index:
return CardState.SETTER_NOT_SET
elif index == current_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, index: int) -> CardState:
completed_move_count = self._completed_move_count
if index > completed_move_count:
return CardState.GUESSER_DISABLED
elif index == completed_move_count:
if self._step_state == StepState.WAITING_FOR_GUESSER:
return CardState.GUESSER_WAITING
else:
return CardState.GUESSER_DISABLED
else:
setter_move = self._setter_moves[index]
guesser_move = self._guesser_moves[index]
if setter_move == guesser_move:
return CardState.GUESSER_CORRECT
else:
return CardState.GUESSER_WRONG
def start_session(self) -> None:
index = 0
pub.sendMessage(
"session.session_started",
step=StepData(
index=index,
setter=CardData(
direction=None,
state=self._get_setter_card_state(index),
),
guesser=CardData(
direction=None,
state=self._get_guesser_card_state(index),
),
),
)
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
index = len(self._setter_moves) - 1
pub.sendMessage(
"session.setter_moved",
step=StepData(
index=index,
setter=CardData(
direction=direction,
state=self._get_setter_card_state(index),
),
guesser=CardData(
direction=direction,
state=self._get_guesser_card_state(index),
),
),
)
return True
def guesser_move(self, direction: ArrowDirection) -> bool:
if self._step_state != StepState.WAITING_FOR_GUESSER:
return False
self._guesser_moves.append(direction)
if self._completed_move_count < self._sequence_length:
self._step_state = StepState.WAITING_FOR_SETTER
else:
self._step_state = StepState.SESSION_FINISHED
index = len(self._guesser_moves) - 1
pub.sendMessage(
"session.guesser_moved",
step=StepData(
index=index,
setter=CardData(
direction=self._setter_moves[index],
state=self._get_setter_card_state(index),
),
guesser=CardData(
direction=self._guesser_moves[index],
state=self._get_guesser_card_state(index),
),
),
)
next = index + 1
pub.sendMessage(
"session.step_closed",
step=StepData(
index=next,
setter=CardData(
direction=None,
state=self._get_setter_card_state(next),
),
guesser=CardData(
direction=None,
state=self._get_guesser_card_state(next),
),
),
)
if 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
@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_length(self) -> int:
return self._sequence_length
@dataclass(frozen=True) @dataclass(frozen=True)
@@ -379,19 +111,20 @@ class Card(wx.Panel):
class SessionPanel(wx.Panel): class SessionPanel(wx.Panel):
def __init__(self, parent, state: SessionState): def __init__(
self, parent, setter_name: str, guesser_name: str, sequence_length: int
):
super().__init__(parent) super().__init__(parent)
self._state = state self._setter_name = setter_name
self._guesser_name = guesser_name
self._setter_name = self._state.setter_name self._sequence_length = sequence_length
self._guesser_name = self._state.guesser_name
self._sequence_length = self._state.sequence_length
self._setter_sequence: list[Card] = [] self._setter_sequence: list[Card] = []
self._guesser_sequence: list[Card] = [] self._guesser_sequence: list[Card] = []
self._statusbar = self._get_statusbar() self._statusbar = self._get_statusbar()
self._setup_statusbar()
self._setup() self._setup()
self._fit_parent_frame() self._fit_parent_frame()
@@ -491,6 +224,22 @@ class SessionPanel(wx.Panel):
return None return None
def _setup_statusbar(self) -> None:
if not self._statusbar:
return
message = " Ожидание начала игры... "
progress = f" Прогресс 0/{self._sequence_length} "
accuracy = " Точность 0.0% (0/0) "
taken_time = " Время 00:00 "
self._statusbar.SetStatusText(message, 0)
self._statusbar.SetStatusText(progress, 1)
self._statusbar.SetStatusText(accuracy, 2)
self._statusbar.SetStatusText(taken_time, 3)
self._autofit_statusbar([progress, accuracy, message])
def _autofit_statusbar(self, texts: list[str]) -> None: def _autofit_statusbar(self, texts: list[str]) -> None:
if not self._statusbar: if not self._statusbar:
return return
@@ -616,34 +365,3 @@ class SessionPanel(wx.Panel):
self._statusbar.SetStatusText(taken_time, 3) self._statusbar.SetStatusText(taken_time, 3)
self._autofit_statusbar([progress, accuracy, taken_time]) self._autofit_statusbar([progress, accuracy, taken_time])
class TestFrame(wx.Frame):
def __init__(self):
super().__init__(None, title="TestFrame")
local = Player("Бывалый", PlayerRole.SETTER)
remote = Player("Балбес", PlayerRole.GUESSER)
session = SessionState(local, remote)
main_panel = SessionPanel(self, session)
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(main_panel, 1, wx.EXPAND)
self.SetSizer(main_sizer)
s = SessionStats(20, 1, 0, 1, 5.1)
main_panel.update_statusbar(None, s)
session.start_session()
session.setter_move(ArrowDirection.LEFT)
session.guesser_move(ArrowDirection.LEFT)
session.setter_move(ArrowDirection.LEFT)
session.guesser_move(ArrowDirection.RIGHT)
if __name__ == "__main__":
enable_high_dpi_support()
app = wx.App()
frame = TestFrame()
frame.Show()
app.MainLoop()