@@ -153,4 +153,74 @@ in to `find-digits` with the `outputs`, and add together the results. See? Tha
153
153
(map (fn [[patterns outputs]] (-> (identify-signals patterns)
154
154
(find-digits outputs))))
155
155
(apply +)))
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Alternative
161
+
162
+ My Twitter friend [ @JoePittsy ] ( https://twitter.com/JoePittsy ) posted an
163
+ [ absolutely brilliant solution] ( https://twitter.com/JoePittsy/status/1468598079569989636/photo/1 ) to part 2 in Python
164
+ which, after I read it multiple times and understood the approach (I don't know Python), I just had to reproduce in
165
+ Clojure and share with the world.
166
+
167
+ He starts with the accepted observation that we can immediately determine the letters in the 1 and 4 signal patterns,
168
+ because the 1 is the only pattern with two segments, and the 4 is the only pattern with four segments. Once you have
169
+ those two patterns identified, _ you don't need to identify the other patterns._
170
+
171
+ Instead, we can go directly to the four output values, and extract three pieces of data - the length of the output,
172
+ the number of overlapping segments with the 1, and the number of overlapping segments with the 4. These three data
173
+ elements will uniquely identify each number. For example:
174
+
175
+ * We know from my solution that there are three numbers that have six segments: 0, 6 and 9.
176
+ * Zero has two overlaps with 1 (c and f), and three overlaps with 4 (b, c, and f).
177
+ * Six has one overlap with 1 (f) and three overlaps with 4 (b, d, and f).
178
+ * Nine has two overlaps with 1 (c and f), and four overlaps with 4 (b, c, d, and f).
179
+ * Thus in a partial map of ` {[count overlaps-with-one overlaps-with-four] digit} ` , we would have at least
180
+ ` {[6 2 3] 0, [6 1 3] 6, [6 2 4] 9} ` .
181
+
182
+ Taking all ten digits, we create ` digit-finder ` :
183
+
184
+ ``` clojure
185
+ (def digit-finder {[6 2 3 ] 0
186
+ [2 2 2 ] 1
187
+ [5 1 2 ] 2
188
+ [5 2 3 ] 3
189
+ [4 2 4 ] 4
190
+ [5 1 3 ] 5
191
+ [6 1 3 ] 6
192
+ [3 2 2 ] 7
193
+ [7 2 4 ] 8
194
+ [6 2 4 ] 9 })
195
+ ```
196
+
197
+ So given that we have out lookup table/map, we can create the function ` digits ` , which takes in the patterns and
198
+ outputs, and returns the digits. First, we identify ` one ` and ` four ` by finding the distinct 2- and 4-character
199
+ in the pattern segments. Then we create a function ` digit-keys ` using ` juxt ` , which applies the three functions we
200
+ need to form the key of ` digit-finder ` - the length of the input, the number of segments intersecting ` one ` , and the
201
+ number of segments intersecting ` four ` . The ` (map (comp digit-finder digit-keys) outputs) ` line converts each of the
202
+ _ outputs_ (not patterns) into the key we need, then looks it up in ` digit-finder ` to get the actual digit. Then
203
+ finally we concatenate each digit into a string and parse it as an int to get the actual digit.
204
+
205
+ ``` clojure
206
+ (defn digits [patterns outputs]
207
+ (let [one (first (filter #(= 2 (count %)) patterns))
208
+ four (first (filter #(= 4 (count %)) patterns))
209
+ digit-keys (juxt count
210
+ (comp count (partial set/intersection one))
211
+ (comp count (partial set/intersection four)))]
212
+ (->> outputs
213
+ (map (comp digit-finder digit-keys))
214
+ (apply str)
215
+ parse-int)))
216
+ ```
217
+
218
+ Finally, the revised ` part2 ` function is really simple - parse the input, call ` digits ` on each line, and add up the
219
+ digits. Well done, [ @JoePittsy ] ( https://twitter.com/JoePittsy ) !
220
+
221
+ ``` clojure
222
+ (defn part2 [input]
223
+ (->> (parse-input input)
224
+ (map (partial apply digits))
225
+ (apply +)))
156
226
```
0 commit comments