fix wip scheduler

multistore
Razmig Sarkissian 1 year ago
parent 5ca9f8f462
commit 039110785a
  1. 4
      PadelClub.xcodeproj/project.pbxproj
  2. 45
      PadelClub/Data/MatchScheduler.swift
  3. 1
      PadelClub/Views/Club/ClubRowView.swift
  4. 25
      PadelClub/Views/Planning/PlanningSettingsView.swift
  5. 2
      PadelClub/Views/Planning/PlanningView.swift

@ -1859,7 +1859,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 47;
CURRENT_PROJECT_VERSION = 48;
DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6;
@ -1896,7 +1896,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 47;
CURRENT_PROJECT_VERSION = 48;
DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6;

@ -363,6 +363,7 @@ class MatchScheduler : ModelObject, Storable {
var rotationIndex = 0
var availableMatchs = flattenedMatches.filter({ $0.startDate == nil })
let courtsUnavailability = courtsUnavailability
var issueFound: Bool = false
flattenedMatches.filter { $0.startDate != nil }.sorted(by: \.startDate!).forEach { match in
if _startDate == nil {
@ -388,7 +389,7 @@ class MatchScheduler : ModelObject, Storable {
var shouldStartAtDispatcherDate = rotationIndex > 0
while availableMatchs.count > 0 {
while availableMatchs.count > 0 && issueFound == false {
freeCourtPerRotation[rotationIndex] = []
let previousRotationSlots = slots.filter({ $0.rotationIndex == rotationIndex - 1 })
var rotationStartDate: Date = getNextStartDate(fromPreviousRotationSlots: previousRotationSlots, includeBreakTime: false) ?? dispatcherStartDate
@ -431,6 +432,13 @@ class MatchScheduler : ModelObject, Storable {
rotationStartDate = rotationStartDate.addingTimeInterval(-difference)
}
}
} else if let first = availableMatchs.first {
let duration = first.matchFormat.getEstimatedDuration(additionalEstimationDuration)
let courtsUnavailable = courtsUnavailable(startDate: rotationStartDate, duration: duration, courtsUnavailability: courtsUnavailability)
if courtsUnavailable == numberOfCourtsAvailablePerRotation {
print("issue")
issueFound = true
}
}
dispatchCourts(availableCourts: numberOfCourtsAvailablePerRotation, courts: courts, availableMatchs: &availableMatchs, slots: &slots, rotationIndex: rotationIndex, rotationStartDate: rotationStartDate, freeCourtPerRotation: &freeCourtPerRotation, courtsUnavailability: courtsUnavailability)
@ -450,7 +458,7 @@ class MatchScheduler : ModelObject, Storable {
}
return MatchDispatcher(timedMatches: slots, freeCourtPerRotation: freeCourtPerRotation, rotationCount: rotationIndex)
return MatchDispatcher(timedMatches: slots, freeCourtPerRotation: freeCourtPerRotation, rotationCount: rotationIndex, issueFound: issueFound)
}
func dispatchCourts(availableCourts: Int, courts: [Int], availableMatchs: inout [Match], slots: inout [TimeMatch], rotationIndex: Int, rotationStartDate: Date, freeCourtPerRotation: inout [Int: [Int]], courtsUnavailability: [DateInterval]?) {
@ -542,16 +550,18 @@ class MatchScheduler : ModelObject, Storable {
}.sorted(by: \.1).map { $0.0 }
}
let courtsUnavailable = courtsUnavailable(at: minimumTargetedEndDate, courtsUnavailability: courtsUnavailability)
if let courtsUnavailable, courtsUnavailable == availableCourts {
minimumTargetedEndDate.addTimeInterval(3600)
if let first = availableMatchs.first {
let duration = first.matchFormat.getEstimatedDuration(additionalEstimationDuration)
let courtsUnavailable = courtsUnavailable(startDate: minimumTargetedEndDate, duration: duration, courtsUnavailability: courtsUnavailability)
if courtsUnavailable < availableCourts {
dispatchCourts(availableCourts: availableCourts, courts: freeCourts, availableMatchs: &availableMatchs, slots: &slots, rotationIndex: rotationIndex, rotationStartDate: minimumTargetedEndDate, freeCourtPerRotation: &freeCourtPerRotation, courtsUnavailability: courtsUnavailability)
}
}
dispatchCourts(availableCourts: availableCourts, courts: freeCourts, availableMatchs: &availableMatchs, slots: &slots, rotationIndex: rotationIndex, rotationStartDate: minimumTargetedEndDate, freeCourtPerRotation: &freeCourtPerRotation, courtsUnavailability: courtsUnavailability)
}
}
func updateBracketSchedule(tournament: Tournament, fromRoundId roundId: String?, fromMatchId matchId: String?, startDate: Date) {
@discardableResult func updateBracketSchedule(tournament: Tournament, fromRoundId roundId: String?, fromMatchId matchId: String?, startDate: Date) -> Bool {
let upperRounds: [Round] = tournament.rounds()
let allMatches: [Match] = tournament.allMatches()
@ -643,6 +653,8 @@ class MatchScheduler : ModelObject, Storable {
} catch {
Logger.error(error)
}
return roundDispatch.issueFound
}
@ -656,18 +668,6 @@ class MatchScheduler : ModelObject, Storable {
}.count
}
func courtsUnavailable(at startDate: Date, courtsUnavailability: [DateInterval]?) -> Int? {
guard let courtsUnavailability else { return nil }
let groupedBy = Dictionary(grouping: courtsUnavailability, by: { $0.courtIndex })
let courts = groupedBy.keys
return courts.filter { courtIndex in
let courtLockedSchedule = courtsUnavailability.filter({ $0.courtIndex == courtIndex })
return courtLockedSchedule.anySatisfy({ dateInterval in
dateInterval.range.contains(startDate)
})
}.count
}
func courtUnavailable(courtIndex: Int, from startDate: Date, to endDate: Date, source: [DateInterval]) -> Bool {
let courtLockedSchedule = source.filter({ $0.courtIndex == courtIndex })
return courtLockedSchedule.anySatisfy({ dateInterval in
@ -676,9 +676,9 @@ class MatchScheduler : ModelObject, Storable {
})
}
func updateSchedule(tournament: Tournament) {
func updateSchedule(tournament: Tournament) -> Bool {
let lastDate = updateGroupStageSchedule(tournament: tournament)
updateBracketSchedule(tournament: tournament, fromRoundId: nil, fromMatchId: nil, startDate: lastDate)
return updateBracketSchedule(tournament: tournament, fromRoundId: nil, fromMatchId: nil, startDate: lastDate)
}
}
@ -714,6 +714,7 @@ struct MatchDispatcher {
let timedMatches: [TimeMatch]
let freeCourtPerRotation: [Int: [Int]]
let rotationCount: Int
let issueFound: Bool
}
extension Match {

@ -19,7 +19,6 @@ struct ClubRowView: View {
// .foregroundStyle(club.isFavorite() ? .green : .logoRed)
// }
} label: {
Text("Club")
Text(club.name)
}
}

@ -17,6 +17,7 @@ struct PlanningSettingsView: View {
@State private var isScheduling: Bool = false
@State private var schedulingDone: Bool = false
@State private var showOptions: Bool = false
@State private var issueFound: Bool = false
init(tournament: Tournament) {
self.tournament = tournament
@ -87,6 +88,11 @@ struct PlanningSettingsView: View {
}
}
if issueFound {
Text("Padel Club n'a pas réussi à définir un horaire pour tous les matchs de ce tournoi, à cause de la programmation d'autres épreuves ou de l'indisponibilité des terrains.")
.foregroundStyle(.logoRed)
}
NavigationLink {
List {
_optionsView()
@ -151,9 +157,10 @@ struct PlanningSettingsView: View {
}
RowButtonView("Horaire intelligent", role: .destructive) {
await MainActor.run {
issueFound = false
schedulingDone = false
}
await _setupSchedule()
self.issueFound = await _setupSchedule()
await MainActor.run {
_save()
schedulingDone = true
@ -173,9 +180,15 @@ struct PlanningSettingsView: View {
}
.overlay(alignment: .bottom) {
if schedulingDone {
Label("Horaires mis à jour", systemImage: "checkmark.circle.fill")
.toastFormatted()
.deferredRendering(for: .seconds(2))
if issueFound {
Label("Horaires mis à jour", systemImage: "xmark.circle.fill")
.toastFormatted()
.deferredRendering(for: .seconds(2))
} else {
Label("Horaires mis à jour", systemImage: "checkmark.circle.fill")
.toastFormatted()
.deferredRendering(for: .seconds(2))
}
}
}
.onChange(of: tournament.startDate) {
@ -262,8 +275,8 @@ struct PlanningSettingsView: View {
}
}
private func _setupSchedule() async {
matchScheduler.updateSchedule(tournament: tournament)
private func _setupSchedule() async -> Bool {
return matchScheduler.updateSchedule(tournament: tournament)
}
private func _save() {

@ -90,7 +90,7 @@ struct PlanningView: View {
private func _timeSlotView(key: Date, matches: [Match]) -> some View {
LabeledContent {
Text(self._formattedMatchCount(self.matches.count))
Text(self._formattedMatchCount(matches.count))
} label: {
Text(key.formatted(date: .omitted, time: .shortened)).font(.title).fontWeight(.semibold)
Text(Set(matches.compactMap { $0.roundTitle() }).joined(separator: ", "))

Loading…
Cancel
Save