@ -41,7 +41,7 @@ class Round: ModelObject, Storable {
}
func _matches ( ) -> [ Match ] {
return self . tournamentStore . matches . filter { $0 . round = = self . id }
return self . tournamentStore . matches . filter { $0 . round = = self . id } . sorted ( by : \ . index )
// r e t u r n S t o r e . m a i n . f i l t e r { $ 0 . r o u n d = = s e l f . i d }
}
@ -66,7 +66,11 @@ class Round: ModelObject, Storable {
}
func hasEnded ( ) -> Bool {
if parent = = nil {
return playedMatches ( ) . anySatisfy ( { $0 . hasEnded ( ) = = false } ) = = false
} else {
return enabledMatches ( ) . anySatisfy ( { $0 . hasEnded ( ) = = false } ) = = false
}
}
func upperMatches ( ofMatch match : Match ) -> [ Match ] {
@ -81,8 +85,8 @@ class Round: ModelObject, Storable {
func previousMatches ( ofMatch match : Match ) -> [ Match ] {
guard let previousRound = previousRound ( ) else { return [ ] }
return self . tournamentStore . filter {
( $0 . index = = match . topPreviousRoundMatchIndex ( ) || $0 . index = = match . bottomPreviousRoundMatchIndex ( ) ) && $0 . round = = previousRound . id
return self . tournamentStore . matches . filter {
$0 . round = = previousRound . id && ( $0 . index = = match . topPreviousRoundMatchIndex ( ) || $0 . index = = match . bottomPreviousRoundMatchIndex ( ) )
}
// r e t u r n S t o r e . m a i n . f i l t e r {
@ -103,13 +107,8 @@ class Round: ModelObject, Storable {
}
}
func team ( _ team : TeamPosition , inMatch match : Match ) -> TeamRegistration ? {
switch team {
case . one :
return roundProjectedTeam ( . one , inMatch : match )
case . two :
return roundProjectedTeam ( . two , inMatch : match )
}
func team ( _ team : TeamPosition , inMatch match : Match , previousRound : Round ? ) -> TeamRegistration ? {
return roundProjectedTeam ( team , inMatch : match , previousRound : previousRound )
}
func seed ( _ team : TeamPosition , inMatchIndex matchIndex : Int ) -> TeamRegistration ? {
@ -119,17 +118,11 @@ class Round: ModelObject, Storable {
&& ( $0 . bracketPosition ! / 2 ) = = matchIndex
&& ( $0 . bracketPosition ! % 2 ) = = team . rawValue
} )
// r e t u r n S t o r e . m a i n . f i l t e r ( i s I n c l u d e d : {
// $ 0 . t o u r n a m e n t = = t o u r n a m e n t
// & & $ 0 . b r a c k e t P o s i t i o n ! = n i l
// & & ( $ 0 . b r a c k e t P o s i t i o n ! / 2 ) = = m a t c h I n d e x
// & & ( $ 0 . b r a c k e t P o s i t i o n ! % 2 ) = = t e a m . r a w V a l u e
// } ) . f i r s t
}
func seeds ( inMatchIndex matchIndex : Int ) -> [ TeamRegistration ] {
return self . tournamentStore . teamRegistrations . filter {
$0 . tournament = = tournament
&& $0 . bracketPosition != nil
&& ( $0 . bracketPosition ! / 2 ) = = matchIndex
@ -162,7 +155,14 @@ class Round: ModelObject, Storable {
return playedMatches ( ) . flatMap ( { $0 . teams ( ) } )
}
func roundProjectedTeam ( _ team : TeamPosition , inMatch match : Match ) -> TeamRegistration ? {
func roundProjectedTeam ( _ team : TeamPosition , inMatch match : Match , previousRound : Round ? ) -> TeamRegistration ? {
#if DEBUG_TIME // D E B U G I N G T I M E
let start = Date ( )
defer {
let duration = Duration . milliseconds ( Date ( ) . timeIntervalSince ( start ) * 1_000 )
print ( " func roundProjectedTeam " , team . rawValue , duration . formatted ( . units ( allowed : [ . seconds , . milliseconds ] ) ) )
}
#endif
if isLoserBracket ( ) = = false , let seed = seed ( team , inMatchIndex : match . index ) {
return seed
}
@ -171,86 +171,116 @@ class Round: ModelObject, Storable {
case . one :
if let luckyLoser = match . teamScores . first ( where : { $0 . luckyLoser = = match . index * 2 } ) {
return luckyLoser . team
} else if let parent = upperBracketTopMatch ( ofMatchIndex : match . index ) ? . losingTeamId {
return self . tournamentStore . teamRegistrations . findById ( parent )
} else if let previousMatch = topPreviousRoundMatch ( ofMatch : match ) {
} else if let previousMatch = topPreviousRoundMatch ( ofMatch : match , previousRound : previousRound ) {
if let teamId = previousMatch . winningTeamId {
return self . tournamentStore . teamRegistrations . findById ( teamId )
} else if previousMatch . disabled {
return previousMatch . teams ( ) . first
}
} else if let parent = upperBracketTopMatch ( ofMatchIndex : match . index , previousRound : previousRound ) ? . losingTeamId {
return Store . main . findById ( parent )
}
case . two :
if let luckyLoser = match . teamScores . first ( where : { $0 . luckyLoser = = match . index * 2 + 1 } ) {
return luckyLoser . team
} else if let parent = upperBracketBottomMatch ( ofMatchIndex : match . index ) ? . losingTeamId {
return self . tournamentStore . teamRegistrations . findById ( parent )
} else if let previousMatch = bottomPreviousRoundMatch ( ofMatch : match ) {
} else if let previousMatch = bottomPreviousRoundMatch ( ofMatch : match , previousRound : previousRound ) {
if let teamId = previousMatch . winningTeamId {
return self . tournamentStore . teamRegistrations . findById ( teamId )
} else if previousMatch . disabled {
return previousMatch . teams ( ) . first
}
} else if let parent = upperBracketBottomMatch ( ofMatchIndex : match . index , previousRound : previousRound ) ? . losingTeamId {
return Store . main . findById ( parent )
}
}
return nil
}
func upperBracketTopMatch ( ofMatchIndex matchIndex : Int ) -> Match ? {
func upperBracketTopMatch ( ofMatchIndex matchIndex : Int , previousRound : Round ? ) -> Match ? {
#if DEBUG_TIME // D E B U G I N G T I M E
let start = Date ( )
defer {
let duration = Duration . milliseconds ( Date ( ) . timeIntervalSince ( start ) * 1_000 )
print ( " func upperBracketTopMatch " , matchIndex , duration . formatted ( . units ( allowed : [ . seconds , . milliseconds ] ) ) )
}
#endif
let indexInRound = RoundRule . matchIndexWithinRound ( fromMatchIndex : matchIndex )
if isLoserBracket ( ) , previousRound ( ) = = nil , let parentRound = parentRound , let upperBracketTopMatch = parentRound . getMatch ( atMatchIndexInRound : indexInRound * 2 ) {
if isLoserBracket ( ) , previousRound = = nil , let parentRound = parentRound , let upperBracketTopMatch = parentRound . getMatch ( atMatchIndexInRound : indexInRound * 2 ) {
return upperBracketTopMatch
}
return nil
}
func upperBracketBottomMatch ( ofMatchIndex matchIndex : Int ) -> Match ? {
func upperBracketBottomMatch ( ofMatchIndex matchIndex : Int , previousRound : Round ? ) -> Match ? {
#if DEBUG_TIME // D E B U G I N G T I M E
let start = Date ( )
defer {
let duration = Duration . milliseconds ( Date ( ) . timeIntervalSince ( start ) * 1_000 )
print ( " func upperBracketBottomMatch " , matchIndex , duration . formatted ( . units ( allowed : [ . seconds , . milliseconds ] ) ) )
}
#endif
let indexInRound = RoundRule . matchIndexWithinRound ( fromMatchIndex : matchIndex )
if isLoserBracket ( ) , previousRound ( ) = = nil , let parentRound = parentRound , let upperBracketBottomMatch = parentRound . getMatch ( atMatchIndexInRound : indexInRound * 2 + 1 ) {
if isLoserBracket ( ) , previousRound = = nil , let parentRound = parentRound , let upperBracketBottomMatch = parentRound . getMatch ( atMatchIndexInRound : indexInRound * 2 + 1 ) {
return upperBracketBottomMatch
}
return nil
}
func topPreviousRoundMatch ( ofMatch match : Match ) -> Match ? {
guard let previousRound = previousRound ( ) else { return nil }
let matches : [ Match ] = self . tournamentStore . matches . filter {
$0 . index = = match . topPreviousRoundMatchIndex ( ) && $0 . round = = previousRound . id
func topPreviousRoundMatch ( ofMatch match : Match , previousRound : Round ? ) -> Match ? {
#if DEBUG_TIME // D E B U G I N G T I M E
let start = Date ( )
defer {
let duration = Duration . milliseconds ( Date ( ) . timeIntervalSince ( start ) * 1_000 )
print ( " func topPreviousRoundMatch " , match . id , duration . formatted ( . units ( allowed : [ . seconds , . milliseconds ] ) ) )
}
// l e t m a t c h e s : [ M a t c h ] = S t o r e . m a i n . f i l t e r {
// $ 0 . i n d e x = = m a t c h . t o p P r e v i o u s R o u n d M a t c h I n d e x ( ) & & $ 0 . r o u n d = = p r e v i o u s R o u n d . i d
// }
return matches . sorted ( by : \ . index ) . first
#endif
guard let previousRound else { return nil }
let topPreviousRoundMatchIndex = match . topPreviousRoundMatchIndex ( )
return self . tournamentStore . matches . first ( where : {
$0 . round = = previousRound . id && $0 . index = = topPreviousRoundMatchIndex
} )
}
func bottomPreviousRoundMatch ( ofMatch match : Match ) -> Match ? {
guard let previousRound = previousRound ( ) else { return nil }
let matches : [ Match ] = self . tournamentStore . matches . filter {
$0 . index = = match . bottomPreviousRoundMatchIndex ( ) && $0 . round = = previousRound . id
func bottomPreviousRoundMatch ( ofMatch match : Match , previousRound : Round ? ) -> Match ? {
#if DEBUG_TIME // D E B U G I N G T I M E
let start = Date ( )
defer {
let duration = Duration . milliseconds ( Date ( ) . timeIntervalSince ( start ) * 1_000 )
print ( " func bottomPreviousRoundMatch " , match . id , duration . formatted ( . units ( allowed : [ . seconds , . milliseconds ] ) ) )
}
return matches . sorted ( by : \ . index ) . first
#endif
guard let previousRound else { return nil }
let bottomPreviousRoundMatchIndex = match . bottomPreviousRoundMatchIndex ( )
return self . tournamentStore . matches . first ( where : {
$0 . round = = previousRound . id && $0 . index = = bottomPreviousRoundMatchIndex
} )
}
func getMatch ( atMatchIndexInRound matchIndexInRound : Int ) -> Match ? {
return self . tournamentStore . matches . first ( where : {
self . tournamentStore . matches . first ( where : {
let index = RoundRule . matchIndexWithinRound ( fromMatchIndex : $0 . index )
return $0 . round = = id && index = = matchIndexInRound
} )
// S t o r e . m a i n . f i l t e r ( i s I n c l u d e d : {
// l e t i n d e x = R o u n d R u l e . m a t c h I n d e x W i t h i n R o u n d ( f r o m M a t c h I n d e x : $ 0 . i n d e x )
// r e t u r n $ 0 . r o u n d = = i d & & i n d e x = = m a t c h I n d e x I n R o u n d
// } ) . f i r s t
}
func enabledMatches ( ) -> [ Match ] {
return self . tournamentStore . matches . filter { $0 . round = = self . id && $0 . disabled = = false }
// r e t u r n S t o r e . m a i n . f i l t e r { $ 0 . r o u n d = = s e l f . i d & & $ 0 . d i s a b l e d = = f a l s e }
return self . tournamentStore . matches . filter { $0 . round = = self . id && $0 . disabled = = false } . sorted ( by : \ . index )
}
func displayableMatches ( ) -> [ Match ] {
#if DEBUG_TIME // D E B U G I N G T I M E
let start = Date ( )
defer {
let duration = Duration . milliseconds ( Date ( ) . timeIntervalSince ( start ) * 1_000 )
print ( " func displayableMatches of round: " , id , duration . formatted ( . units ( allowed : [ . seconds , . milliseconds ] ) ) )
}
#endif
if index = = 0 && isUpperBracket ( ) {
var matches : [ Match ? ] = [ playedMatches ( ) . first ]
matches . append ( loserRounds ( ) . first ? . playedMatches ( ) . first )
@ -269,18 +299,28 @@ class Round: ModelObject, Storable {
}
func previousRound ( ) -> Round ? {
return self . tournamentStore . rounds . first ( where : { $0 . tournament = = tournament && $0 . parent = = parent && $0 . index = = index + 1 } )
// r e t u r n S t o r e . m a i n . f i l t e r ( i s I n c l u d e d : { $ 0 . t o u r n a m e n t = = t o u r n a m e n t & & $ 0 . p a r e n t = = p a r e n t & & $ 0 . i n d e x = = i n d e x + 1 } ) . f i r s t
#if DEBUG_TIME // D E B U G I N G T I M E
let start = Date ( )
defer {
let duration = Duration . milliseconds ( Date ( ) . timeIntervalSince ( start ) * 1_000 )
print ( " func previousRound of: " , id , duration . formatted ( . units ( allowed : [ . seconds , . milliseconds ] ) ) )
}
#endif
return self . tournamentStore . rounds . first ( where : { $0 . parent = = parent && $0 . index = = index + 1 } )
}
func nextRound ( ) -> Round ? {
return self . tournamentStore . rounds . first ( where : { $0 . tournament = = tournament && $0 . parent = = parent && $0 . index = = index - 1 } )
return self . tournamentStore . rounds . first ( where : { $0 . parent = = parent && $0 . index = = index - 1 } )
}
func loserRounds ( forRoundIndex roundIndex : Int ) -> [ Round ] {
return loserRoundsAndChildren ( ) . filter ( { $0 . index = = roundIndex } ) . sorted ( by : \ . theoryCumulativeMatchCount )
}
func loserRounds ( forRoundIndex roundIndex : Int , loserRoundsAndChildren : [ Round ] ) -> [ Round ] {
return loserRoundsAndChildren . filter ( { $0 . index = = roundIndex } ) . sorted ( by : \ . theoryCumulativeMatchCount )
}
func isDisabled ( ) -> Bool {
return _matches ( ) . allSatisfy ( { $0 . disabled } )
}
@ -387,11 +427,16 @@ class Round: ModelObject, Storable {
func correspondingLoserRoundTitle ( _ displayStyle : DisplayStyle = . wide ) -> String {
#if DEBUG_TIME // D E B U G I N G T I M E
let start = Date ( )
defer {
let duration = Duration . milliseconds ( Date ( ) . timeIntervalSince ( start ) * 1_000 )
print ( " func correspondingLoserRoundTitle() " , duration . formatted ( . units ( allowed : [ . seconds , . milliseconds ] ) ) )
}
#endif
let initialMatchIndexFromRoundIndex = RoundRule . matchIndex ( fromRoundIndex : index )
let seedsAfterThisRound : [ TeamRegistration ] = self . tournamentStore . teamRegistrations . filter {
$0 . tournament = = tournament
&& $0 . bracketPosition != nil
$0 . bracketPosition != nil
&& ( $0 . bracketPosition ! / 2 ) < initialMatchIndexFromRoundIndex
}
@ -406,26 +451,40 @@ class Round: ModelObject, Storable {
}
func hasNextRound ( ) -> Bool {
return nextRound ( ) ? . isDisabled ( ) = = false
return nextRound ( ) ? . isRankDisabled ( ) = = false
}
func seedInterval ( expanded : Bool = false ) -> SeedInterval ? {
#if DEBUG_TIME // D E B U G I N G T I M E
let start = Date ( )
defer {
let duration = Duration . milliseconds ( Date ( ) . timeIntervalSince ( start ) * 1_000 )
print ( " func seedInterval(expanded: Bool = false) " , duration . formatted ( . units ( allowed : [ . seconds , . milliseconds ] ) ) )
}
#endif
func seedInterval ( ) -> SeedInterval ? {
if parent = = nil {
let numberOfMatches = RoundRule . numberOfMatches ( forRoundIndex : index + 1 )
if index = = 0 { return SeedInterval ( first : 1 , last : 2 ) }
let initialMatchIndexFromRoundIndex = RoundRule . matchIndex ( fromRoundIndex : index )
let seedsAfterThisRound : [ TeamRegistration ] = self . tournamentStore . teamRegistrations . filter {
$0 . tournament = = tournament
&& $0 . bracketPosition != nil
$0 . bracketPosition != nil
&& ( $0 . bracketPosition ! / 2 ) < initialMatchIndexFromRoundIndex
}
let playedMatches = playedMatches ( )
let reduce = numberOfMatches / 2 - ( playedMatches . count + seedsAfterThisRound . count )
return SeedInterval ( first : 1 , last : numberOfMatches , reduce : reduce )
let seedInterval = SeedInterval ( first : playedMatches . count + seedsAfterThisRound . count + 1 , last : playedMatches . count * 2 + seedsAfterThisRound . count )
return seedInterval
}
if let previousRound = previousRound ( ) {
if previousRound . enabledMatches ( ) . isEmpty = = false && expanded = = false {
return previousRound . seedInterval ( ) ? . chunks ( ) ? . first
} else {
return previousRound . previousRound ( ) ? . seedInterval ( )
}
} else if let parentRound {
if parentRound . parent = = nil && expanded = = false {
return parentRound . seedInterval ( )
}
return parentRound . seedInterval ( ) ? . chunks ( ) ? . last
}
@ -462,8 +521,16 @@ class Round: ModelObject, Storable {
}
func loserRounds ( ) -> [ Round ] {
let rounds : [ Round ] = self . tournamentStore . rounds . filter { $0 . parent = = id }
return rounds . sorted ( by : \ . index ) . reversed ( )
#if DEBUG_TIME // D E B U G I N G T I M E
let start = Date ( )
defer {
let duration = Duration . milliseconds ( Date ( ) . timeIntervalSince ( start ) * 1_000 )
print ( " func loserRounds: " , id , duration . formatted ( . units ( allowed : [ . seconds , . milliseconds ] ) ) )
}
#endif
return self . tournamentStore . rounds . filter ( { $0 . parent = = id } ) . sorted ( by : \ . index ) . reversed ( )
}
func loserRoundsAndChildren ( ) -> [ Round ] {
@ -604,7 +671,7 @@ extension Round: Selectable, Equatable {
}
func selectionLabel ( ) -> String {
func selectionLabel ( index : Int ) -> String {
if let parentRound {
return " Tour # \( parentRound . loserRounds ( ) . count - index ) "
} else {
@ -613,6 +680,15 @@ extension Round: Selectable, Equatable {
}
func badgeValue ( ) -> Int ? {
#if DEBUG_TIME // D E B U G I N G T I M E
let start = Date ( )
defer {
let duration = Duration . milliseconds ( Date ( ) . timeIntervalSince ( start ) * 1_000 )
print ( " func badgeValue round of: " , id , duration . formatted ( . units ( allowed : [ . seconds , . milliseconds ] ) ) )
}
#endif
if let parentRound {
return parentRound . loserRounds ( forRoundIndex : index ) . flatMap { $0 . playedMatches ( ) } . filter ( { $0 . isRunning ( ) } ) . count
} else {
@ -625,6 +701,13 @@ extension Round: Selectable, Equatable {
}
func badgeImage ( ) -> Badge ? {
hasEnded ( ) ? . checkmark : nil
#if DEBUG_TIME // D E B U G I N G T I M E
let start = Date ( )
defer {
let duration = Duration . milliseconds ( Date ( ) . timeIntervalSince ( start ) * 1_000 )
print ( " func badgeImage of round: " , id , duration . formatted ( . units ( allowed : [ . seconds , . milliseconds ] ) ) )
}
#endif
return hasEnded ( ) ? . checkmark : nil
}
}