@@ -116,23 +116,23 @@ func readParts() -> [Part] {
116
116
}
117
117
118
118
func process( workflows: Workflows , parts: [ Part ] ) -> Int {
119
- parts. filter ( { doesAccept ( part: $0, workflows: workflows) } ) . map { p in
120
- p. x + p. m + p. a + p. s
121
- } . reduce ( 0 , + )
119
+ parts
120
+ . filter { p in isAccepted ( workflows: workflows, part: p) }
121
+ . map { p in p. x + p. m + p. a + p. s }
122
+ . reduce ( 0 , + )
122
123
}
123
124
124
- func doesAccept ( part : Part , workflows : Workflows ) -> Bool {
125
- var workflowName = " in "
125
+ func isAccepted ( workflows : Workflows , part : Part ) -> Bool {
126
+ var workflow = " in "
126
127
next: while true {
127
- let workflow = workflows [ workflowName] !
128
- for rule in workflow {
128
+ for rule in workflows [ workflow] ! {
129
129
if let condition = rule. condition, !condition. isValid ( part: part) {
130
130
} else {
131
131
switch rule. action {
132
132
case . accept: return true
133
133
case . reject: return false
134
- case . send( let wfn ) :
135
- workflowName = wfn
134
+ case . send( let newWorkflow ) :
135
+ workflow = newWorkflow
136
136
continue next
137
137
}
138
138
}
@@ -141,25 +141,26 @@ func doesAccept(part: Part, workflows: Workflows) -> Bool {
141
141
}
142
142
143
143
func filterRanges( workflows: Workflows ) -> Int {
144
- let attributes : [ Attribute ] = [ . x , . m , . a , . s ]
145
- let attributeRanges = Dictionary ( uniqueKeysWithValues: attributes . map { ( $0, 1 ... 4000 ) } )
144
+ let attributeRanges : AttributeRanges =
145
+ Dictionary ( uniqueKeysWithValues: [ . x , . m , . a , . s ] . map { ( $0, 1 ... 4000 ) } )
146
146
var pending = [ ( " in " , attributeRanges) ]
147
147
var acceptedCount = 0
148
148
149
- nextPending: while let ( workflow, _attributeRanges ) = pending. popLast ( ) {
150
- var attributeRanges = _attributeRanges
149
+ nextPending: while let ( workflow, attributeRanges ) = pending. popLast ( ) {
150
+ var attributeRanges = attributeRanges
151
151
for rule in workflows [ workflow] ! {
152
152
if let condition = rule. condition {
153
153
// Conditional rule, will cause attributeRanges to split.
154
154
155
- // Find the part to which this rule applies.
156
- let newAttributeRanges = transformed (
157
- attributeRanges: attributeRanges,
158
- attribute: condition. attribute) {
159
- $0. clamped ( to: condition. validRange)
160
- }
155
+ // Find the range to which this rule applies.
156
+ let attribute = condition. attribute
157
+ let range = attributeRanges [ attribute] !
158
+ let newRange = range. clamped ( to: condition. validRange)
161
159
162
- // Process the part to which the condition applied.
160
+ // Create a new set of attribute ranges with this range, and
161
+ // apply the rule's action to it.
162
+ var newAttributeRanges = attributeRanges
163
+ newAttributeRanges [ attribute] = newRange
163
164
switch rule. action {
164
165
case . reject:
165
166
break
@@ -169,7 +170,8 @@ func filterRanges(workflows: Workflows) -> Int {
169
170
pending. append ( ( newWorkflow, newAttributeRanges) )
170
171
}
171
172
172
- // For the parts that we didn't process here
173
+ // There will be a leftover range, possibly empty. Continue
174
+ // processing it if it is not empty.
173
175
let remaining = remainingNonEmptyRanges (
174
176
range: attributeRanges [ condition. attribute] !,
175
177
validRange: condition. validRange)
@@ -185,7 +187,7 @@ func filterRanges(workflows: Workflows) -> Int {
185
187
fatalError ( " found 2 remaining entries \( remaining) " )
186
188
}
187
189
} else {
188
- // Unconditional rule, always a match, so applies to the whole ranges
190
+ // Unconditional rule, always a match, so consumes the whole ranges
189
191
switch rule. action {
190
192
case . reject:
191
193
break
@@ -194,11 +196,11 @@ func filterRanges(workflows: Workflows) -> Int {
194
196
case . send( let newWorkflow) :
195
197
pending. append ( ( newWorkflow, attributeRanges) )
196
198
}
197
- // Done processing this rule
198
199
continue nextPending
199
200
}
200
201
}
201
202
}
203
+
202
204
return acceptedCount
203
205
}
204
206
@@ -208,15 +210,6 @@ func combinations(attributeRanges: AttributeRanges) -> Int {
208
210
attributeRanges. values. reduce ( 1 , { $0 * $1. count } )
209
211
}
210
212
211
- func transformed(
212
- attributeRanges: AttributeRanges , attribute: Attribute ,
213
- transform: ( ClosedRange < Int > ) -> ClosedRange < Int >
214
- ) -> AttributeRanges {
215
- var copy = attributeRanges
216
- copy [ attribute] = transform ( attributeRanges [ attribute] !)
217
- return copy
218
- }
219
-
220
213
func remainingNonEmptyRanges( range: ClosedRange < Int > , validRange: ClosedRange < Int >
221
214
) -> [ ClosedRange < Int > ] {
222
215
var result = [ ClosedRange < Int > ] ( )
0 commit comments