Fix swiss scheduling (#328)

This commit is contained in:
Erik Vroon
2023-11-11 10:59:52 +01:00
committed by GitHub
parent 68aff95fe4
commit 664b13b0db
14 changed files with 80 additions and 737 deletions

View File

@@ -31,6 +31,8 @@ async def create_rounds_for_new_stage_item(tournament_id: int, stage_item: Stage
rounds_count = get_number_of_rounds_to_create_round_robin(stage_item.team_count)
case StageType.SINGLE_ELIMINATION:
rounds_count = get_number_of_rounds_to_create_single_elimination(stage_item.team_count)
case StageType.SWISS:
return None
case other:
raise NotImplementedError(f'No round creation implementation for {other}')
@@ -60,6 +62,8 @@ async def build_matches_for_stage_item(stage_item: StageItem, tournament_id: int
await build_round_robin_stage_item(tournament_id, stage_item_with_rounds)
case StageType.SINGLE_ELIMINATION:
await build_single_elimination_stage_item(tournament_id, stage_item_with_rounds)
case StageType.SWISS:
return None
case _:
raise HTTPException(

View File

@@ -1,127 +0,0 @@
import random
from collections import defaultdict
from functools import lru_cache
from typing import cast
from fastapi import HTTPException
from bracket.logic.scheduling.shared import check_team_combination_adheres_to_filter
from bracket.models.db.match import (
MatchFilter,
MatchWithDetailsDefinitive,
SuggestedMatch,
SuggestedVirtualMatch,
)
from bracket.models.db.player import Player
from bracket.models.db.team import TeamWithPlayers
from bracket.models.db.util import RoundWithMatches
from bracket.sql.players import get_active_players_in_tournament
from bracket.sql.stage_items import get_stage_item
from bracket.utils.types import assert_some
# TODO: needs refactor
# pylint: disable=too-many-branches
def player_already_scheduled(player: Player, draft_round: RoundWithMatches) -> bool:
return any(
player.id in match.player_ids
for match in draft_round.matches
if isinstance(match, MatchWithDetailsDefinitive)
)
async def get_possible_upcoming_matches_for_players(
tournament_id: int, filter_: MatchFilter, stage_item_id: int, round_id: int
) -> list[SuggestedMatch | SuggestedVirtualMatch]:
random.seed(10)
suggestions: set[SuggestedMatch] = set()
stage_item = await get_stage_item(tournament_id, stage_item_id)
if stage_item is None:
raise ValueError(
f'Could not find stage item with id {stage_item_id} for tournament {tournament_id}'
)
draft_round = next((round_ for round_ in stage_item.rounds if round_.id == round_id), None)
other_rounds = [round_ for round_ in stage_item.rounds if not round_.is_draft]
max_matches_per_round = (
max(len(other_round.matches) for other_round in other_rounds)
if len(other_rounds) > 0
else 10
)
@lru_cache
def team_already_scheduled_before(player1: Player, player2: Player) -> bool:
return any(
player1 in match.team1.players and player2 in match.team2.players
for round_ in other_rounds
for match in round_.matches
if isinstance(match, MatchWithDetailsDefinitive)
)
team_already_scheduled_before.cache_clear()
if draft_round is None:
raise HTTPException(400, 'There is no draft round, so no matches can be scheduled.')
players = await get_active_players_in_tournament(tournament_id)
players_match_count: dict[int, int] = defaultdict(int)
for round_ in other_rounds:
for match_ in round_.matches:
if isinstance(match_, MatchWithDetailsDefinitive):
for player_id in match_.player_ids:
players_match_count[player_id] += 1
for player in players:
if player.id not in players_match_count:
players_match_count[assert_some(player.id)] = 0
max_played_matches = max(players_match_count.values())
player_ids_behind_schedule = [
player_id
for player_id, played in players_match_count.items()
if played != max_played_matches
]
players_behind_schedule = [
player for player in players if player.id in player_ids_behind_schedule
]
players_to_consider = players_behind_schedule if filter_.only_behind_schedule else players
players_to_schedule = [
player
for player in players_to_consider
if not player_already_scheduled(player, draft_round)
]
if len(players_to_schedule) < 4:
return []
for i in range(filter_.iterations):
possible_players = random.sample(players_to_schedule, 4)
team1_players, team2_players = possible_players[:2], possible_players[2:4]
if team_already_scheduled_before(
team1_players[0], team1_players[1]
) or team_already_scheduled_before(team2_players[0], team2_players[1]):
continue
team1 = TeamWithPlayers.from_players(team1_players)
team2 = TeamWithPlayers.from_players(team2_players)
suggested_match = check_team_combination_adheres_to_filter(team1, team2, filter_)
if suggested_match:
suggested_match.player_behind_schedule_count = sum(
1 if player.id in player_ids_behind_schedule else 0
for player in team1_players + team2_players
)
suggestions.add(suggested_match)
result = sorted(
list(suggestions),
key=lambda s: s.elo_diff - (int(1e9) * s.player_behind_schedule_count),
)
for i in range(min(max_matches_per_round, len(result))):
result[i].is_recommended = True
team_already_scheduled_before.cache_clear()
return cast(list[SuggestedMatch | SuggestedVirtualMatch], result[: filter_.limit])

View File

@@ -5,17 +5,16 @@ from bracket.models.db.match import (
MatchFilter,
MatchWithDetailsDefinitive,
SuggestedMatch,
SuggestedVirtualMatch,
)
from bracket.sql.rounds import get_rounds_for_stage_item
from bracket.sql.teams import get_teams_with_members
async def todo_get_possible_upcoming_matches_for_teams(
tournament_id: int, filter_: MatchFilter, stage_id: int
) -> list[SuggestedMatch | SuggestedVirtualMatch]:
suggestions: list[SuggestedMatch | SuggestedVirtualMatch] = []
rounds = await get_rounds_for_stage_item(tournament_id, stage_id) # TODO: fix stage item id
async def get_possible_upcoming_matches_for_teams(
tournament_id: int, filter_: MatchFilter, stage_item_id: int
) -> list[SuggestedMatch]:
suggestions: list[SuggestedMatch] = []
rounds = await get_rounds_for_stage_item(tournament_id, stage_item_id)
draft_round = next((round_ for round_ in rounds if round_.is_draft), None)
if draft_round is None:
raise HTTPException(400, 'There is no draft round, so no matches can be scheduled.')

View File

@@ -24,7 +24,7 @@ def check_team_combination_adheres_to_filter(
suggested_match = get_suggested_match(team1, team2)
if suggested_match.elo_diff < filter_.elo_diff_threshold:
if suggested_match.elo_diff <= filter_.elo_diff_threshold:
return suggested_match
return None

View File

@@ -1,7 +1,7 @@
from fastapi import HTTPException
from bracket.logic.scheduling.ladder_players_iter import get_possible_upcoming_matches_for_players
from bracket.models.db.match import MatchFilter, SuggestedMatch, SuggestedVirtualMatch
from bracket.logic.scheduling.ladder_teams import get_possible_upcoming_matches_for_teams
from bracket.models.db.match import MatchFilter, SuggestedMatch
from bracket.models.db.round import Round
from bracket.models.db.stage_item import StageType
from bracket.sql.stages import get_full_tournament_details
@@ -10,7 +10,7 @@ from bracket.utils.types import assert_some
async def get_upcoming_matches_for_swiss_round(
match_filter: MatchFilter, round_: Round, tournament_id: int
) -> list[SuggestedMatch | SuggestedVirtualMatch]:
) -> list[SuggestedMatch]:
[stage] = await get_full_tournament_details(tournament_id, stage_item_id=round_.stage_item_id)
assert len(stage.stage_items) == 1
[stage_item] = stage.stage_items
@@ -18,8 +18,6 @@ async def get_upcoming_matches_for_swiss_round(
if stage_item.type is not StageType.SWISS:
raise HTTPException(400, 'There is no draft round, so no matches can be scheduled.')
upcoming_matches = await get_possible_upcoming_matches_for_players(
tournament_id, match_filter, assert_some(stage_item.id), assert_some(round_.id)
return await get_possible_upcoming_matches_for_teams(
tournament_id, match_filter, assert_some(stage_item.id)
)
return upcoming_matches

View File

@@ -102,13 +102,6 @@ class MatchFilter(BaseModel):
iterations: int
class SuggestedVirtualMatch(BaseModel):
team1_winner_from_stage_item_id: int
team1_position_in_group: int
team2_winner_from_stage_item_id: int
team2_position_in_group: int
class SuggestedMatch(BaseModel):
team1: TeamWithPlayers
team2: TeamWithPlayers

View File

@@ -29,17 +29,6 @@ class TeamWithPlayers(BaseModel):
draws: int
losses: int
@classmethod
def from_players(cls, players: list[Player]) -> TeamWithPlayers:
return TeamWithPlayers(
players=players,
elo_score=Decimal(sum(p.elo_score for p in players) / len(players)),
swiss_score=Decimal(sum(p.swiss_score for p in players) / len(players)),
wins=sum(p.wins for p in players) // len(players),
draws=sum(p.draws for p in players) // len(players),
losses=sum(p.losses for p in players) // len(players),
)
@property
def player_ids(self) -> list[int]:
return [assert_some(player.id) for player in self.players]

View File

@@ -19,9 +19,11 @@ from bracket.models.db.match import (
)
from bracket.models.db.round import Round
from bracket.models.db.user import UserPublic
from bracket.models.db.util import RoundWithMatches
from bracket.routes.auth import user_authenticated_for_tournament
from bracket.routes.models import SingleMatchResponse, SuccessResponse, UpcomingMatchesResponse
from bracket.routes.util import match_dependency, round_dependency
from bracket.routes.util import match_dependency, round_dependency, round_with_matches_dependency
from bracket.sql.courts import get_all_courts_in_tournament
from bracket.sql.matches import sql_delete_match, sql_update_match
from bracket.utils.types import assert_some
@@ -34,7 +36,7 @@ router = APIRouter()
)
async def get_matches_to_schedule(
tournament_id: int,
elo_diff_threshold: int = 100,
elo_diff_threshold: int = 200,
iterations: int = 200,
only_behind_schedule: bool = False,
limit: int = 50,
@@ -109,7 +111,7 @@ async def create_matches_automatically(
iterations: int = 200,
only_behind_schedule: bool = False,
_: UserPublic = Depends(user_authenticated_for_tournament),
round_: Round = Depends(round_dependency),
round_: RoundWithMatches = Depends(round_with_matches_dependency),
) -> SuccessResponse:
if not round_.is_draft:
raise HTTPException(400, 'There is no draft round, so no matches can be scheduled.')
@@ -120,8 +122,9 @@ async def create_matches_automatically(
limit=1,
iterations=iterations,
)
courts = await get_all_courts_in_tournament(tournament_id)
limit = 15
limit = len(courts) - len(round_.matches)
for __ in range(limit):
all_matches_to_schedule = await get_upcoming_matches_for_swiss_round(
match_filter, round_, tournament_id

View File

@@ -5,7 +5,7 @@ from pydantic.generics import GenericModel
from bracket.models.db.club import Club
from bracket.models.db.court import Court
from bracket.models.db.match import Match, SuggestedMatch, SuggestedVirtualMatch
from bracket.models.db.match import Match, SuggestedMatch
from bracket.models.db.player import Player
from bracket.models.db.stage_item_inputs import (
StageItemInputOptionFinal,
@@ -56,7 +56,7 @@ class StagesWithStageItemsResponse(DataResponse[list[StageWithStageItems]]):
pass
class UpcomingMatchesResponse(DataResponse[list[SuggestedMatch | SuggestedVirtualMatch]]):
class UpcomingMatchesResponse(DataResponse[list[SuggestedMatch]]):
pass

View File

@@ -7,6 +7,7 @@ from bracket.models.db.round import Round
from bracket.models.db.team import FullTeamWithPlayers, Team
from bracket.models.db.util import RoundWithMatches, StageItemWithRounds, StageWithStageItems
from bracket.schema import matches, rounds, teams
from bracket.sql.rounds import get_round_by_id
from bracket.sql.stage_items import get_stage_item
from bracket.sql.stages import get_full_tournament_details
from bracket.sql.teams import get_teams_with_members
@@ -30,20 +31,14 @@ async def round_dependency(tournament_id: int, round_id: int) -> Round:
async def round_with_matches_dependency(tournament_id: int, round_id: int) -> RoundWithMatches:
stages = await get_full_tournament_details(
tournament_id, no_draft_rounds=False, round_id=round_id
)
round_ = await get_round_by_id(tournament_id, round_id)
if round_ is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Could not find round with id {round_id}",
)
for stage in stages:
for stage_item in stage.stage_items:
for round_ in stage_item.rounds:
if round_ is not None:
return round_
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Could not find round with id {round_id}",
)
return round_
async def stage_dependency(tournament_id: int, stage_id: int) -> StageWithStageItems:

View File

@@ -13,17 +13,6 @@ async def get_all_players_in_tournament(tournament_id: int) -> list[Player]:
return [Player.parse_obj(x._mapping) for x in result]
async def get_active_players_in_tournament(tournament_id: int) -> list[Player]:
query = '''
SELECT *
FROM players
WHERE players.tournament_id = :tournament_id
AND players.active IS TRUE
'''
result = await database.fetch_all(query=query, values={'tournament_id': tournament_id})
return [Player.parse_obj(x._mapping) for x in result]
async def update_player_stats(
tournament_id: int, player_id: int, player_statistics: PlayerStatistics
) -> None:

View File

@@ -1,6 +1,7 @@
from bracket.database import database
from bracket.models.db.util import RoundWithMatches
from bracket.sql.stage_items import get_stage_item
from bracket.sql.stages import get_full_tournament_details
async def get_rounds_for_stage_item(
@@ -16,6 +17,20 @@ async def get_rounds_for_stage_item(
return stage_item.rounds
async def get_round_by_id(tournament_id: int, round_id: int) -> RoundWithMatches | None:
stages = await get_full_tournament_details(
tournament_id, no_draft_rounds=False, round_id=round_id
)
for stage in stages:
for stage_item in stage.stage_items:
for round_ in stage_item.rounds:
if round_ is not None:
return round_
return None
async def get_next_round_name(tournament_id: int, stage_item_id: int) -> str:
query = '''
SELECT count(*) FROM rounds

View File

@@ -206,25 +206,25 @@ async def test_upcoming_matches_endpoint(
update={'elo_score': 1100, 'tournament_id': auth_context.tournament.id}
),
assert_some(team1_inserted.id),
),
) as player_inserted_1,
inserted_player_in_team(
DUMMY_PLAYER2.copy(
update={'elo_score': 1300, 'tournament_id': auth_context.tournament.id}
),
assert_some(team2_inserted.id),
),
) as player_inserted_2,
inserted_player_in_team(
DUMMY_PLAYER3.copy(
update={'elo_score': 1200, 'tournament_id': auth_context.tournament.id}
),
assert_some(team1_inserted.id),
),
) as player_inserted_3,
inserted_player_in_team(
DUMMY_PLAYER4.copy(
update={'elo_score': 1400, 'tournament_id': auth_context.tournament.id}
),
assert_some(team2_inserted.id),
),
) as player_inserted_4,
):
json_response = await send_tournament_request(
HTTPMethod.GET, f'rounds/{round_inserted.id}/upcoming_matches', auth_context, {}
@@ -233,595 +233,77 @@ async def test_upcoming_matches_endpoint(
'data': [
{
'team1': {
'id': None,
'id': team2_inserted.id,
'players': [
{
'id': 4,
'id': player_inserted_2.id,
'active': True,
'name': 'Player 4',
'name': 'Player 2',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1400.0,
'swiss_score': 0.0,
'elo_score': 1300,
'swiss_score': 0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 1,
'id': player_inserted_4.id,
'active': True,
'name': 'Player 1',
'name': 'Player 4',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1100.0,
'swiss_score': 0.0,
'elo_score': 1400,
'swiss_score': 0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'elo_score': 1350.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'team2': {
'id': None,
'id': team1_inserted.id,
'players': [
{
'id': 2,
'active': True,
'name': 'Player 2',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1300.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 3,
'active': True,
'name': 'Player 3',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1200.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'elo_diff': 0.0,
'swiss_diff': 0.0,
'is_recommended': True,
'player_behind_schedule_count': 0,
},
{
'team1': {
'id': None,
'players': [
{
'id': 4,
'active': True,
'name': 'Player 4',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1400.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 1,
'id': player_inserted_1.id,
'active': True,
'name': 'Player 1',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1100.0,
'swiss_score': 0.0,
'elo_score': 1100,
'swiss_score': 0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'team2': {
'id': None,
'players': [
{
'id': 3,
'id': player_inserted_3.id,
'active': True,
'name': 'Player 3',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1200.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 2,
'active': True,
'name': 'Player 2',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1300.0,
'swiss_score': 0.0,
'elo_score': 1200,
'swiss_score': 0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'elo_score': 1150.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'elo_diff': 0.0,
'swiss_diff': 0.0,
'is_recommended': True,
'elo_diff': 200,
'swiss_diff': 0,
'is_recommended': False,
'player_behind_schedule_count': 0,
},
{
'team1': {
'id': None,
'players': [
{
'id': 2,
'active': True,
'name': 'Player 2',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1300.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 3,
'active': True,
'name': 'Player 3',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1200.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'team2': {
'id': None,
'players': [
{
'id': 1,
'active': True,
'name': 'Player 1',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1100.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 4,
'active': True,
'name': 'Player 4',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1400.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'elo_diff': 0.0,
'swiss_diff': 0.0,
'is_recommended': True,
'player_behind_schedule_count': 0,
},
{
'team1': {
'id': None,
'players': [
{
'id': 1,
'active': True,
'name': 'Player 1',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1100.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 4,
'active': True,
'name': 'Player 4',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1400.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'team2': {
'id': None,
'players': [
{
'id': 2,
'active': True,
'name': 'Player 2',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1300.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 3,
'active': True,
'name': 'Player 3',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1200.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'elo_diff': 0.0,
'swiss_diff': 0.0,
'is_recommended': True,
'player_behind_schedule_count': 0,
},
{
'team1': {
'id': None,
'players': [
{
'id': 3,
'active': True,
'name': 'Player 3',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1200.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 2,
'active': True,
'name': 'Player 2',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1300.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'team2': {
'id': None,
'players': [
{
'id': 4,
'active': True,
'name': 'Player 4',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1400.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 1,
'active': True,
'name': 'Player 1',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1100.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'elo_diff': 0.0,
'swiss_diff': 0.0,
'is_recommended': True,
'player_behind_schedule_count': 0,
},
{
'team1': {
'id': None,
'players': [
{
'id': 3,
'active': True,
'name': 'Player 3',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1200.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 2,
'active': True,
'name': 'Player 2',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1300.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'team2': {
'id': None,
'players': [
{
'id': 1,
'active': True,
'name': 'Player 1',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1100.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 4,
'active': True,
'name': 'Player 4',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1400.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'elo_diff': 0.0,
'swiss_diff': 0.0,
'is_recommended': True,
'player_behind_schedule_count': 0,
},
{
'team1': {
'id': None,
'players': [
{
'id': 1,
'active': True,
'name': 'Player 1',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1100.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 4,
'active': True,
'name': 'Player 4',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1400.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'team2': {
'id': None,
'players': [
{
'id': 3,
'active': True,
'name': 'Player 3',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1200.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 2,
'active': True,
'name': 'Player 2',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1300.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'elo_diff': 0.0,
'swiss_diff': 0.0,
'is_recommended': True,
'player_behind_schedule_count': 0,
},
{
'team1': {
'id': None,
'players': [
{
'id': 2,
'active': True,
'name': 'Player 2',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1300.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 3,
'active': True,
'name': 'Player 3',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1200.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'team2': {
'id': None,
'players': [
{
'id': 4,
'active': True,
'name': 'Player 4',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1400.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
{
'id': 1,
'active': True,
'name': 'Player 1',
'created': '2022-01-11T04:32:11+00:00',
'tournament_id': 1,
'elo_score': 1100.0,
'swiss_score': 0.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
],
'swiss_score': 0.0,
'elo_score': 1250.0,
'wins': 0,
'draws': 0,
'losses': 0,
},
'elo_diff': 0.0,
'swiss_diff': 0.0,
'is_recommended': True,
'player_behind_schedule_count': 0,
},
}
]
}

View File

@@ -12,6 +12,7 @@ import { getTournamentIdFromRouter, responseIsValid } from '../../components/uti
import { SchedulerSettings } from '../../interfaces/match';
import { RoundInterface } from '../../interfaces/round';
import { StageWithStageItems, getActiveStages } from '../../interfaces/stage';
import { StageItemWithRounds } from '../../interfaces/stage_item';
import { Tournament, getTournamentEndpoint } from '../../interfaces/tournament';
import {
checkForAuthError,
@@ -57,10 +58,12 @@ export default function TournamentPage() {
if (isResponseValid) {
[activeStage] = getActiveStages(swrStagesResponse);
if (activeStage != null && activeStage.rounds != null) {
const draftRounds = activeStage.rounds.filter((round: RoundInterface) => round.is_draft);
if (draftRounds != null && draftRounds.length > 0) {
[draftRound] = draftRounds;
if (activeStage != null && activeStage.stage_items != null) {
const draftRounds = activeStage.stage_items.map((stageItem: StageItemWithRounds) =>
stageItem.rounds.filter((round: RoundInterface) => round.is_draft)
);
if (draftRounds != null && draftRounds.length > 0 && draftRounds[0].length > 0) {
[[draftRound]] = draftRounds;
}
}