diff --git a/data/lib/api/tournament/tournament_model.dart b/data/lib/api/tournament/tournament_model.dart index f5cfbea9..9e656a61 100644 --- a/data/lib/api/tournament/tournament_model.dart +++ b/data/lib/api/tournament/tournament_model.dart @@ -76,9 +76,7 @@ enum TournamentType { doubleOut(4, minTeamReq: 4), superOver(5, minTeamReq: 2), bestOf(6, minTeamReq: 2), - gully(7, minTeamReq: 2), - mixed(8, minTeamReq: 2), - other(9, minTeamReq: 2); + custom(7, minTeamReq: 2); final int value; final int minTeamReq; diff --git a/data/lib/api/tournament/tournament_model.g.dart b/data/lib/api/tournament/tournament_model.g.dart index 4085349e..a24fcf9b 100644 --- a/data/lib/api/tournament/tournament_model.g.dart +++ b/data/lib/api/tournament/tournament_model.g.dart @@ -60,9 +60,7 @@ const _$TournamentTypeEnumMap = { TournamentType.doubleOut: 4, TournamentType.superOver: 5, TournamentType.bestOf: 6, - TournamentType.gully: 7, - TournamentType.mixed: 8, - TournamentType.other: 9, + TournamentType.custom: 7, }; Value? _$JsonConverterFromJson( diff --git a/data/lib/service/tournament/tournament_service.dart b/data/lib/service/tournament/tournament_service.dart index fa3341c6..30254a5d 100644 --- a/data/lib/service/tournament/tournament_service.dart +++ b/data/lib/service/tournament/tournament_service.dart @@ -186,7 +186,7 @@ class TournamentService { id: tournamentId, name: '', created_by: '', - type: TournamentType.other, + type: TournamentType.knockOut, start_date: DateTime.now(), end_date: DateTime.now().add(const Duration(days: 1)), ); diff --git a/khelo/assets/locales/app_en.arb b/khelo/assets/locales/app_en.arb index 5e9b26b8..e9bcbd1b 100644 --- a/khelo/assets/locales/app_en.arb +++ b/khelo/assets/locales/app_en.arb @@ -303,9 +303,7 @@ "tournament_type_double_out": "Double Out", "tournament_type_super_over": "Super Over", "tournament_type_best_of": "Best Of", - "tournament_type_gully": "Gully", - "tournament_type_mixed": "Mixed", - "tournament_type_other": "Other", + "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.", @@ -313,9 +311,7 @@ "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_super_over_description": "A knockout format with a super over to decide tied matches.\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_gully_description": "Casual street-style cricket with short games and flexible rules.\nMinimum {count} teams required.", - "tournament_type_mixed_description": "Teams are randomly mixed, creating fun and unpredictable matches.\nMinimum {count} teams required.", - "tournament_type_other_description": "A custom format for tournaments with unique rules or structures.\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", "add_team_edit_team_screen_title": "Edit Team", diff --git a/khelo/lib/domain/extensions/enum_extensions.dart b/khelo/lib/domain/extensions/enum_extensions.dart index b80d0e3e..134282ff 100644 --- a/khelo/lib/domain/extensions/enum_extensions.dart +++ b/khelo/lib/domain/extensions/enum_extensions.dart @@ -306,12 +306,8 @@ extension TournamentTypeString on TournamentType { return context.l10n.tournament_type_super_over; case TournamentType.bestOf: return context.l10n.tournament_type_best_of; - case TournamentType.gully: - return context.l10n.tournament_type_gully; - case TournamentType.mixed: - return context.l10n.tournament_type_mixed; - case TournamentType.other: - return context.l10n.tournament_type_other; + case TournamentType.custom: + return context.l10n.tournament_type_custom; } } @@ -329,12 +325,8 @@ extension TournamentTypeString on TournamentType { return context.l10n.tournament_type_super_over_description(minTeamReq); case TournamentType.bestOf: return context.l10n.tournament_type_best_of_description(minTeamReq); - case TournamentType.gully: - return context.l10n.tournament_type_gully_description(minTeamReq); - case TournamentType.mixed: - return context.l10n.tournament_type_mixed_description(minTeamReq); - case TournamentType.other: - return context.l10n.tournament_type_other_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 2d60450d..84a8a46f 100644 --- a/khelo/lib/ui/flow/tournament/match_selection/match_scheduler.dart +++ b/khelo/lib/ui/flow/tournament/match_selection/match_scheduler.dart @@ -58,13 +58,13 @@ class MatchScheduler { case TournamentType.boxLeague: return scheduleBoxLeagueMatches(); case TournamentType.doubleOut: - return scheduleDoubleEliminationMatches(); + return scheduleDoubleOutMatches(); case TournamentType.superOver: return scheduleSuperOverMatches(); case TournamentType.bestOf: return scheduleBestOfMatches(); - default: - throw Exception('Unsupported match type'); + case TournamentType.custom: + return scheduledMatches; } } @@ -88,7 +88,7 @@ class MatchScheduler { groupNumbers.forEach((number, matches) { removeAlreadyScheduledTeams(matches, teamPool); - final teamPairs = createTeamPairsForKnockout(teamPool); + final teamPairs = createKnockoutTeamPairs(teamPool); addMatches(matches, teamPairs, group, number); teamPool.removeWhere((team) => teamPairs @@ -143,7 +143,7 @@ class MatchScheduler { rounds.forEach((number, matches) { removeTeamsThatReachedLimit(matches, teamPool, matchesPerTeam); - final teamPairs = createTeamPairsForRoundRobin( + final teamPairs = createRoundRobinTeamPairs( teamPool, matchesPerTeam, matches @@ -224,7 +224,7 @@ class MatchScheduler { teams.addAll(teamPool.take(boxSize - teams.length + 1)); } - final teamPairs = createTeamPairsForRoundRobin( + final teamPairs = createRoundRobinTeamPairs( teams, teams.length - 1, matches @@ -305,8 +305,39 @@ class MatchScheduler { return additionalScheduledMatches; } - GroupedMatchMap scheduleDoubleEliminationMatches() { - return {}; + GroupedMatchMap scheduleDoubleOutMatches() { + final GroupedMatchMap additionalScheduledMatches = scheduledMatches; + final teamPool = List.of(teams); + + final roundOne = additionalScheduledMatches[MatchGroup.round]?[1] ?? []; + final roundTwo = additionalScheduledMatches[MatchGroup.round]?[2] ?? []; + + final win = scheduleSingleBracketTeams(roundOne, teamPool, true); + final los = scheduleSingleBracketTeams(roundTwo, teamPool, false); + final rounds = {1: roundOne}; + if (roundTwo.isNotEmpty) { + rounds.addAll({2: roundTwo}); + } + + additionalScheduledMatches.addAll({MatchGroup.round: rounds}); + if (win != null && los != null) { + addNewGroupToGroupMap(additionalScheduledMatches, MatchGroup.finals); + final finalRounds = + additionalScheduledMatches[MatchGroup.finals]![1] ?? []; + bool isMatchAdded = finalRounds.any((match) => + match.teams.map((e) => e.team_id).contains(win.id) && + match.teams.map((e) => e.team_id).contains(los.id)); + if (!isMatchAdded) { + addMatches( + additionalScheduledMatches[MatchGroup.finals]![1] ?? [], + [ + [win, los] + ], + MatchGroup.finals, + 1); + } + } + return additionalScheduledMatches; } GroupedMatchMap scheduleSuperOverMatches() { @@ -403,7 +434,7 @@ class MatchScheduler { return teamPoints; } - List> createTeamPairsForRoundRobin(List teamPool, + List> createRoundRobinTeamPairs(List teamPool, int matchesPerTeam, List> scheduledMatches) { final List> teamPairs = []; @@ -444,7 +475,7 @@ class MatchScheduler { return teamPairs; } - List> createTeamPairsForKnockout(List teams) { + List> createKnockoutTeamPairs(List teams) { final List shuffledTeams = List.from(teams)..shuffle(); return shuffledTeams.chunked(2); } @@ -541,4 +572,37 @@ class MatchScheduler { MapEntry(newGroup, {1: []}) ]); } + + TeamModel? scheduleSingleBracketTeams( + List matches, + List teams, + bool isWinBracket, + ) { + final finishedMatches = + matches.where((element) => element.match_status == MatchStatus.finish); + + final loserTeams = finishedMatches.map((e) => e.teams + .firstWhere((element) => element.team_id != e.matchResult!.teamId) + .team); + final unFinishedMatches = + matches.where((element) => element.match_status != MatchStatus.finish); + teams.removeWhere((team) => + loserTeams.contains(team) || + unFinishedMatches + .any((element) => element.teams.map((e) => e.team).contains(team))); + + final chunks = createKnockoutTeamPairs(teams); + addMatches(matches, chunks, MatchGroup.round, isWinBracket ? 1 : 2); + TeamModel? teamToReturn; + if (unFinishedMatches.isEmpty && teams.length == 1) { + teamToReturn = teams.first; + } + teams + .removeWhere((team) => chunks.any((element) => element.contains(team))); + + if (isWinBracket) { + teams.addAll(loserTeams); + } + return teamToReturn; + } }