|
2 | 2 |
|
3 | 3 | * [Problem statement](https://adventofcode.com/2021/day/3)
|
4 | 4 | * [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) |
5 | 6 |
|
6 | 7 | ---
|
7 | 8 |
|
@@ -226,3 +227,47 @@ list. Other than the constructor and changing `final-score` to call `(first numb
|
226 | 227 |
|
227 | 228 | What's the lesson? Encapsulation is still important at times, but using open maps and properties doesn't need to be
|
228 | 229 | 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! |
0 commit comments