@@ -141,8 +141,13 @@ func isAccepted(workflows: Workflows, part: Part) -> Bool {
141
141
}
142
142
143
143
func filterRanges( workflows: Workflows ) -> Int {
144
- let attributeRanges : AttributeRanges =
145
- Dictionary ( uniqueKeysWithValues: [ . x, . m, . a, . s] . map { ( $0, 1 ... 4000 ) } )
144
+ func combinations( _ attributeRanges: [ Attribute : ClosedRange < Int > ] ) -> Int {
145
+ attributeRanges. values. reduce ( 1 , { $0 * $1. count } )
146
+ }
147
+
148
+ let attributes : [ Attribute ] = [ . x, . m, . a, . s]
149
+ let attributeRanges =
150
+ Dictionary ( uniqueKeysWithValues: attributes. map { ( $0, 1 ... 4000 ) } )
146
151
var pending = [ ( " in " , attributeRanges) ]
147
152
var acceptedCount = 0
148
153
@@ -154,8 +159,9 @@ func filterRanges(workflows: Workflows) -> Int {
154
159
155
160
// Find the range to which this rule applies.
156
161
let attribute = condition. attribute
162
+ let validRange = condition. validRange
157
163
let range = attributeRanges [ attribute] !
158
- let newRange = range. clamped ( to: condition . validRange)
164
+ let newRange = range. clamped ( to: validRange)
159
165
160
166
// Create a new set of attribute ranges with this range, and
161
167
// apply the rule's action to it.
@@ -165,34 +171,34 @@ func filterRanges(workflows: Workflows) -> Int {
165
171
case . reject:
166
172
break
167
173
case . accept:
168
- acceptedCount += combinations ( attributeRanges : newAttributeRanges)
174
+ acceptedCount += combinations ( newAttributeRanges)
169
175
case . send( let newWorkflow) :
170
176
pending. append ( ( newWorkflow, newAttributeRanges) )
171
177
}
172
178
173
179
// There will be a leftover range, possibly empty. Continue
174
180
// processing it if it is not empty.
175
- let remaining = remainingNonEmptyRanges (
176
- range : attributeRanges [ condition . attribute ] ! ,
177
- validRange : condition . validRange )
178
- // If there are zero of them, then we're done with this pending
179
- // entry
180
- if remaining . count == 0 { continue nextPending }
181
- // If there is one of them, that continues on with the sequence
182
- // of rules in this workflow.
183
- if remaining . count == 1 {
184
- attributeRanges [ condition . attribute ] = remaining [ 0 ]
181
+ //
182
+ // Because of how the problem is structured, either the leftover
183
+ // range will be of values lower than the valid range, or of
184
+ // values above the valid range, but it won't span both.
185
+ if range . lowerBound < validRange . lowerBound {
186
+ attributeRanges [ attribute ] =
187
+ range . lowerBound ... ( validRange . lowerBound - 1 )
188
+ } else if validRange . upperBound < range . upperBound {
189
+ attributeRanges [ attribute ] =
190
+ ( validRange . upperBound + 1 ) ... range . upperBound
185
191
} else {
186
- // 2 of them. Haven't handled this case yet
187
- fatalError ( " found 2 remaining entries \( remaining) " )
192
+ continue nextPending
188
193
}
189
194
} else {
190
- // Unconditional rule, always a match, so consumes the whole ranges
195
+ // Unconditional rule, always a match, so consumes the whole.
196
+ // ranges
191
197
switch rule. action {
192
198
case . reject:
193
199
break
194
200
case . accept:
195
- acceptedCount += combinations ( attributeRanges: attributeRanges )
201
+ acceptedCount += combinations ( attributeRanges)
196
202
case . send( let newWorkflow) :
197
203
pending. append ( ( newWorkflow, attributeRanges) )
198
204
}
@@ -204,26 +210,6 @@ func filterRanges(workflows: Workflows) -> Int {
204
210
return acceptedCount
205
211
}
206
212
207
- typealias AttributeRanges = [ Attribute : ClosedRange < Int > ]
208
-
209
- func combinations( attributeRanges: AttributeRanges ) -> Int {
210
- attributeRanges. values. reduce ( 1 , { $0 * $1. count } )
211
- }
212
-
213
- func remainingNonEmptyRanges( range: ClosedRange < Int > , validRange: ClosedRange < Int >
214
- ) -> [ ClosedRange < Int > ] {
215
- var result = [ ClosedRange < Int > ] ( )
216
- // Before valid range
217
- if range. lowerBound < validRange. lowerBound {
218
- result. append ( range. lowerBound... ( validRange. lowerBound - 1 ) )
219
- }
220
- // After valid range
221
- if validRange. upperBound < range. upperBound {
222
- result. append ( ( validRange. upperBound + 1 ) ... range. upperBound)
223
- }
224
- return result
225
- }
226
-
227
213
let ( workflows, parts) = readInput ( )
228
214
let p1 = process ( workflows: workflows, parts: parts)
229
215
let p2 = filterRanges ( workflows: workflows)
0 commit comments