From 3732d636f750508f77f0f7154398bf0a00899b34 Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Sat, 13 Apr 2024 09:02:53 +0200 Subject: [PATCH] wip --- PadelClub/ViewModel/MatchScheduler.swift | 204 ++++++++++++++--------- 1 file changed, 123 insertions(+), 81 deletions(-) diff --git a/PadelClub/ViewModel/MatchScheduler.swift b/PadelClub/ViewModel/MatchScheduler.swift index 7919d25..61a763c 100644 --- a/PadelClub/ViewModel/MatchScheduler.swift +++ b/PadelClub/ViewModel/MatchScheduler.swift @@ -23,7 +23,7 @@ struct TimeMatch { var durationLeft: Int //in minutes var minimumBreakTime: Int //in minutes var courtLocked: Bool = false - + var freeCourt: Bool = false func estimatedEndDate(includeBreakTime: Bool) -> Date { let minutesToAdd = Double(durationLeft + (includeBreakTime ? minimumBreakTime : 0)) return startDate.addingTimeInterval(minutesToAdd * 60.0) @@ -136,8 +136,8 @@ class MatchScheduler { return GroupStageMatchDispatcher(timedMatches: organizedSlots, freeCourtPerRotation: freeCourtPerRotation, rotationCount: rotationIndex, groupLastRotation: groupLastRotation) } - func roundMatchCanBePlayed(_ match: Match, roundObject: Round, slots: [TimeMatch], rotationIndex: Int, targetedStartDate: Date) -> Bool { - print(roundObject.roundTitle(), match.matchTitle()) + func roundMatchCanBePlayed(_ match: Match, roundObject: Round, slots: [TimeMatch], rotationIndex: Int, targetedStartDate: Date, minimumTargetedEndDate: inout Date) -> Bool { + //print(roundObject.roundTitle(), match.matchTitle()) let previousMatches = roundObject.precedentMatches(ofMatch: match) if previousMatches.isEmpty { return true } @@ -159,18 +159,21 @@ class MatchScheduler { return false } -// if roundObject.isLoserBracket() { -// let previousMatchIsInPreviousRotation = previousMatchSlots.allSatisfy({ $0.rotationIndex < rotationIndex }) -// return previousMatchIsInPreviousRotation -// } - let previousMatchIsInPreviousRotation = previousMatchSlots.allSatisfy({ $0.rotationIndex < rotationIndex }) - - guard let minimumPossibleEndDate = previousMatchSlots.map({ $0.estimatedEndDate(includeBreakTime: true) }).max() else { + guard let minimumPossibleEndDate = previousMatchSlots.map({ $0.estimatedEndDate(includeBreakTime: roundObject.isLoserBracket() == false) }).max() else { return previousMatchIsInPreviousRotation } - return targetedStartDate >= minimumPossibleEndDate + if targetedStartDate >= minimumPossibleEndDate { + return true + } else { + if targetedStartDate == minimumTargetedEndDate { + minimumTargetedEndDate = minimumPossibleEndDate + } else { + minimumTargetedEndDate = min(minimumPossibleEndDate, minimumTargetedEndDate) + } + return false + } } func getAvailableCourt(inSlots slots: [TimeMatch], nextStartDate: Date) -> [TimeMatch] { @@ -212,102 +215,141 @@ class MatchScheduler { let previousRotationSlots = slots.filter({ $0.rotationIndex == rotationIndex - 1 }) var rotationStartDate: Date = getNextStartDate(fromPreviousRotationSlots: previousRotationSlots, includeBreakTime: false) ?? dispatcherStartDate - let duplicatedSlots = getAvailableCourt(inSlots: previousRotationSlots, nextStartDate: rotationStartDate) - print("duplicatedSlots", duplicatedSlots) - slots.append(contentsOf: duplicatedSlots) - courts.removeAll(where: { index in - duplicatedSlots.anySatisfy { $0.courtIndex == index } - }) +// let duplicatedSlots = getAvailableCourt(inSlots: previousRotationSlots, nextStartDate: rotationStartDate) +// print("duplicatedSlots", duplicatedSlots) +// slots.append(contentsOf: duplicatedSlots) +// courts.removeAll(where: { index in +// duplicatedSlots.anySatisfy { $0.courtIndex == index } +// }) courts.sort() print("courts available at rotation \(rotationIndex)", courts) print("rotationStartDate", rotationStartDate) - let freeCourtPreviousRotation = rotationIndex > 0 ? freeCourtPerRotation[rotationIndex - 1]!.count : 0 - - if previousRotationSlots.isEmpty && rotationIndex > 0 { - let previousPreviousRotationSlots = slots.filter({ $0.rotationIndex == rotationIndex - 2 }) - rotationStartDate = getNextStartDate(fromPreviousRotationSlots: previousPreviousRotationSlots, includeBreakTime: false) ?? dispatcherStartDate - } else if freeCourtPreviousRotation > 0 { + if rotationIndex > 0, let freeCourtPreviousRotation = freeCourtPerRotation[rotationIndex - 1], freeCourtPreviousRotation.count > 0 { print("scenario where we are waiting for a breaktime to be over without any match to play in between or a free court was available and we need to recheck breaktime left on it") - let previousPreviousRotationSlots = slots.filter({ $0.rotationIndex == rotationIndex - 2 }) - if let previousEndDate = getNextStartDate(fromPreviousRotationSlots: previousPreviousRotationSlots, includeBreakTime: true) { - rotationStartDate = previousEndDate - courts = freeCourtPerRotation[rotationIndex - 1]! - } - } - - courts.forEach { courtIndex in - //print(mt.map { ($0.bracket!.index.intValue, counts[$0.bracket!.index.intValue]) }) + let previousPreviousRotationSlots = slots.filter({ $0.rotationIndex == rotationIndex - 2 && freeCourtPreviousRotation.contains($0.courtIndex) }) + let previousEndDate = getNextStartDate(fromPreviousRotationSlots: previousPreviousRotationSlots, includeBreakTime: true) + let previousEndDateNoBreak = getNextStartDate(fromPreviousRotationSlots: previousPreviousRotationSlots, includeBreakTime: false) - if let first = availableMatchs.first(where: { match in - let roundObject = match.roundObject! - let canBePlayed = roundMatchCanBePlayed(match, roundObject: roundObject, slots: slots, rotationIndex: rotationIndex, targetedStartDate: rotationStartDate) - if roundObject.loser == nil && roundObject.index > 0, match.indexInRound() == 0, numberOfCourtsAvailablePerRotation > 1, let nextMatch = match.next() { - if canBePlayed && roundMatchCanBePlayed(nextMatch, roundObject: roundObject, slots: slots, rotationIndex: rotationIndex, targetedStartDate: rotationStartDate) { - return true - } else { - return false - } - } - - if (matchPerRound[roundObject.index] ?? 0)%2 == 0 && roundObject.index != 0 && roundObject.loser == nil && courtIndex == numberOfCourtsAvailablePerRotation - 1 { - return false + let noBreakAlreadyTested = previousRotationSlots.anySatisfy({ $0.startDate == previousEndDateNoBreak }) + if let previousEndDate, let previousEndDateNoBreak { + let differenceWithBreak = rotationStartDate.timeIntervalSince(previousEndDate) + let differenceWithoutBreak = rotationStartDate.timeIntervalSince(previousEndDateNoBreak) + print("difference w break", differenceWithBreak) + print("difference w/o break", differenceWithoutBreak) + var difference = differenceWithBreak + if differenceWithBreak <= 0 { + difference = differenceWithoutBreak + } else if differenceWithBreak > 0 && differenceWithoutBreak > 0 { + difference = noBreakAlreadyTested ? differenceWithBreak : max(differenceWithBreak, differenceWithoutBreak) } - - return canBePlayed - }) { - //print(first.roundObject!.roundTitle(), first.matchTitle()) - if first.roundObject!.loser == nil { - if let roundIndex = matchPerRound[first.roundObject!.index] { - matchPerRound[first.roundObject!.index] = roundIndex + 1 - } else { - matchPerRound[first.roundObject!.index] = 1 - } + if difference > 0 { + courts.removeAll(where: { index in freeCourtPreviousRotation.contains(index) + }) + freeCourtPerRotation[rotationIndex] = courts + courts = freeCourtPreviousRotation + rotationStartDate = rotationStartDate.addingTimeInterval(-difference) } - let timeMatch = TimeMatch(matchID: first.id, rotationIndex: rotationIndex, courtIndex: courtIndex, groupIndex: first.roundObject!.index, startDate: rotationStartDate, durationLeft: first.matchFormat.estimatedDuration, minimumBreakTime: first.matchFormat.breakTime.breakTime) - slots.append(timeMatch) - availableMatchs.removeAll(where: { $0.id == first.id }) - if let index = first.roundObject?.index { - groupLastRotation[index] = rotationIndex - } - timeToAdd = 0.0 - } else { - freeCourtPerRotation[rotationIndex]!.append(courtIndex) } } - + +// if previousRotationSlots.isEmpty && rotationIndex > 0 { +// let previousPreviousRotationSlots = slots.filter({ $0.rotationIndex == rotationIndex - 2 }) +// rotationStartDate = getNextStartDate(fromPreviousRotationSlots: previousPreviousRotationSlots, includeBreakTime: false) ?? dispatcherStartDate +// } else if freeCourtPreviousRotation > 0 { +// print("scenario where we are waiting for a breaktime to be over without any match to play in between or a free court was available and we need to recheck breaktime left on it") +// let previousPreviousRotationSlots = slots.filter({ $0.rotationIndex == rotationIndex - 2 }) +// if let previousEndDate = getNextStartDate(fromPreviousRotationSlots: previousPreviousRotationSlots, includeBreakTime: true) { +// rotationStartDate = previousEndDate +// courts = freeCourtPerRotation[rotationIndex - 1]! +// } +// } + dispatchCourts(availableCourts: numberOfCourtsAvailablePerRotation, courts: courts, availableMatchs: &availableMatchs, slots: &slots, rotationIndex: rotationIndex, rotationStartDate: rotationStartDate, freeCourtPerRotation: &freeCourtPerRotation) rotationIndex += 1 } - var organizedSlots = [TimeMatch]() - for i in 0.. 0, match.indexInRound() == 0, courts.count > 1, let nextMatch = match.next() { + if canBePlayed && roundMatchCanBePlayed(nextMatch, roundObject: roundObject, slots: slots, rotationIndex: rotationIndex, targetedStartDate: rotationStartDate, minimumTargetedEndDate: &minimumTargetedEndDate) { + return true + } else { + return false + } + } + + if (matchPerRound[roundObject.index] ?? 0)%2 == 0 && roundObject.index != 0 && roundObject.loser == nil && courtIndex == courts.count - 1 { + return false + } + + return canBePlayed + }) { + print(first.roundObject!.roundTitle(), first.matchTitle(), courtIndex, rotationStartDate) + + if first.roundObject!.loser == nil { + if let roundIndex = matchPerRound[first.roundObject!.index] { + matchPerRound[first.roundObject!.index] = roundIndex + 1 + } else { + matchPerRound[first.roundObject!.index] = 1 + } + } + let timeMatch = TimeMatch(matchID: first.id, rotationIndex: rotationIndex, courtIndex: courtIndex, groupIndex: first.roundObject!.index, startDate: rotationStartDate, durationLeft: first.matchFormat.estimatedDuration, minimumBreakTime: first.matchFormat.breakTime.breakTime) + slots.append(timeMatch) + availableMatchs.removeAll(where: { $0.id == first.id }) + } else { + freeCourtPerRotation[rotationIndex]!.append(courtIndex) } } - - return MatchDispatcher(timedMatches: organizedSlots, freeCourtPerRotation: freeCourtPerRotation, rotationCount: rotationIndex, groupLastRotation: groupLastRotation) + if freeCourtPerRotation[rotationIndex]!.count == availableCourts { + freeCourtPerRotation[rotationIndex] = [] + let freeCourts = (0..