Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX: amount of player required at creation #276

Merged
merged 15 commits into from
Nov 26, 2022
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tool.poetry]
name = "whist-core"
# remember to also update the version in __init__.py!
version = "0.7.0"
version = "0.7.1"
iTitus marked this conversation as resolved.
Show resolved Hide resolved
description = "Whist rules implementation"
authors = ["Whist-Team"]
license = "MIT"
Expand Down
24 changes: 19 additions & 5 deletions tests/whist_core/session/test_matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ def setUp(self) -> None:
player_d = Player(user_id=5, username='d', rating=1)
self.players = [player_a, player_b, player_c, player_d]
self.user_list = UserList()
self.random_matcher = RandomMatcher(number_teams=2, team_size=2)
self.robin_matcher = RoundRobinMatcher(number_teams=2, team_size=2)
self.random_matcher = RandomMatcher(number_teams=2)
Segelzwerg marked this conversation as resolved.
Show resolved Hide resolved
self.robin_matcher = RoundRobinMatcher(number_teams=2)
for player in self.players:
self.user_list.append(player)

Expand All @@ -36,13 +36,27 @@ def test_round_robin_distribute(self):
self.assertEqual(distribution[3].player_index, 3)
self.assertEqual(distribution[3].team_id, 1)

def test_random_min_player_distribute(self):
user_list = UserList()
user_list.append(self.players[0])
user_list.append(self.players[1])
random_matcher = RandomMatcher(number_teams=2)
distribution = random_matcher.distribute(user_list)
self.assertEqual(distribution[0].player_index, 0)
self.assertEqual(distribution[0].team_id, 0)
self.assertEqual(distribution[1].player_index, 1)
self.assertEqual(len(user_list), len(distribution))

def test_round_robin_min_player_distribute(self):
user_list = UserList()
user_list.append(self.players[0])
user_list.append(self.players[1])
random_matcher = RandomMatcher(number_teams=2, team_size=2)
with self.assertRaises(NotEnoughPlayersError):
_ = random_matcher.distribute(user_list)
robin_matcher = RoundRobinMatcher(number_teams=2)
distribution = robin_matcher.distribute(user_list)
self.assertEqual(distribution[0].player_index, 0)
self.assertEqual(distribution[0].team_id, 0)
self.assertEqual(distribution[1].player_index, 1)
self.assertEqual(len(user_list), len(distribution))

def test_second_round_robin(self):
_ = self.robin_matcher.distribute(self.user_list)
Expand Down
22 changes: 14 additions & 8 deletions tests/whist_core/session/test_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,31 @@ def setUp(self) -> None:
super().setUp()
self.mock_user_list = MagicMock()
self.table = Table(name='test table', min_player=1, max_player=4,
matcher=RoundRobinMatcher(number_teams=2, team_size=2))
matcher=RoundRobinMatcher(number_teams=2))

def test_table_random_matcher_from_dict(self):
self.table.matcher = RandomMatcher(number_teams=2, team_size=2)
self.table.matcher = RandomMatcher(number_teams=2)
table_from_dict = Table(**self.table.dict())
self.assertEqual(self.table, table_from_dict)
self.assertIsInstance(table_from_dict.matcher, RandomMatcher)

def test_table_random_matcher_from_dict_generic(self):
self.table.matcher = RandomMatcher(number_teams=2, team_size=2)
self.table.matcher = RandomMatcher(number_teams=2)
table_dict = dict(self.table)
table_from_dict = Table(**table_dict)
self.assertEqual(self.table, table_from_dict)
self.assertIsInstance(table_from_dict.matcher, RandomMatcher)

def test_table_random_matcher_from_json(self):
self.table.matcher = RandomMatcher(number_teams=2, team_size=2)
self.table.matcher = RandomMatcher(number_teams=2)
table_json = self.table.json()
table_dict_from_json = json.loads(table_json)
table_from_json = Table(**table_dict_from_json)
self.assertEqual(self.table, table_from_json)
self.assertIsInstance(table_from_json.matcher, RandomMatcher)

def test_table_random_matcher_from_json_generic(self):
self.table.matcher = RandomMatcher(number_teams=2, team_size=2)
self.table.matcher = RandomMatcher(number_teams=2)
table_json = self.table.json()
table_from_json = Table(**json.loads(table_json))
self.assertEqual(self.table, table_from_json)
Expand All @@ -49,7 +49,7 @@ def test_table_random_matcher_from_json_generic(self):
def test_min_max_validation(self):
with self.assertRaises(TableSettingsError):
_ = Table(name='faulty table', min_player=3, max_player=2,
matcher=RandomMatcher(number_teams=2, team_size=2))
matcher=RandomMatcher(number_teams=2))

def test_ready(self):
self.table.join(self.player)
Expand All @@ -64,7 +64,7 @@ def test_not_ready(self):

def test_not_ready_min_player(self):
table = Table(name='test table', min_player=2, max_player=4,
matcher=RandomMatcher(number_teams=2, team_size=2))
matcher=RandomMatcher(number_teams=2))
table.join(self.player)
table.player_ready(self.player)
self.assertFalse(table.ready)
Expand Down Expand Up @@ -109,7 +109,7 @@ def test_conversion(self):
self.assertEqual(self.table, table)

def test_start_random(self):
self.table.matcher = RandomMatcher(number_teams=2, team_size=2)
self.table.matcher = RandomMatcher(number_teams=2)
self._ready_four_players()
self.table.start()
self.assertTrue(self.table.started)
Expand All @@ -125,6 +125,12 @@ def test_start_robin(self):
self.assertIsInstance(self.table.current_rubber, Rubber)
self.assertTrue(isinstance(self.table.matcher, RoundRobinMatcher))

def test_start_early(self):
self.table.join(self.player)
self.table.player_ready(self.player)
self.table.start()
self.assertTrue(self.table.started)

def test_not_ready_start(self):
self.table.join(self.player)
with self.assertRaises(TableNotReadyError):
Expand Down
2 changes: 1 addition & 1 deletion whist_core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os

# remember to also update the version in pyproject.toml!
__version__ = '0.7.0'
__version__ = '0.7.1'
iTitus marked this conversation as resolved.
Show resolved Hide resolved

ALGORITHM = os.getenv('ALGORITHM', 'HS256')
SECRET_KEY = os.getenv('SECRET_KEY', 'geheim')
30 changes: 15 additions & 15 deletions whist_core/session/matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ class Matcher(abc.ABC, BaseModel):
"""
teams: list[Distribution] = []
number_teams: int
team_size: int

def __init_subclass__(cls, **kwargs: Any) -> None:
"""
Expand Down Expand Up @@ -59,23 +58,14 @@ class RoundRobinMatcher(Matcher):
iteration: int = 0
distributions: list[Distribution] = []

def __init__(self, number_teams: int, team_size: int, **data):
def __init__(self, number_teams: int, **data):
"""
Constructor. See details in base class.
:param number_teams:
:param team_size:
:param data:
"""
super().__init__(number_teams=number_teams, team_size=team_size, **data)
number_players = self.team_size * self.number_teams

if len(self.distributions) == 0:
for distribution_int in sorted(
set(permutations((x % self.number_teams for x in range(number_players))))):
distribution = Distribution()
for player_index, team_id in enumerate(distribution_int):
distribution.add(DistributionEntry(player_index=player_index, team_id=team_id))
self.distributions.append(distribution)
super().__init__(number_teams=number_teams, **data)

def distribute(self, users: UserList) -> Distribution:
"""
Expand All @@ -84,12 +74,23 @@ def distribute(self, users: UserList) -> Distribution:
:param users: the players to be distributed to teams
:return: the teams in round robin distribution
"""
if len(self.distributions) != len(users):
self.distributions = []
self._precalculate_distributions(len(users))
distribution = self.distributions[self.iteration]
self.iteration += 1
self._apply_distribution(distribution)

return distribution

def _precalculate_distributions(self, number_players: int):
for distribution_int in sorted(
set(permutations((x % self.number_teams for x in range(number_players))))):
distribution = Distribution()
for player_index, team_id in enumerate(distribution_int):
distribution.add(DistributionEntry(player_index=player_index, team_id=team_id))
self.distributions.append(distribution)


class RandomMatcher(Matcher):
"""
Expand All @@ -103,9 +104,8 @@ def distribute(self, users: UserList) -> Distribution:
:rtype: None
"""
players = users.players
if len(players) != self.number_teams * self.team_size:
raise NotEnoughPlayersError()
teams: list = list(range(0, self.team_size)) * self.number_teams
team_size: int = int(len(players) / self.number_teams)
teams: list = list(range(0, team_size)) * self.number_teams
distribution: Distribution = Distribution()
for player_index in range(len(players)):
team_id = random.choice(teams) # nosec random
Expand Down