Day 8 - Solutions
Yeah today was easy https://gist.github.com/RokLenarcic/9350d027d293a0dce71b68e7d68c0161
p1 (sort positions)
p2 (sort positions)
:when (= 1 (compare p1 p2))
If youβre going to do a compare, why sort them at all?try deleting sorts and see if it changes the result
It keeps the values in a nice predictable order for testing as I go
Took me a minute to find how to determine whether a division was an integer... Also I remember week-end being super hard, but this year has been surprisingly easy ?
nothing fancy:
(def input #(slurp (format "resources/2024/%02d" %)))
(let [grid (->> (input 8) (re-seq #".+") (mapv vec))
rows (count grid)
cols (count (first grid))
inmap? (fn [[r c]] (and (< -1 r rows) (< -1 c cols)))
grid-map (into {} (for [r (range rows)
c (range cols)]
[[r c] (get-in grid [r c])]))
antenna-map (update-vals (dissoc (group-by val grid-map) \.) #(map key %))]
[(->> (for [[antenna locs] antenna-map
loca locs
locb locs
:when (not= loca locb)]
(map - (map * loca [2 2]) locb))
(filter inmap?)
set
count)
(->> (for [[antenna locs] antenna-map
loca locs
locb locs
:when (not= loca locb)
:let [diff (map - loca locb)]]
(iterate #(map - % diff) loca))
(mapcat #(take-while inmap? %))
set
count)])After solving, I kept playing for a while with transducers: https://github.com/erdos/advent-of-code/blob/master/2024/day08.clj
What times did you end up with? I never know whether to use transducers or reducers. I find reducers easier to manipulate, but maybe transducers are faster?
around 7ms+7ms with both bb and clj. I think majority is taken up by creating vector objects.
I didn't need any division at all in my approach. What really made me happy was being able to solve part 2 with just one new fn and an adjustment to one other. https://github.com/rjray/advent-2024-clojure/blob/master/src/advent_of_code/day08.clj
> able to solve part 2 with just one new fn and an adjustment to one other. this.
same thing here, just needed to change the function that outputs the set of anti-nodes induced by one kind of antennas
Exactly. When I did part 1, that function was called by name in the outer function that iterated over the types of antennae. I changed the outer fn to take a "finder" as first parameter and part 2 just subbed in a new one.
I miss re-seq π₯²
> nothing fancy I really like the simplicity of your solution @zengxh, mine is similar to @rjray's one.
(defn calc-antinodes-2 [in-bounds? pair]
(let [[[x1 y1] [x2 y2]] pair
dx (abs (- x1 x2))
dy (abs (- y1 y2))
[a c] (if (< x1 x2) [- +] [+ -])
[b d] (if (< y1 y2) [- +] [+ -])]
(concat
(->> (iterate (fn [[x y]] [(a x dx) (b y dy)]) [x1 y1])
(take-while in-bounds?))
(->> (iterate (fn [[x y]] [(c x dx) (d y dy)]) [x2 y2])
(take-while in-bounds?)))))Ended up similar to @zengxhβs for approach but with another dimension for steps.
Runs in about 30ms, probably due to lots of unnecessary stepping outside the board.
Runs in around 115us/315us
I always forget about libraries
should have used combinatorics lib instead of writing my own function for pairs
Simplified my answer by using combinatorics and factoring out the common terms (went back and changed part1 to be answered by part2 code). https://gist.github.com/RokLenarcic/9350d027d293a0dce71b68e7d68c0161
I'm wondering what's the number of a result with this input? I'm stuck with a full test but a sample test works.
0...
.A..
..A.
Is this 0 . Right?
Ah.. part 1For which part?
this particular snippet has 1
Thanks. hmm.. weird.
The 2 As have an antinode at position of character 0
So A's antinode can install at (0,0)?
Yes
> Antennas with different frequencies don't create antinodes; A and a count as different frequencies. However, antinodes can occur at locations that contain antennas.
Thanks for clarifying.
Simplified it, now I'm happy with my solution for the both parts https://github.com/zelark/AoC/blob/master/src/zelark/aoc_2024/day_08.clj
> but only when one of the antennas is twice as far away as the other. This part really messed with me π I'm not sure how this factors into the problem at all
Any antinode X' is paired with an antenna X, not a couple of antenna (X, Y) in their way of explaining it. So the distance between X and X' is twice the distance between X and Y. It's just a very convoluted way of explaining something that is very clear with a diagram.
This part really messed with meIt messed me up too
@mail191 Itβs basically a fancy way of saying that you take a line between the points and paste it each direction.
The advantage of not reading half the text and looking at the samples first π
@malaingreclement yes, but sometimes you might miss a really important detail and it could cost you a lot
Oh I know. It was mostly a joke. It's just that I'm trying to be faster this year and I'm skipping the fluff for after submission. Actually filtering what is fluff and what is important while diagonal reading is a cool skill to develop, and AoC is low-stake.
meh
nodes2 (reduce into #{}
(for [[k xys] M->xys
[x y] xys
[X Y] xys
:when (not= k \.)
:when (not= [x y] [X Y])]
(let [dx (- X x)
dy (- Y y)
f1 (fn [[x y]] [(- x dx) (- y dy)])
f2 (fn [[x y]] [(+ x dx) (+ y dy)])]
(concat
(->> [x y] (iterate f1) (take-while within))
(->> [x y] (iterate f2) (take-while within))))))I need a help. With the example case, the third antinode from 0 and the first antinode from A must count as 1?
You're asked to count unique locations for antinodes, yeah
I want to reset my brain. I was messed up with requirements of the problem. Thank you. I must be back.
I ran this on the second part...
(quick-bench (transduce (xf (range sz)) + xs))
Which gives Execution time mean : 326.636769 Β΅s but that can't be right, can it? Its a few ms with timedoesn't that throw?
Nope... should it? First time using criterium
What does bench tell you ?
are you perhaps testing with the example input in quick-bench and with the real one in time?
Because the Java JIT compiler compiles code differently after the code has been running for a bit of time, if you want to useFrom Notes in https://clojuredocs.org/clojure.core/timetimefor benchmarking, you should at least "warm up" your code by running it several times, using the latertimeoutputs as the ones that count. A better strategy is to use a benchmarking library such as https://github.com/hugoduncan/criterium, which will do the warmup for you, and much more.
Its on the full input... maybe its just wicked fast π
My part1 benches at 244 us, so I don't think you have a mistake.
Checked for my part 1
;; time: 6.560913 msecs
;; criterium: 4.000629 ms
looks similar, but it counts the parsing as wellWithout the parsing it is about 660.637259 Β΅s
So I just realized you can just use the https://www.andreaminini.net/math/central-symmetry to calc antinodes super easily... I am literally dumber than when I was in middle school x) > In the plane, the central symmetry of any point P(x;y) with respect to another point C(x0;y0) chosen as the center of symmetry can be determined using the following equations: > xβ²=2x0βx, yβ²=2y0βy
@malaingreclement did you see this line from @zengxh's solution:
(map - (map * loca [2 2]) locb)
that's it
I gave it a cursory read but was confused by that line, yeah. Should have asked.
I'm pretty ashamed that I couldn't solve a part2 from my codebase. It's really hard to extend at the moment and I will have to definitely write code with erasing all my memory. https://github.com/jungwookim/aoc-exercise/blob/master/src/aoc/2024/day8.clj I was pretty painful today for some reasons so I need to try to refresh myself and retry it later, not today. I would be able to check other's solution if i get learned as an education π₯²
Sweet and simple today:
(ns aoc2024.day8
(:require [ :as io]
[clojure.math.combinatorics :refer [combinations]]
[net.cgrand.xforms :as xforms]))
(defn read-input [filename]
(with-open [rdr (io/reader filename)]
(let [lines (vec (line-seq rdr))]
{:dim [(count (first lines)) (count lines)]
:antennas (for [[y line] (map-indexed vector lines)
[x ch] (map-indexed vector line)
:when (not= ch \.)]
[ch [x y]])})))
(defn within-bounds? [[w h] [x y]]
(and (< -1 x w) (< -1 y h)))
(def coord+ (partial mapv +))
(def coord- (partial mapv -))
(defn antinode-pair [bounds [v1 v2]]
(let [d (coord- v2 v1)]
(filter (partial within-bounds? bounds)
[(coord- v1 d) (coord+ v2 d)])))
(defn antinode-list [bounds [v1 v2]]
(let [d (coord- v2 v1)]
(concat (take-while (partial within-bounds? bounds) (iterate #(coord- % d) v2))
(take-while (partial within-bounds? bounds) (iterate #(coord+ % d) v1)))))
(defn all-antinodes [antinode-fn bounds antennas]
(->> (combinations antennas 2)
(mapcat (partial antinode-fn bounds))))
(defn compute [antinode-fn {:keys [dim antennas]}]
(let [groups (into {} (xforms/by-key (xforms/into [])) antennas)]
(count
(into #{}
(mapcat (partial all-antinodes antinode-fn dim))
(vals groups)))))
(def part1 (partial compute antinode-pair))
(def part2 (partial compute antinode-list)) a relief to finally have a solution that runs in less than a second for part 2
And hereβs todays: https://github.com/bhauman/adv2024/blob/main/src/adv2024/day08/sol.clj
(def width (count input))
(def locations (set (for [y (range width) x (range width)] [y x])))
(def station-locs (-> (reduce #(update %1 (get-in input %2) conj %2) {} locations)
(dissoc \.)))
(defn dydx* [[[y x] [y' x']]] [(- y' y) (- x' x)])
(defn antinodes [station-pair]
(let [dydx (dydx* station-pair)]
(->> (concat
(mapv #(mapv - % dydx) station-pair)
(mapv #(mapv + % dydx) station-pair))
(remove (set station-pair))
(filter locations))))
;; part 1
(->> (vals station-locs)
(map #(combo/combinations % 2))
(map #(mapcat antinodes %))
(reduce into #{})
count)
(defn antinodes-freq [station-pair]
(let [dydx (dydx* station-pair)]
(into
(take-while locations (iterate #(mapv - % dydx) (first station-pair)))
(take-while locations (iterate #(mapv + % dydx) (first station-pair))))))
;; part 2
(->> (vals station-locs)
(map #(combo/combinations % 2))
(map #(mapcat antinodes-freq %))
(reduce into #{})
count)itβs definitely better to use a fn like @erdos mirrors for part 1
in fact it seems like thatβs what most folks did β¦ and I apparently didnβt feel like thinking about it
β¦ and I reimplemented group-by instead of just using it
I forgot to post my solution, but at a quick glance, it looks similar to other solutions posted here. β’ Blog: https://github.com/abyala/advent-2024-clojure/blob/main/docs/day08.md β’ Source: https://github.com/abyala/advent-2024-clojure/blob/main/src/advent_2024_clojure/day08.clj
#yamlscript Part 2 (late start today)
It's already a meme https://www.reddit.com/r/adventofcode/comments/1h9bmsm/2024_aoc_day_8_what_does_this_even_mean/
I wasnβt expecting memes on Reddit to be one of my favorite parts of aoc this year but here we are
Yeah, I have zero clue what day 8 is asking. Skipping it.
AOC creator Eric Wastl spoke on the project recently: https://www.youtube.com/watch?v=uZ8DcbhojOw things I found interesting: β’ first year he estimated 70 users, got 50k, up to 1.5m now β’ when trying to clarify problem descriptions, he considers that βfor every sentence, there is a user that skipped only that sentenceβ β’ he considers accessibility issues as incidents - they are outages for some % of users. I thought this was great framing.
I had seen the one he presented a few years ago: https://www.youtube.com/watch?v=gibVyxpi-qA seems like an updated version of it judging by the slides π will check it out!
Hi! I am working through Advent of Code a few days behind. For https://adventofcode.com/2024/day/6, I am getting a stackoverflow error, and cannot figure out why it might be happening. When I run the code on my test-input, I get the correct result. Running on actual input gives the error. The primary function is a recursive one, so I feel the error is somewhere in there, but if i had an endless loop I feel like that'd fail in the test-input too. I don't think I'm using any lazy sequences in the recursive function either. The relevant code is here: https://git.sr.ht/~zim/advent-of-code-2024/tree/main/item/day-6/solution.clj Would someone mind scanning that to see if there's an obvious error causing the stack overflow?
Thank you for this explanation!
The primary function is here: https://git.sr.ht/~zim/advent-of-code-2024/tree/main/item/day-6/solution.clj#L89 And I reduced the inputs down to just sequences of positions, so it doesn't feel computationally heavy. I am stuck!
try using recur on line 91 instead
stack overflow suggests you have too many nested function calls
That did it, thank you!
do you understand whatβs happening?
Kind of. Recur is a function that replaces the given function it's within, in my case big-bang and the parallel rebindings special to recur prevents the nested functions? That's my rough understanding.
Critically recursion in Clojure without recur consumes the call stack. Do that too many times and your program blows up. recur just jumps to the nearest recur point and starts over with the arguments you gave it - no call stack needed. only caveat is that recur must be in tail position. See also loop