Skip to content

Commit 664b13b

Browse files
authored
Fix swiss scheduling (#328)
1 parent 68aff95 commit 664b13b

File tree

14 files changed

+78
-735
lines changed

14 files changed

+78
-735
lines changed

backend/bracket/logic/scheduling/builder.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ async def create_rounds_for_new_stage_item(tournament_id: int, stage_item: Stage
3131
rounds_count = get_number_of_rounds_to_create_round_robin(stage_item.team_count)
3232
case StageType.SINGLE_ELIMINATION:
3333
rounds_count = get_number_of_rounds_to_create_single_elimination(stage_item.team_count)
34+
case StageType.SWISS:
35+
return None
3436
case other:
3537
raise NotImplementedError(f'No round creation implementation for {other}')
3638

@@ -60,6 +62,8 @@ async def build_matches_for_stage_item(stage_item: StageItem, tournament_id: int
6062
await build_round_robin_stage_item(tournament_id, stage_item_with_rounds)
6163
case StageType.SINGLE_ELIMINATION:
6264
await build_single_elimination_stage_item(tournament_id, stage_item_with_rounds)
65+
case StageType.SWISS:
66+
return None
6367

6468
case _:
6569
raise HTTPException(

backend/bracket/logic/scheduling/ladder_players_iter.py

Lines changed: 0 additions & 127 deletions
This file was deleted.

backend/bracket/logic/scheduling/ladder_teams.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@
55
MatchFilter,
66
MatchWithDetailsDefinitive,
77
SuggestedMatch,
8-
SuggestedVirtualMatch,
98
)
109
from bracket.sql.rounds import get_rounds_for_stage_item
1110
from bracket.sql.teams import get_teams_with_members
1211

1312

14-
async def todo_get_possible_upcoming_matches_for_teams(
15-
tournament_id: int, filter_: MatchFilter, stage_id: int
16-
) -> list[SuggestedMatch | SuggestedVirtualMatch]:
17-
suggestions: list[SuggestedMatch | SuggestedVirtualMatch] = []
18-
rounds = await get_rounds_for_stage_item(tournament_id, stage_id) # TODO: fix stage item id
13+
async def get_possible_upcoming_matches_for_teams(
14+
tournament_id: int, filter_: MatchFilter, stage_item_id: int
15+
) -> list[SuggestedMatch]:
16+
suggestions: list[SuggestedMatch] = []
17+
rounds = await get_rounds_for_stage_item(tournament_id, stage_item_id)
1918
draft_round = next((round_ for round_ in rounds if round_.is_draft), None)
2019
if draft_round is None:
2120
raise HTTPException(400, 'There is no draft round, so no matches can be scheduled.')

backend/bracket/logic/scheduling/shared.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def check_team_combination_adheres_to_filter(
2424

2525
suggested_match = get_suggested_match(team1, team2)
2626

27-
if suggested_match.elo_diff < filter_.elo_diff_threshold:
27+
if suggested_match.elo_diff <= filter_.elo_diff_threshold:
2828
return suggested_match
2929

3030
return None
Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from fastapi import HTTPException
22

3-
from bracket.logic.scheduling.ladder_players_iter import get_possible_upcoming_matches_for_players
4-
from bracket.models.db.match import MatchFilter, SuggestedMatch, SuggestedVirtualMatch
3+
from bracket.logic.scheduling.ladder_teams import get_possible_upcoming_matches_for_teams
4+
from bracket.models.db.match import MatchFilter, SuggestedMatch
55
from bracket.models.db.round import Round
66
from bracket.models.db.stage_item import StageType
77
from bracket.sql.stages import get_full_tournament_details
@@ -10,16 +10,14 @@
1010

1111
async def get_upcoming_matches_for_swiss_round(
1212
match_filter: MatchFilter, round_: Round, tournament_id: int
13-
) -> list[SuggestedMatch | SuggestedVirtualMatch]:
13+
) -> list[SuggestedMatch]:
1414
[stage] = await get_full_tournament_details(tournament_id, stage_item_id=round_.stage_item_id)
1515
assert len(stage.stage_items) == 1
1616
[stage_item] = stage.stage_items
1717

1818
if stage_item.type is not StageType.SWISS:
1919
raise HTTPException(400, 'There is no draft round, so no matches can be scheduled.')
2020

21-
upcoming_matches = await get_possible_upcoming_matches_for_players(
22-
tournament_id, match_filter, assert_some(stage_item.id), assert_some(round_.id)
21+
return await get_possible_upcoming_matches_for_teams(
22+
tournament_id, match_filter, assert_some(stage_item.id)
2323
)
24-
25-
return upcoming_matches

backend/bracket/models/db/match.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,6 @@ class MatchFilter(BaseModel):
102102
iterations: int
103103

104104

105-
class SuggestedVirtualMatch(BaseModel):
106-
team1_winner_from_stage_item_id: int
107-
team1_position_in_group: int
108-
team2_winner_from_stage_item_id: int
109-
team2_position_in_group: int
110-
111-
112105
class SuggestedMatch(BaseModel):
113106
team1: TeamWithPlayers
114107
team2: TeamWithPlayers

backend/bracket/models/db/team.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,6 @@ class TeamWithPlayers(BaseModel):
2929
draws: int
3030
losses: int
3131

32-
@classmethod
33-
def from_players(cls, players: list[Player]) -> TeamWithPlayers:
34-
return TeamWithPlayers(
35-
players=players,
36-
elo_score=Decimal(sum(p.elo_score for p in players) / len(players)),
37-
swiss_score=Decimal(sum(p.swiss_score for p in players) / len(players)),
38-
wins=sum(p.wins for p in players) // len(players),
39-
draws=sum(p.draws for p in players) // len(players),
40-
losses=sum(p.losses for p in players) // len(players),
41-
)
42-
4332
@property
4433
def player_ids(self) -> list[int]:
4534
return [assert_some(player.id) for player in self.players]

backend/bracket/routes/matches.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
)
2020
from bracket.models.db.round import Round
2121
from bracket.models.db.user import UserPublic
22+
from bracket.models.db.util import RoundWithMatches
2223
from bracket.routes.auth import user_authenticated_for_tournament
2324
from bracket.routes.models import SingleMatchResponse, SuccessResponse, UpcomingMatchesResponse
24-
from bracket.routes.util import match_dependency, round_dependency
25+
from bracket.routes.util import match_dependency, round_dependency, round_with_matches_dependency
26+
from bracket.sql.courts import get_all_courts_in_tournament
2527
from bracket.sql.matches import sql_delete_match, sql_update_match
2628
from bracket.utils.types import assert_some
2729

@@ -34,7 +36,7 @@
3436
)
3537
async def get_matches_to_schedule(
3638
tournament_id: int,
37-
elo_diff_threshold: int = 100,
39+
elo_diff_threshold: int = 200,
3840
iterations: int = 200,
3941
only_behind_schedule: bool = False,
4042
limit: int = 50,
@@ -109,7 +111,7 @@ async def create_matches_automatically(
109111
iterations: int = 200,
110112
only_behind_schedule: bool = False,
111113
_: UserPublic = Depends(user_authenticated_for_tournament),
112-
round_: Round = Depends(round_dependency),
114+
round_: RoundWithMatches = Depends(round_with_matches_dependency),
113115
) -> SuccessResponse:
114116
if not round_.is_draft:
115117
raise HTTPException(400, 'There is no draft round, so no matches can be scheduled.')
@@ -120,8 +122,9 @@ async def create_matches_automatically(
120122
limit=1,
121123
iterations=iterations,
122124
)
125+
courts = await get_all_courts_in_tournament(tournament_id)
123126

124-
limit = 15
127+
limit = len(courts) - len(round_.matches)
125128
for __ in range(limit):
126129
all_matches_to_schedule = await get_upcoming_matches_for_swiss_round(
127130
match_filter, round_, tournament_id

backend/bracket/routes/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from bracket.models.db.club import Club
77
from bracket.models.db.court import Court
8-
from bracket.models.db.match import Match, SuggestedMatch, SuggestedVirtualMatch
8+
from bracket.models.db.match import Match, SuggestedMatch
99
from bracket.models.db.player import Player
1010
from bracket.models.db.stage_item_inputs import (
1111
StageItemInputOptionFinal,
@@ -56,7 +56,7 @@ class StagesWithStageItemsResponse(DataResponse[list[StageWithStageItems]]):
5656
pass
5757

5858

59-
class UpcomingMatchesResponse(DataResponse[list[SuggestedMatch | SuggestedVirtualMatch]]):
59+
class UpcomingMatchesResponse(DataResponse[list[SuggestedMatch]]):
6060
pass
6161

6262

backend/bracket/routes/util.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from bracket.models.db.team import FullTeamWithPlayers, Team
88
from bracket.models.db.util import RoundWithMatches, StageItemWithRounds, StageWithStageItems
99
from bracket.schema import matches, rounds, teams
10+
from bracket.sql.rounds import get_round_by_id
1011
from bracket.sql.stage_items import get_stage_item
1112
from bracket.sql.stages import get_full_tournament_details
1213
from bracket.sql.teams import get_teams_with_members
@@ -30,20 +31,14 @@ async def round_dependency(tournament_id: int, round_id: int) -> Round:
3031

3132

3233
async def round_with_matches_dependency(tournament_id: int, round_id: int) -> RoundWithMatches:
33-
stages = await get_full_tournament_details(
34-
tournament_id, no_draft_rounds=False, round_id=round_id
35-
)
36-
37-
for stage in stages:
38-
for stage_item in stage.stage_items:
39-
for round_ in stage_item.rounds:
40-
if round_ is not None:
41-
return round_
34+
round_ = await get_round_by_id(tournament_id, round_id)
35+
if round_ is None:
36+
raise HTTPException(
37+
status_code=status.HTTP_404_NOT_FOUND,
38+
detail=f"Could not find round with id {round_id}",
39+
)
4240

43-
raise HTTPException(
44-
status_code=status.HTTP_404_NOT_FOUND,
45-
detail=f"Could not find round with id {round_id}",
46-
)
41+
return round_
4742

4843

4944
async def stage_dependency(tournament_id: int, stage_id: int) -> StageWithStageItems:

0 commit comments

Comments
 (0)