diff --git a/PadelClub/Data/Match.swift b/PadelClub/Data/Match.swift index 7877f00..2e4432c 100644 --- a/PadelClub/Data/Match.swift +++ b/PadelClub/Data/Match.swift @@ -126,19 +126,17 @@ class Match: ModelObject, Storable { _toggleMatchDisableState(false) } - func _toggleLoserMatchDisableState(_ state: Bool) { + private func _toggleLoserMatchDisableState(_ state: Bool) { if isLoserBracket == false { let indexInRound = RoundRule.matchIndexWithinRound(fromMatchIndex: index) if let loserMatch = roundObject?.loserRounds().first?.getMatch(atMatchIndexInRound: indexInRound / 2) { - print("disabling first loserround", state, loserMatch.matchTitle(.wide)) loserMatch.disabled = state try? DataStore.shared.matches.addOrUpdate(instance: loserMatch) loserMatch._toggleLoserMatchDisableState(state) } } else { roundObject?.loserRounds().forEach({ round in - print("disabling", state, round.roundTitle()) - round.disableLoserRound(state) + round.handleLoserRoundState() }) } } diff --git a/PadelClub/Data/Round.swift b/PadelClub/Data/Round.swift index 68a4378..b7090f2 100644 --- a/PadelClub/Data/Round.swift +++ b/PadelClub/Data/Round.swift @@ -140,10 +140,10 @@ class Round: ModelObject, Storable { func getMatch(atMatchIndexInRound matchIndexInRound: Int) -> Match? { - _matches().first(where: { + Store.main.filter(isIncluded: { let index = RoundRule.matchIndexWithinRound(fromMatchIndex: $0.index) - return index == matchIndexInRound - }) + return $0.round == id && index == matchIndexInRound + }).first } func playedMatches() -> [Match] { @@ -176,32 +176,53 @@ class Round: ModelObject, Storable { } func enableRound() { + _toggleRound(disable: false) + } + + func disableRound() { + _toggleRound(disable: true) + } + + private func _toggleRound(disable: Bool) { let _matches = _matches() _matches.forEach { match in - match.disabled = false + match.disabled = disable match.resetMatch() try? DataStore.shared.teamScores.delete(contentOfs: match.teamScores) } try? DataStore.shared.matches.addOrUpdate(contentOfs: _matches) } - func disableLoserRound(_ disable: Bool) { + func handleLoserRoundState() { let _matches = _matches() _matches.forEach { match in - if disable { - if upperBracketTopMatch(ofMatchIndex: match.index)?.disabled == true || upperBracketBottomMatch(ofMatchIndex: match.index)?.disabled == true { - match.disabled = true - } - } else { - if upperBracketTopMatch(ofMatchIndex: match.index)?.disabled == false && upperBracketBottomMatch(ofMatchIndex: match.index)?.disabled == false { - match.disabled = false - } + let previousRound = self.previousRound() + let indexInRound = RoundRule.matchIndexWithinRound(fromMatchIndex: match.index) + var parentMatches = [Match]() + if isLoserBracket(), previousRound == nil, let parentRound = parentRound { + let upperBracketTopMatch = parentRound.getMatch(atMatchIndexInRound: indexInRound * 2) + let upperBracketBottomMatch = parentRound.getMatch(atMatchIndexInRound: indexInRound * 2 + 1) + parentMatches = [upperBracketTopMatch, upperBracketBottomMatch].compactMap({ $0 }) + } else if let previousRound { + let previousRoundTopMatch : Match? = Store.main.filter { + $0.round == previousRound.id && $0.index == match.topPreviousRoundMatchIndex() + }.first + let previousRoundBottomMatch : Match? = Store.main.filter { + $0.round == previousRound.id && $0.index == match.bottomPreviousRoundMatchIndex() + }.first + parentMatches = [previousRoundTopMatch, previousRoundBottomMatch].compactMap({ $0 }) + } + + if parentMatches.anySatisfy({ $0.disabled }) { + match.disabled = true + } else if parentMatches.allSatisfy({ $0.disabled == false }) { + match.disabled = false } } try? DataStore.shared.matches.addOrUpdate(contentOfs: _matches) loserRounds().forEach { round in - round.disableLoserRound(disable) + round.handleLoserRoundState() } } diff --git a/PadelClub/Data/TeamRegistration.swift b/PadelClub/Data/TeamRegistration.swift index 1891628..d945a78 100644 --- a/PadelClub/Data/TeamRegistration.swift +++ b/PadelClub/Data/TeamRegistration.swift @@ -62,7 +62,6 @@ class TeamRegistration: ModelObject, Storable { if opposingSeeding { teamPosition = slot ?? (isUpper ? .two : .one) } - match.enableMatch() match.previousMatch(teamPosition)?.disableMatch() bracketPosition = matchIndex * 2 + teamPosition.rawValue } diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index 8c65c16..b93c344 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -143,11 +143,11 @@ class Tournament : ModelObject, Storable { return seeds().filter { $0.isSeedable() } } - func lastSeedRound() -> Int? { + func lastSeedRound() -> Int { if let last = seeds().filter({ $0.bracketPosition != nil }).last { return RoundRule.roundIndex(fromMatchIndex: last.bracketPosition! / 2) } else { - return nil + return 0 } } @@ -213,24 +213,67 @@ class Tournament : ModelObject, Storable { return availableSeeds } - func setSeeds(inRoundIndex roundIndex: Int, inSeedGroup seedGroup: SeedInterval) { - let availableSeedSpot = availableSeedSpot(inRoundIndex: roundIndex) - let availableSeedOpponentSpot = availableSeedOpponentSpot(inRoundIndex: roundIndex) - let availableSeeds = seeds(inSeedGroup: seedGroup) + func seedGroupAvailable(atRoundIndex roundIndex: Int) -> SeedInterval? { + if let availableSeedGroup = availableSeedGroup() { + return seedGroupAvailable(atRoundIndex: roundIndex, availableSeedGroup: availableSeedGroup) + } else { + return nil + } + } + + func seedGroupAvailable(atRoundIndex roundIndex: Int, availableSeedGroup: SeedInterval) -> SeedInterval? { + + if availableSeeds().isEmpty == false && roundIndex >= lastSeedRound() { + + if availableSeedGroup == SeedInterval(first: 1, last: 2) { return availableSeedGroup } + + let availableSeeds = seeds(inSeedGroup: availableSeedGroup) + let availableSeedSpot = availableSeedSpot(inRoundIndex: roundIndex) + let availableSeedOpponentSpot = availableSeedOpponentSpot(inRoundIndex: roundIndex) + + if availableSeeds.count == availableSeedSpot.count { + return availableSeedGroup + } else if (availableSeeds.count == availableSeedOpponentSpot.count && availableSeeds.count == self.availableSeeds().count) { + return availableSeedGroup + } else if let chunk = availableSeedGroup.chunk() { + return seedGroupAvailable(atRoundIndex: roundIndex, availableSeedGroup: chunk) + } + } - if availableSeeds.count <= availableSeedSpot.count { - let spots = availableSeedSpot.shuffled() - for (index, seed) in availableSeeds.enumerated() { - seed.setSeedPosition(inSpot: spots[index], slot: nil, opposingSeeding: false) + return nil + } + + func setSeeds(inRoundIndex roundIndex: Int, inSeedGroup seedGroup: SeedInterval) { + if seedGroup == SeedInterval(first: 1, last: 2) { + let seeds = seeds() + if let matches = getRound(atRoundIndex: roundIndex)?.playedMatches() { + if let lastMatch = matches.last { + seeds.prefix(1).first?.setSeedPosition(inSpot: lastMatch, slot: .two, opposingSeeding: false) + } + if let firstMatch = matches.first { + seeds.prefix(2).dropFirst().first?.setSeedPosition(inSpot: firstMatch, slot: .one, opposingSeeding: false) + } } - } else if (availableSeeds.count <= availableSeedOpponentSpot.count && availableSeeds.count <= self.availableSeeds().count) { + } else { - let spots = availableSeedOpponentSpot.shuffled() - for (index, seed) in availableSeeds.enumerated() { - seed.setSeedPosition(inSpot: spots[index], slot: nil, opposingSeeding: true) + let availableSeedSpot = availableSeedSpot(inRoundIndex: roundIndex) + let availableSeedOpponentSpot = availableSeedOpponentSpot(inRoundIndex: roundIndex) + let availableSeeds = seeds(inSeedGroup: seedGroup) + + if availableSeeds.count <= availableSeedSpot.count { + let spots = availableSeedSpot.shuffled() + for (index, seed) in availableSeeds.enumerated() { + seed.setSeedPosition(inSpot: spots[index], slot: nil, opposingSeeding: false) + } + } else if (availableSeeds.count <= availableSeedOpponentSpot.count && availableSeeds.count <= self.availableSeeds().count) { + + let spots = availableSeedOpponentSpot.shuffled() + for (index, seed) in availableSeeds.enumerated() { + seed.setSeedPosition(inSpot: spots[index], slot: nil, opposingSeeding: true) + } + } else if let chunk = seedGroup.chunk() { + setSeeds(inRoundIndex: roundIndex, inSeedGroup: chunk) } - } else if let chunk = seedGroup.chunk() { - setSeeds(inRoundIndex: roundIndex, inSeedGroup: chunk) } } diff --git a/PadelClub/ViewModel/SeedInterval.swift b/PadelClub/ViewModel/SeedInterval.swift index 506be68..d0a82c0 100644 --- a/PadelClub/ViewModel/SeedInterval.swift +++ b/PadelClub/ViewModel/SeedInterval.swift @@ -16,11 +16,12 @@ struct SeedInterval: Hashable, Comparable { } func chunk() -> SeedInterval? { - if last - (last - first) / 2 > first { - return SeedInterval(first: first, last: last - (last - first) / 2) - } else { - return nil + if (last - first) / 2 > 0 { + if last - (last - first) / 2 > first { + return SeedInterval(first: first, last: last - (last - first) / 2) + } } + return nil } } diff --git a/PadelClub/Views/Match/PlayerBlockView.swift b/PadelClub/Views/Match/PlayerBlockView.swift index 3b9aa15..68ee799 100644 --- a/PadelClub/Views/Match/PlayerBlockView.swift +++ b/PadelClub/Views/Match/PlayerBlockView.swift @@ -46,7 +46,6 @@ struct PlayerBlockView: View { if match.upperBracketMatch(teamPosition)?.disabled == true { return "Bye" } - return teamPosition.localizedLabel() } diff --git a/PadelClub/Views/Round/LoserRoundsView.swift b/PadelClub/Views/Round/LoserRoundsView.swift index f4e6063..fd9dd32 100644 --- a/PadelClub/Views/Round/LoserRoundsView.swift +++ b/PadelClub/Views/Round/LoserRoundsView.swift @@ -81,22 +81,14 @@ struct LoserRoundView: View { if _roundDisabled() { RowButtonView("Jouer ce tour", role: .destructive) { loserRounds.forEach { round in - let matches = round.playedMatches() - matches.forEach { match in - if round.upperBracketTopMatch(ofMatchIndex: match.index)?.disabled == false && round.upperBracketBottomMatch(ofMatchIndex: match.index)?.disabled == false { - match.disabled = false - } - } - - try? dataStore.matches.addOrUpdate(contentOfs: matches) + round.enableRound() + round.handleLoserRoundState() } } } else { RowButtonView("Ne pas jouer ce tour", role: .destructive) { loserRounds.forEach { round in - round.playedMatches().forEach { match in - match.disabled = true - } + round.disableRound() } } } diff --git a/PadelClub/Views/Round/RoundSettingsView.swift b/PadelClub/Views/Round/RoundSettingsView.swift index daabeae..8a412a0 100644 --- a/PadelClub/Views/Round/RoundSettingsView.swift +++ b/PadelClub/Views/Round/RoundSettingsView.swift @@ -11,93 +11,17 @@ struct RoundSettingsView: View { @EnvironmentObject var dataStore: DataStore @Environment(\.editMode) private var editMode @Environment(Tournament.self) var tournament: Tournament - @State private var roundIndex: Int? - - var round: Round? { - guard let roundIndex else { return nil } - return tournament.rounds()[roundIndex] - } var body: some View { List { - if let availableSeedGroup = tournament.availableSeedGroup() { - Section { - - Picker(selection: $roundIndex) { - Text("choisir de la manche").tag(nil as Int?) - ForEach(tournament.rounds()) { round in - Text(round.roundTitle()).tag(round.index as Int?) - } - } label: { - Text(availableSeedGroup.localizedLabel()) - } - - if let roundIndex { - - RowButtonView("Valider") { - if availableSeedGroup == SeedInterval(first: 1, last: 2) { - let seeds = tournament.seeds() -// let startIndex = RoundRule.matchIndex(fromRoundIndex: roundIndex) -// let numberOfMatchInRound = RoundRule.numberOfMatches(forRoundIndex: roundIndex) -// let lastIndex = startIndex + numberOfMatchInRound - 1 -// seeds.prefix(1).first?.bracketPosition = lastIndex * 2 + 1 //TS 1 branche du bas du dernier match -// seeds.prefix(2).dropFirst().first?.bracketPosition = startIndex * 2 //TS 2 branche du haut du premier match - - if let matches = tournament.getRound(atRoundIndex: roundIndex)?.playedMatches() { - if let lastMatch = matches.last { - seeds.prefix(1).first?.setSeedPosition(inSpot: lastMatch, slot: .two, opposingSeeding: false) - } - if let firstMatch = matches.first { - seeds.prefix(2).dropFirst().first?.setSeedPosition(inSpot: firstMatch, slot: .one, opposingSeeding: false) - } - } - try? dataStore.teamRegistrations.addOrUpdate(contentOfs: seeds) - } else { - tournament.setSeeds(inRoundIndex: roundIndex, inSeedGroup: availableSeedGroup) - try? dataStore.teamRegistrations.addOrUpdate(contentOfs: tournament.seeds()) - } - - if tournament.availableSeeds().isEmpty { - editMode?.wrappedValue = .inactive - } - } - } - - } header: { - Text("Placement des têtes de série") - } - } -// -// Section { -// RowButtonView("Effacer classement", role: .destructive) { -// tournament.rounds().forEach { round in -// try? dataStore.rounds.delete(contentOfs: round.loserRounds()) -// } -// } -// } -// -// Section { -// RowButtonView("Match de classement") { -// tournament.rounds().forEach { round in -// round.buildLoserBracket() -// } -// } -// } Section { RowButtonView("Retirer toutes les têtes de séries", role: .destructive) { tournament.unsortedTeams().forEach({ $0.bracketPosition = nil }) try? dataStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams()) tournament.allRounds().forEach({ round in round.enableRound() - }) - } - } - - Section { - if let lastRound = tournament.rounds().first { // first is final, last round - RowButtonView("Supprimer " + lastRound.roundTitle(), role: .destructive) { - try? dataStore.rounds.delete(instance: lastRound) - } + }) + editMode?.wrappedValue = .active } } @@ -116,6 +40,13 @@ struct RoundSettingsView: View { } } + Section { + if let lastRound = tournament.rounds().first { // first is final, last round + RowButtonView("Supprimer " + lastRound.roundTitle(), role: .destructive) { + try? dataStore.rounds.delete(instance: lastRound) + } + } + } } } } diff --git a/PadelClub/Views/Round/RoundView.swift b/PadelClub/Views/Round/RoundView.swift index 58f7d62..cc1cb11 100644 --- a/PadelClub/Views/Round/RoundView.swift +++ b/PadelClub/Views/Round/RoundView.swift @@ -10,6 +10,7 @@ import SwiftUI struct RoundView: View { @Environment(\.editMode) private var editMode @Environment(Tournament.self) var tournament: Tournament + @EnvironmentObject var dataStore: DataStore var round: Round @@ -29,6 +30,16 @@ struct RoundView: View { } } } + } else if let availableSeedGroup = tournament.seedGroupAvailable(atRoundIndex: round.index) { + + RowButtonView("Placer \(availableSeedGroup.localizedLabel())") { + tournament.setSeeds(inRoundIndex: round.index, inSeedGroup: availableSeedGroup) + try? dataStore.teamRegistrations.addOrUpdate(contentOfs: tournament.seeds()) + + if tournament.availableSeeds().isEmpty { + editMode?.wrappedValue = .inactive + } + } } ForEach(round.playedMatches()) { match in