diff --git a/PadelClub/Data/GroupStage.swift b/PadelClub/Data/GroupStage.swift index 15eee50..e00435d 100644 --- a/PadelClub/Data/GroupStage.swift +++ b/PadelClub/Data/GroupStage.swift @@ -115,6 +115,25 @@ final class GroupStage: ModelObject, Storable { return match } + func addReturnMatches() { + var teamScores = [TeamScore]() + var matches = [Match]() + + for i in 0..<_numberOfMatchesToBuild() { + let newMatch = self._createMatch(index: i + matchCount) +// let newMatch = Match(groupStage: self.id, index: i, matchFormat: self.matchFormat, name: localizedMatchUpLabel(for: i)) + teamScores.append(contentsOf: newMatch.createTeamScores()) + matches.append(newMatch) + } + + do { + try self.tournamentStore.matches.addOrUpdate(contentOfs: matches) + try self.tournamentStore.teamScores.addOrUpdate(contentOfs: teamScores) + } catch { + Logger.error(error) + } + } + func buildMatches(keepExistingMatches: Bool = false) { var teamScores = [TeamScore]() var matches = [Match]() @@ -291,40 +310,58 @@ final class GroupStage: ModelObject, Storable { return playedMatches.filter({ $0.hasEnded() }).sorted(by: \.computedEndDateForSorting).reversed() } + func isReturnMatchEnabled() -> Bool { + _matches().count > matchCount + } + private func _matchOrder() -> [Int] { + var order: [Int] + switch size { case 3: - return [1, 2, 0] + order = [1, 2, 0] case 4: - return [2, 3, 1, 4, 5, 0] + order = [2, 3, 1, 4, 5, 0] case 5: -// return [5, 8, 0, 7, 3, 4, 2, 6, 1, 9] - return [3, 5, 8, 2, 6, 1, 9, 4, 7, 0] + order = [3, 5, 8, 2, 6, 1, 9, 4, 7, 0] case 6: - //return [1, 7, 13, 11, 3, 6, 10, 2, 8, 12, 5, 4, 9, 14, 0] - return [4, 7, 9, 3, 6, 11, 2, 8, 10, 1, 13, 5, 12, 14, 0] + order = [4, 7, 9, 3, 6, 11, 2, 8, 10, 1, 13, 5, 12, 14, 0] default: - return [] + order = [] + } + + if isReturnMatchEnabled() { + let arraySize = order.count + // Duplicate and increment each value by the array size + order += order.map { $0 + arraySize } } + + return order } - + + func indexOf(_ matchIndex: Int) -> Int { _matchOrder().firstIndex(of: matchIndex) ?? matchIndex } private func _matchUp(for matchIndex: Int) -> [Int] { - Array((0.. String { let matchUp = _matchUp(for: matchIndex) if let index = matchUp.first, let index2 = matchUp.last { - return "#\(index + 1) vs #\(index2 + 1)" + return "#\(index + 1) vs #\(index2 + 1)" + (matchIndex >= matchCount ? " - retour" : "") } else { return "--" } } + var matchCount: Int { + (size * size - 1) / 2 + } + func team(teamPosition team: TeamPosition, inMatchIndex matchIndex: Int) -> TeamRegistration? { let _teams = _teams(for: matchIndex) switch team { @@ -337,7 +374,7 @@ final class GroupStage: ModelObject, Storable { private func _teams(for matchIndex: Int) -> [TeamRegistration?] { let combinations = Array(0.. Bool { let indexes = [teamPosition, otherTeam].compactMap({ $0.groupStagePosition }).sorted() let combos = Array((0.. 1 { + let scoreA = calculateScore(for: teamPosition, matches: matches, groupStagePosition: teamPosition.groupStagePosition!) + let scoreB = calculateScore(for: otherTeam, matches: matches, groupStagePosition: otherTeam.groupStagePosition!) + + let teamsSorted = [scoreA, scoreB].sorted { (lhs, rhs) in + let predicates: [TeamScoreAreInIncreasingOrder] = [ + { $0.wins < $1.wins }, + { $0.setDifference < $1.setDifference }, + { $0.gameDifference < $1.gameDifference}, + { [self] in $0.team.groupStagePositionAtStep(self.step)! > $1.team.groupStagePositionAtStep(self.step)! } + ] + + for predicate in predicates { + if !predicate(lhs, rhs) && !predicate(rhs, lhs) { + continue + } + + return predicate(lhs, rhs) + } + + return false + }.map({ $0.team }) + + return teamsSorted.first == teamPosition } else { - return false + + if let matchIndex = combos.firstIndex(of: indexes), let match = _matches().first(where: { $0.index == matchIndex }) { + return teamPosition.id == match.losingTeamId + } else { + return false + } + } } @@ -428,16 +495,19 @@ final class GroupStage: ModelObject, Storable { guard let team = teamAt(groupStagePosition: groupStagePosition) else { return nil } let matches = matches(forGroupStagePosition: groupStagePosition).filter({ $0.hasEnded() }) if matches.isEmpty && nilIfEmpty { return nil } + let score = calculateScore(for: team, matches: matches, groupStagePosition: groupStagePosition) + scoreCache[groupStagePosition] = score + return score + } + + private func calculateScore(for team: TeamRegistration, matches: [Match], groupStagePosition: Int) -> TeamGroupStageScore { let wins = matches.filter { $0.winningTeamId == team.id }.count let loses = matches.filter { $0.losingTeamId == team.id }.count let differences = matches.compactMap { $0.scoreDifference(groupStagePosition, atStep: step) } let setDifference = differences.map { $0.set }.reduce(0,+) let gameDifference = differences.map { $0.game }.reduce(0,+) - // Calculate the score and store it in the cache - let score = (team, wins, loses, setDifference, gameDifference) - scoreCache[groupStagePosition] = score - return score + return (team, wins, loses, setDifference, gameDifference) } // Clear the cache if necessary, for example when starting a new step or when matches update diff --git a/PadelClub/Views/GroupStage/Components/GroupStageSettingsView.swift b/PadelClub/Views/GroupStage/Components/GroupStageSettingsView.swift index ad0d943..9f7851a 100644 --- a/PadelClub/Views/GroupStage/Components/GroupStageSettingsView.swift +++ b/PadelClub/Views/GroupStage/Components/GroupStageSettingsView.swift @@ -149,6 +149,12 @@ struct GroupStageSettingsView: View { Text("Tous les matchs seront recronstruits, les données des matchs seront perdus.") } + Section { + RowButtonView("Rajouter les matchs retours", role: .destructive) { + groupStage.addReturnMatches() + } + } + Section { RowButtonView("Rafraichir", role: .destructive) { let playedMatches = groupStage.playedMatches()