diff --git a/data/lib/api/tournament/tournament_model.dart b/data/lib/api/tournament/tournament_model.dart index 9458b365..87473840 100644 --- a/data/lib/api/tournament/tournament_model.dart +++ b/data/lib/api/tournament/tournament_model.dart @@ -74,7 +74,7 @@ enum TournamentType { miniRobin(2, minTeamReq: 3), boxLeague(3, minTeamReq: 4), doubleOut(4, minTeamReq: 4), - bestOf(6, minTeamReq: 2), + bestOfThree(6, minTeamReq: 2), custom(7, minTeamReq: 2); final int value; diff --git a/data/lib/api/tournament/tournament_model.g.dart b/data/lib/api/tournament/tournament_model.g.dart index 7c1a0900..df91f380 100644 --- a/data/lib/api/tournament/tournament_model.g.dart +++ b/data/lib/api/tournament/tournament_model.g.dart @@ -58,7 +58,7 @@ const _$TournamentTypeEnumMap = { TournamentType.miniRobin: 2, TournamentType.boxLeague: 3, TournamentType.doubleOut: 4, - TournamentType.bestOf: 6, + TournamentType.bestOfThree: 6, TournamentType.custom: 7, }; diff --git a/khelo/assets/locales/app_en.arb b/khelo/assets/locales/app_en.arb index 6d348c14..90f4c496 100644 --- a/khelo/assets/locales/app_en.arb +++ b/khelo/assets/locales/app_en.arb @@ -301,14 +301,14 @@ "tournament_type_mini_robin": "Mini Robin", "tournament_type_box_league": "Box League", "tournament_type_double_out": "Double Out", - "tournament_type_best_of": "Best Of three", + "tournament_type_best_of_three": "Best Of three", "tournament_type_custom": "Custom", "tournament_type_knock_out_description": "Teams face off in a single elimination, with the loser immediately knocked out.\nMinimum {count} teams required.", "tournament_type_mini_robin_description": "A smaller round-robin format where each team plays once against all others.\nMinimum {count} teams required.", "tournament_type_box_league_description": "Teams are divided into groups, with top teams advancing to the knockout stage.\nMinimum {count} teams required.", "tournament_type_double_out_description": "Teams get two chances before being knocked out, with a winners and losers bracket.\nMinimum {count} teams required.", - "tournament_type_best_of_description": "Teams play a series of matches, and the first to win the majority is the champion.\nMinimum {count} teams required.", + "tournament_type_best_of_three_description": "Teams play a series of matches, and the first to win the majority is the champion.\nMinimum {count} teams required.", "tournament_type_custom_description": "Fully flexible, create a structure that suits your needs.\nMinimum {count} teams required.", "add_team_screen_title": "Add Team", diff --git a/khelo/lib/domain/extensions/enum_extensions.dart b/khelo/lib/domain/extensions/enum_extensions.dart index 298bd31b..e1a8d9a2 100644 --- a/khelo/lib/domain/extensions/enum_extensions.dart +++ b/khelo/lib/domain/extensions/enum_extensions.dart @@ -302,8 +302,8 @@ extension TournamentTypeString on TournamentType { return context.l10n.tournament_type_box_league; case TournamentType.doubleOut: return context.l10n.tournament_type_double_out; - case TournamentType.bestOf: - return context.l10n.tournament_type_best_of; + case TournamentType.bestOfThree: + return context.l10n.tournament_type_best_of_three; case TournamentType.custom: return context.l10n.tournament_type_custom; } @@ -319,8 +319,8 @@ extension TournamentTypeString on TournamentType { return context.l10n.tournament_type_box_league_description(minTeamReq); case TournamentType.doubleOut: return context.l10n.tournament_type_double_out_description(minTeamReq); - case TournamentType.bestOf: - return context.l10n.tournament_type_best_of_description(minTeamReq); + case TournamentType.bestOfThree: + return context.l10n.tournament_type_best_of_three_description(minTeamReq); case TournamentType.custom: return context.l10n.tournament_type_custom_description(minTeamReq); } diff --git a/khelo/lib/ui/flow/tournament/match_selection/match_scheduler.dart b/khelo/lib/ui/flow/tournament/match_selection/match_scheduler.dart index 397f94a1..a81541d8 100644 --- a/khelo/lib/ui/flow/tournament/match_selection/match_scheduler.dart +++ b/khelo/lib/ui/flow/tournament/match_selection/match_scheduler.dart @@ -61,9 +61,8 @@ class MatchScheduler { return scheduleBoxLeagueMatches(); case TournamentType.doubleOut: return scheduleDoubleOutMatches(); - case TournamentType.bestOf: - // return scheduleBestOfMatchesLoopingApproach(); - return scheduleBestOfMatchesHybridApproach(); + case TournamentType.bestOfThree: + return scheduleBestOfThreeMatches(); case TournamentType.custom: return scheduledMatches; } @@ -341,40 +340,7 @@ class MatchScheduler { return additionalScheduledMatches; } - GroupedMatchMap scheduleBestOfMatchesLoopingApproach() { - final GroupedMatchMap additionalScheduledMatches = - Map.from(scheduledMatches); - final List teamPool = List.of(teams); - - var currentGroup = MatchGroup.round; - var currentRound = 1; - - while (teamPool.length > 1) { - final group = - additionalScheduledMatches.putIfAbsent(currentGroup, () => {1: []}); - final matches = group[currentRound] ?? []; - final expectedQualifiers = handleSingleBestOfThreePhase( - matches, teamPool, currentGroup, currentRound); - group[currentRound] = matches; - - if (expectedQualifiers > 8) { - currentRound++; - } else if (expectedQualifiers > 4) { - currentRound = 1; - currentGroup = MatchGroup.quarterfinal; - } else if (expectedQualifiers > 2) { - currentRound = 1; - currentGroup = MatchGroup.semifinal; - } else if (expectedQualifiers == 2) { - currentRound = 1; - currentGroup = MatchGroup.finals; - } - } - - return additionalScheduledMatches; - } - - GroupedMatchMap scheduleBestOfMatchesHybridApproach() { + GroupedMatchMap scheduleBestOfThreeMatches() { final GroupedMatchMap additionalScheduledMatches = Map.from(scheduledMatches); final List teamPool = List.of(teams); @@ -392,8 +358,12 @@ class MatchScheduler { expectedQualifiers = handleSingleBestOfThreePhase( matches, teamPool, currentGroup, currentRound); } else { - expectedQualifiers = - handleSingleKnockoutPhase(matches, teamPool, currentGroup, currentRound); + expectedQualifiers = handleSingleKnockoutPhase( + matches, + teamPool, + currentGroup, + currentRound, + ); } group[currentRound] = matches; @@ -415,137 +385,6 @@ class MatchScheduler { return additionalScheduledMatches; } - List> createTeamPairsForBestOfThree(List teams) { - final List> pairs = []; - for (int i = 0; i < teams.length; i++) { - for (int j = i + 1; j < teams.length; j++) { - pairs.add([teams[i], teams[j]]); - } - } - return pairs; - } - - MatchModel createBestOfThreeMatch( - TeamModel teamA, - TeamModel teamB, - MatchGroup group, - int roundNumber, - ) { - return MatchModel( - id: '', - teams: [ - MatchTeamModel(team_id: teamA.id, team: teamA), - MatchTeamModel(team_id: teamB.id, team: teamB), - ], - match_type: MatchType.limitedOvers, - number_of_over: 10, - over_per_bowler: 2, - city: '', - ground: '', - ball_type: BallType.leather, - pitch_type: PitchType.rough, - created_by: '', - match_status: MatchStatus.yetToStart, - match_group: group, - match_group_number: roundNumber, - ); - } - - GroupedMatchMap scheduleBestOfMatches() { - final GroupedMatchMap additionalScheduledMatches = scheduledMatches; - final List teamPool = List.from(teams); - - final roundOne = additionalScheduledMatches[MatchGroup.round]?[1] ?? []; - final quarterfinal = - additionalScheduledMatches[MatchGroup.quarterfinal]?[1] ?? []; - final semifinal = - additionalScheduledMatches[MatchGroup.semifinal]?[1] ?? []; - final finals = additionalScheduledMatches[MatchGroup.finals]?[1] ?? []; - - final roundWinners = - scheduleBestOfMatchesForRound(roundOne, teamPool, MatchGroup.round); - additionalScheduledMatches.addAll({ - MatchGroup.round: {1: roundOne} - }); - - List qualifiedTeams = roundWinners; - if (roundWinners.length > 4) { - qualifiedTeams = scheduleBestOfMatchesForRound( - quarterfinal, - roundWinners, - MatchGroup.quarterfinal, - ); - additionalScheduledMatches.addAll({ - MatchGroup.quarterfinal: {1: quarterfinal} - }); - } - - // Semifinals - if (qualifiedTeams.length > 2) { - qualifiedTeams = scheduleBestOfMatchesForRound( - semifinal, qualifiedTeams, MatchGroup.semifinal); - additionalScheduledMatches.addAll({ - MatchGroup.semifinal: {1: semifinal} - }); - } - - // Finals - if (qualifiedTeams.length == 2) { - scheduleBestOfMatchesForRound( - finals, - qualifiedTeams, - MatchGroup.finals, - ); - additionalScheduledMatches.addAll({ - MatchGroup.finals: {1: finals} - }); - } - - return additionalScheduledMatches; - } - - List scheduleBestOfMatchesForRound( - List matches, - List teamPool, - MatchGroup group, { - bool isTiebreaker = false, - }) { - final Map roundWinners = {}; - final List> teamPairs = - createTeamPairsForBestOfThree(teamPool); - - for (var pair in teamPairs) { - final teamA = pair[0]; - final teamB = pair[1]; - - final existingMatches = matches.where((match) { - return match.teams.any((team) => pair.contains(team.team)); - }).toList(); - - for (int i = existingMatches.length; i < 2; i++) { - final newMatch = createBestOfThreeMatch(teamA, teamB, group, 1); - matches.add(newMatch); - } - - final teamAWins = existingMatches - .where((match) => match.matchResult?.teamId == teamA.id) - .length; - final teamBWins = existingMatches - .where((match) => match.matchResult?.teamId == teamB.id) - .length; - - if (teamAWins == 1 && teamBWins == 1 && !isTiebreaker) { - matches.add(createBestOfThreeMatch(teamA, teamB, group, 1)); - } else if (teamAWins == 2) { - roundWinners[teamA.id] = teamA; - } else if (teamBWins == 2) { - roundWinners[teamB.id] = teamB; - } - } - - return roundWinners.values.toList(); - } - List calculateTeamPoints( List matches, List teams) { List teamPoints = teams @@ -790,8 +629,12 @@ class MatchScheduler { return teamToReturn; } - int handleSingleKnockoutPhase(List matches, List teamPool, - MatchGroup group, int number) { + int handleSingleKnockoutPhase( + List matches, + List teamPool, + MatchGroup group, + int number, + ) { removeAlreadyScheduledTeams(matches, teamPool); final teamPairs = createKnockoutTeamPairs(teamPool); @@ -892,7 +735,18 @@ class MatchScheduler { } else if (result.winType == WinnerByType.tie) { final runRateOne = element.getRunRate(teamOne); final runRateTwo = element.getRunRate(teamTwo); - final win = (runRateOne > runRateTwo ? teamOne : teamTwo); + String? win; + if (runRateOne != runRateTwo) { + win = (runRateOne > runRateTwo ? teamOne : teamTwo); + } else { + final wicketsOne = element.teams + .firstWhere((team) => team.team.id == teamOne) + .wicket; + final wicketsTwo = element.teams + .firstWhere((team) => team.team.id == teamTwo) + .wicket; + win = (wicketsOne > wicketsTwo ? teamOne : teamTwo); + } if (winner.containsKey(win)) { winner[win] = winner[win]! + 1; }