diff --git a/tests/whist_core/session/test_table.py b/tests/whist_core/session/test_table.py index 1df4166e..5051bb72 100644 --- a/tests/whist_core/session/test_table.py +++ b/tests/whist_core/session/test_table.py @@ -1,6 +1,9 @@ +from unittest.mock import patch + from tests.whist_core.base_test_case import BaseTestCase from whist_core.error.table_error import TeamFullError, TableFullError, TableNotReadyError, \ TableNotStartedError, PlayerNotJoinedError, TableSettingsError +from whist_core.game.errors import RubberNotDoneError from whist_core.game.rubber import Rubber from whist_core.session.matcher import RandomMatcher, RoundRobinMatcher from whist_core.session.table import Table @@ -68,19 +71,21 @@ def test_join_full_table(self): def test_conversion(self): self.table.join(self.player) - table_dict = self.table.dict() + table_dict = self.table.dict(exclude={'matcher'}) table = Table(**table_dict) self.assertEqual(self.table, table) def test_start_random(self): + table = Table(name='test table', min_player=1, max_player=4, matcher=RandomMatcher()) second_player = Player(username='miles', rating=3000) - self.table.join(self.player) - self.table.join(second_player) - self.table.player_ready(self.player) - self.table.player_ready(second_player) - self.table.start(RandomMatcher) - self.assertTrue(self.table.started) - self.assertIsInstance(self.table.current_rubber, Rubber) + table.join(self.player) + table.join(second_player) + table.player_ready(self.player) + table.player_ready(second_player) + table.start() + self.assertTrue(table.started) + self.assertIsInstance(table.current_rubber, Rubber) + self.assertTrue(isinstance(table.matcher, RandomMatcher)) def test_start_robin(self): second_player = Player(username='miles', rating=3000) @@ -88,16 +93,49 @@ def test_start_robin(self): self.table.join(second_player) self.table.player_ready(self.player) self.table.player_ready(second_player) - self.table.start(RoundRobinMatcher) + self.table.start() self.assertTrue(self.table.started) self.assertIsInstance(self.table.current_rubber, Rubber) + self.assertTrue(isinstance(self.table.matcher, RoundRobinMatcher)) def test_not_ready_start(self): self.table.join(self.player) with self.assertRaises(TableNotReadyError): - self.table.start(RandomMatcher) + self.table.start() self.assertFalse(self.table.started) def test_rubber_without_start(self): with self.assertRaises(TableNotStartedError): _ = self.table.current_rubber + + def test_next_rubber(self): + second_player = Player(username='miles', rating=3000) + self.table.join(self.player) + self.table.join(second_player) + self.table.player_ready(self.player) + self.table.player_ready(second_player) + self.table.start() + with patch('whist_core.game.rubber.Rubber.done', return_value=True): + self.table.next_rubber() + self.assertEqual(2, len(self.table.rubbers)) + + def test_next_rubber_not_done(self): + second_player = Player(username='miles', rating=3000) + self.table.join(self.player) + self.table.join(second_player) + self.table.player_ready(self.player) + self.table.player_ready(second_player) + self.table.start() + with self.assertRaises(RubberNotDoneError): + self.table.next_rubber() + self.assertEqual(1, len(self.table.rubbers)) + + def test_next_rubber_first(self): + second_player = Player(username='miles', rating=3000) + self.table.join(self.player) + self.table.join(second_player) + self.table.player_ready(self.player) + self.table.player_ready(second_player) + with self.assertRaises(TableNotStartedError): + self.table.next_rubber() + self.assertEqual(0, len(self.table.rubbers)) diff --git a/whist_core/game/errors.py b/whist_core/game/errors.py index 5a9f6ed5..0ac2ca19 100644 --- a/whist_core/game/errors.py +++ b/whist_core/game/errors.py @@ -51,6 +51,12 @@ class NoTrumpSelectedError(Exception): """ +class RubberNotDoneError(Exception): + """ + Raised if the current rubber is not done, but action requested requires it to be done. + """ + + class TrickDoneError(Exception): """ Raised when the trick is already done. diff --git a/whist_core/session/matcher.py b/whist_core/session/matcher.py index ec3d03d4..26f13d0a 100644 --- a/whist_core/session/matcher.py +++ b/whist_core/session/matcher.py @@ -4,13 +4,15 @@ import abc import random +from pydantic import BaseModel + from whist_core.error.matcher_error import NotEnoughPlayersError from whist_core.scoring.team import Team from whist_core.session.userlist import UserList # pylint: disable=too-few-public-methods -class Matcher(abc.ABC): +class Matcher(abc.ABC, BaseModel): """ Abstrakt class for player to teams matching. """ diff --git a/whist_core/session/table.py b/whist_core/session/table.py index a6415526..375eebeb 100644 --- a/whist_core/session/table.py +++ b/whist_core/session/table.py @@ -3,8 +3,9 @@ from whist_core.error.table_error import TableFullError, TeamFullError, TableNotReadyError, \ TableNotStartedError, TableSettingsError +from whist_core.game.errors import RubberNotDoneError from whist_core.game.rubber import Rubber -from whist_core.session.matcher import Matcher +from whist_core.session.matcher import Matcher, RoundRobinMatcher from whist_core.session.session import Session from whist_core.user.player import Player @@ -18,6 +19,7 @@ class Table(Session): team_size: int = 2 started: bool = False rubbers: list[Rubber] = [] + matcher: Matcher = RoundRobinMatcher() # pylint: disable=no-self-argument @root_validator(pre=True) @@ -67,20 +69,27 @@ def current_rubber(self) -> Rubber: raise TableNotStartedError() return self.rubbers[-1] - def start(self, matcher: Matcher) -> None: + def next_rubber(self) -> Rubber: + """ + Creates the next rubber. In order to create the first rubber use 'Table.start()'. + :return: the new rubber + """ + if len(self.rubbers) == 0: + raise TableNotStartedError() + if self.rubbers[-1].done: + self.rubbers.append(self._create_rubber()) + else: + raise RubberNotDoneError() + return self.current_rubber + + def start(self) -> None: """ Starts the table, but will check if every player is ready first. """ if not self.ready: raise TableNotReadyError() - team_numbers = 2 - players_available_per_team = int(len(self.users) / team_numbers) - teams = matcher.distribute(num_teams=team_numbers, - team_size=min(players_available_per_team, self.team_size), - users=self.users) - rubber = Rubber(teams=teams) - self.rubbers.append(rubber) + self.rubbers.append(self._create_rubber()) self.started = True def join(self, player: Player) -> None: @@ -142,3 +151,13 @@ def player_unready(self, player) -> None: :rtype: None """ self.users.player_unready(player) + + def _create_rubber(self): + team_numbers = 2 + players_available_per_team = int(len(self.users) / team_numbers) + teams = self.matcher.distribute(num_teams=team_numbers, + team_size=min(players_available_per_team, + self.team_size), + users=self.users) + rubber = Rubber(teams=teams) + return rubber