Skip to content

Commit 79854c0

Browse files
committed
Day 4 with an "all-solo" alternate solution.
1 parent b92845c commit 79854c0

File tree

3 files changed

+77
-4
lines changed

3 files changed

+77
-4
lines changed

docs/day04.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
* [Problem statement](https://adventofcode.com/2021/day/3)
44
* [Solution code](https://github.com/abyala/advent-2021-clojure/blob/master/src/advent_2021_clojure/day04.clj)
5+
* [All-solo solution code](https://github.com/abyala/advent-2021-clojure/blob/master/src/advent_2021_clojure/day04-all-solo.clj)
56

67
---
78

@@ -226,3 +227,47 @@ list. Other than the constructor and changing `final-score` to call `(first numb
226227

227228
What's the lesson? Encapsulation is still important at times, but using open maps and properties doesn't need to be
228229
scary.
230+
231+
---
232+
233+
## Other Approaches
234+
235+
My coworker [mtkuhn](https://github.com/mtkuhn) posted a different algorithm in his
236+
[Kotlin-based solution](https://github.com/mtkuhn/advent-of-code-2021/blob/master/doc/day4.md) to this problem. From
237+
his solution, I offer another way to solve the problem. Essentially, we let each board run through the numbers as solo
238+
games, recording both the number of turns required to finish and the final score. We sort these solutions in turn
239+
order. For part 1, we pick the score of the first game (the one that finished first), and for part 2 we pick the score
240+
of the last game.
241+
242+
I put the relevant code into a different namespace called `day04-all-solo` to keep the solutions distinct, but I
243+
reused almost everything from my solution. The `solo-results` function takes in a game that's assumed to have a
244+
single board in it, and it again uses `day04/take-turn`. This time, though, instead of calling `(keep final-score)`,
245+
I used `keep-indexed` so we'd know which iteration of the game gave us the first winning score. My friend `when-let`
246+
binds the final score to `score` once it exists, and we return the first such value.
247+
248+
The `solve-all` function is responsible for splitting the original game - the one with all of the boards - into
249+
multiple solo games by mapping each board to a game that only has the one board. This is simple to do with
250+
`(map #(assoc game :boards [%]) (:boards game))`, since we can just set the entire vector of `boards` to a
251+
single-elemtn vector. Then we map each game to `solo-results` and sort them in turn order using `(sort-by :turns)`.
252+
253+
Finally, the revised `part1` and `part2` functions parse the game, call `solve-all`, take either the first or last
254+
such game result, and extract the score back out.
255+
256+
```clojure
257+
(defn solo-results [game]
258+
(->> (iterate day04/take-turn game)
259+
(keep-indexed (fn [idx g] (when-let [score (day04/final-score g)]
260+
{:turns idx :score score})))
261+
first))
262+
263+
(defn solve-all [game]
264+
(let [solo-games (map #(assoc game :boards [%]) (:boards game))]
265+
(->> solo-games
266+
(map solo-results)
267+
(sort-by :turns))))
268+
269+
(defn part1 [input] (-> input day04/parse-game solve-all first :score))
270+
(defn part2 [input] (-> input day04/parse-game solve-all last :score))
271+
```
272+
273+
Cool idea, Matt!
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
(ns advent-2021-clojure.day04-all-solo
2+
(:require [advent-2021-clojure.day04 :as day04]))
3+
4+
(defn solo-results [game]
5+
(->> (iterate day04/take-turn game)
6+
(keep-indexed (fn [idx g] (when-let [score (day04/final-score g)]
7+
{:turns idx :score score})))
8+
first))
9+
10+
(defn solve-all [game]
11+
(let [solo-games (map #(assoc game :boards [%]) (:boards game))]
12+
(->> solo-games
13+
(map solo-results)
14+
(sort-by :turns))))
15+
16+
(defn part1 [input] (-> input day04/parse-game solve-all first :score))
17+
(defn part2 [input] (-> input day04/parse-game solve-all last :score))
Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
11
(ns advent-2021-clojure.day04-test
22
(:require
33
[clojure.test :refer :all]
4-
[advent-2021-clojure.day04 :refer :all]))
4+
[advent-2021-clojure.day04 :as day04]
5+
[advent-2021-clojure.day04-all-solo :as day04-solo]))
56

67
(def test-input (slurp "resources/day04_sample_data.txt"))
78
(def puzzle-input (slurp "resources/day04_data.txt"))
89

910
(deftest part1-test
10-
(are [expected input] (= expected (part1 input))
11+
(are [expected input] (= expected (day04/part1 input))
1112
4512 test-input
1213
49686 puzzle-input))
1314

1415
(deftest part2-test
15-
(are [expected input] (= expected (part2 input))
16+
(are [expected input] (= expected (day04/part2 input))
1617
1924 test-input
17-
26878 puzzle-input))
18+
26878 puzzle-input))
19+
20+
(deftest part1-all-solo-test
21+
(are [expected input] (= expected (day04-solo/part1 input))
22+
4512 test-input
23+
49686 puzzle-input))
24+
25+
(deftest part2-all-solo-test
26+
(are [expected input] (= expected (day04-solo/part2 input))
27+
1924 test-input
28+
26878 puzzle-input))

0 commit comments

Comments
 (0)