Skip to content

Commit 4b2af0f

Browse files
committed
Solve y2024/d3
1 parent bf633fa commit 4b2af0f

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,6 @@
3838
| | | |
3939
| 2024 | [1](src/y2024/d1.clj) | I think I'll break from, uh, _tradition_ this year and write marginally more serious summaries! :D</br></br>That said, not much to say about this one. Nice warmup. Hopefully I can keep up the readability, among other things, as we go on — because if I had a goal for **AoC 2024** it'd be to produce elegant, readily understandable (especially to [Clojure](https://clojure.org) beginners), _performant_ solutions. In roughly that order.</br></br>I know I'm going to miss some days. But at the very least I hope to keep up, then swing back later to fill in any gaps. There's only so much time in December for 'toy problems' anyhow... which as it happens is a happy constraint. I'm very grateful that [Clojure](https://clojure.org) isn't just a _toy language_ for me, but a living. Perhaps my rushed solutions here can help others into the same predicament? `(repeat "ONE OF US")`</br></br>P.S. Do also check out the [#adventofcode](https://clojurians.slack.com/archives/C0GLTDB2T) channel in Clojurians Slack! There will be daily solution threads. I always learn a lot from them. |
4040
| 2024 | [2](src/y2024/d2.clj) | This one was fun! My initial approach to **Part One** — based on partitioning each 'report' into pairs, then checking the first pair to determine whether the rest of the report should increase, decrease, or had already failed — didn't seamlessly scale to **Part Two**, so I had to go back to the drawing board a bit. What I ended up with was one big [reduce](https://clojuredocs.org/clojure.core/reduce) that first _scores_ each report based on number of increasing pairs, number of decreasing pairs, and number of 'bounded' pairs; checks whether a score is 'safe' (i.e. the bounded total, plus either the increasing or decreasing total, equals the number of pairs); then if it *isn't* (and a `retry?` arg is true), runs (lazily) over the possible alternate reports missing one element until either a safe alternate is found, or there are no more alternates to test.</br></br>I had worried about this resulting in needlessly, repeatedly scoring the same pairs, so I [memoize](https://clojuredocs.org/clojure.core/memoize)d the `score-pair` function. But this didn't seem to make any measurable difference to performance — plenty fast in either case. Perhaps with much larger 'reports', or a 'tolerance' higher than one bad element, things would get more interesting. :) |
41+
| 2024 | [3](src/y2024/d3.clj) | Cute! A nice short one this morning. It will be interesting to see if subsequent days expand on it... :D |
4142

4243
Feedback welcome!

src/y2024/d3.clj

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
(ns y2024.d3
2+
(:require [hyperfiddle.rcf :refer [tests]]
3+
[utils :as u]))
4+
5+
; Why did I treat the example inputs here as vectors of (single) strings? Simply because my u/input parses the actual
6+
; puzzle input into a vector of strings!
7+
;
8+
; One of these days I may start writing new parsing utils, so that I can speed up the inevitable parsing step that
9+
; every one of these problems begins with. But so far... well, a vector of strings has always seemed just fine. :)
10+
(def example-input-1 ["xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))"])
11+
(def example-input-2 ["xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))"])
12+
(def input (u/input))
13+
14+
; ----------------------------------------------------------------------------------------------------------------------
15+
16+
(defn parse-line
17+
[line]
18+
(let [match->op+nums
19+
(fn [[_ op n1 n2]]
20+
(let [op-kw (keyword op)]
21+
(if (= :mul op-kw)
22+
[op-kw (parse-long n1) (parse-long n2)]
23+
[op-kw])))]
24+
(->> (re-seq #"((?:mul|do|don't))\((?:(\d{1,3}),(\d{1,3}))?\)" line)
25+
(map match->op+nums))))
26+
27+
; ----------------------------------------------------------------------------------------------------------------------
28+
29+
(defn solve
30+
[input & {:keys [:part] :or {part 1}}]
31+
(->> (mapcat parse-line input)
32+
(reduce (fn [{:keys [do? _total] :as m} [op n1 n2]]
33+
(cond
34+
(and (or (= 1 part) do?) (= :mul op))
35+
(update m :total + (* n1 n2))
36+
37+
(and do? (= :don't op))
38+
(assoc m :do? false)
39+
40+
(and (not do?) (= :do op))
41+
(assoc m :do? true)
42+
43+
:else m))
44+
{:do? true
45+
:total 0})
46+
(:total)))
47+
48+
49+
(tests
50+
(solve example-input-1 {:part 1}) := 161
51+
(solve example-input-2 {:part 2}) := 48
52+
)
53+
54+
(comment
55+
(solve input {:part 1})
56+
(solve input {:part 2})
57+
)

0 commit comments

Comments
 (0)