multistore
Razmig Sarkissian 2 years ago
parent 58afa51005
commit 3732d636f7
  1. 194
      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,100 +215,139 @@ 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]!
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)
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)
}
if difference > 0 {
courts.removeAll(where: { index in freeCourtPreviousRotation.contains(index)
})
freeCourtPerRotation[rotationIndex] = courts
courts = freeCourtPreviousRotation
rotationStartDate = rotationStartDate.addingTimeInterval(-difference)
}
}
}
courts.forEach { courtIndex in
//print(mt.map { ($0.bracket!.index.intValue, counts[$0.bracket!.index.intValue]) })
// 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
}
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
}
}
// var organizedSlots = [TimeMatch]()
// for i in 0..<rotationIndex {
// let courtsSorted = slots.filter({ $0.rotationIndex == i && $0.courtLocked == false }).map { $0.courtIndex }.sorted()
// let courts = randomizeCourts ? courtsSorted.shuffled() : courtsSorted
// var matches = slots.filter({ $0.rotationIndex == i }).sorted(using: .keyPath(\.groupIndex), .keyPath(\.courtIndex))
//
// for j in 0..<matches.count {
// matches[j].courtIndex = courts[j]
// organizedSlots.append(matches[j])
// }
// }
//
//
return MatchDispatcher(timedMatches: slots, freeCourtPerRotation: freeCourtPerRotation, rotationCount: rotationIndex, groupLastRotation: groupLastRotation)
}
if (matchPerRound[roundObject.index] ?? 0)%2 == 0 && roundObject.index != 0 && roundObject.loser == nil && courtIndex == numberOfCourtsAvailablePerRotation - 1 {
func dispatchCourts(availableCourts: Int, courts: [Int], availableMatchs: inout [Match], slots: inout [TimeMatch], rotationIndex: Int, rotationStartDate: Date, freeCourtPerRotation: inout [Int: [Int]]) {
var matchPerRound = [Int: Int]()
var minimumTargetedEndDate: Date = rotationStartDate
courts.forEach { courtIndex in
//print(mt.map { ($0.bracket!.index.intValue, counts[$0.bracket!.index.intValue]) })
if let first = availableMatchs.first(where: { match in
let roundObject = match.roundObject!
let canBePlayed = roundMatchCanBePlayed(match, roundObject: roundObject, slots: slots, rotationIndex: rotationIndex, targetedStartDate: rotationStartDate, minimumTargetedEndDate: &minimumTargetedEndDate)
if roundObject.loser == nil && roundObject.index > 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
}
}
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
}
}
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
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
}
timeToAdd = 0.0
} else {
freeCourtPerRotation[rotationIndex]!.append(courtIndex)
}
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)
}
rotationIndex += 1
}
var organizedSlots = [TimeMatch]()
for i in 0..<rotationIndex {
let courtsSorted = slots.filter({ $0.rotationIndex == i && $0.courtLocked == false }).map { $0.courtIndex }.sorted()
let courts = randomizeCourts ? courtsSorted.shuffled() : courtsSorted
var matches = slots.filter({ $0.rotationIndex == i }).sorted(using: .keyPath(\.groupIndex), .keyPath(\.courtIndex))
if freeCourtPerRotation[rotationIndex]!.count == availableCourts {
freeCourtPerRotation[rotationIndex] = []
let freeCourts = (0..<availableCourts).map { $0 }
for j in 0..<matches.count {
matches[j].courtIndex = courts[j]
organizedSlots.append(matches[j])
}
}
return MatchDispatcher(timedMatches: organizedSlots, freeCourtPerRotation: freeCourtPerRotation, rotationCount: rotationIndex, groupLastRotation: groupLastRotation)
dispatchCourts(availableCourts: availableCourts, courts: freeCourts, availableMatchs: &availableMatchs, slots: &slots, rotationIndex: rotationIndex, rotationStartDate: minimumTargetedEndDate, freeCourtPerRotation: &freeCourtPerRotation)
}
}
func updateSchedule(tournament: Tournament, fromRoundId roundId: String?, fromMatchId matchId: String?, randomizeCourts: Bool, startDate: Date) {
let upperRounds = tournament.rounds()
var roundIndex = 0
if let roundId {
roundIndex = upperRounds.firstIndex(where: { $0.id == roundId }) ?? 0
let rounds = upperRounds.map {
$0
} + upperRounds.flatMap {
$0.loserRoundsAndChildren()
}
let rounds = upperRounds.flatMap {
[$0] + $0.loserRoundsAndChildren()
if let roundId {
roundIndex = rounds.firstIndex(where: { $0.id == roundId }) ?? 0
}
var flattenedMatches = rounds[roundIndex...].flatMap { round in

Loading…
Cancel
Save