mirror of
https://github.com/evroon/bracket.git
synced 2026-06-12 10:44:33 -04:00
Fix swiss scheduling (#328)
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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])
|
||||
@@ -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.')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user