Home

Awesome

Advent of Code

yeardaysummary
20151reduuuuuuuce
20152simple regex, yummy destructuring, map/reduce... fun!
20153reduce is very versatile!
20154clojure is plenty fast, eh?
20155maybe helper functions would be more readable? otherwise, simple enough :)
20156had some (but not tooooo much) fun optimising, ha
20157WIP
20201(just warming up for 2024!)
20211off to a nice, neat start
20212sooo much nicer than my first attempt!
20213not terrible
20221let's goooooo!
20222alright: I was a bit distracted :P
20223neat... but feels like the calm before the storm
20224ditto
20225parsing is a little inelegant, but the rest was fine :)
20226piece of piss
20227SO IT BEGINS
20228eh... quite ugly :/
20229not too bad!
202210neat enough!
202211part 1? fine. part 2? uhhhhh...
202212a little ugly. but more importantly: slowwwww...
202213little hard to understand the spec, but got there in the end
202214easy enough; wordy solution though
20231overlapping regex, grrrrr...
20232zero snags; enjoyed making it nice :)
20233easy peeeeez... once I figured how best to parse things
20234neat!
20241I 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 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 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 channel in Clojurians Slack! There will be daily solution threads. I always learn a lot from them.
20242This 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 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 memoized 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. :)
20243Cute! A nice short one this morning. It will be interesting to see if subsequent days expand on it... :D
20244Enjoyed this one! I was glad to be reminded that clojure.core.matrix exists, after first spending a few minutes fiddling with a rather imperative loop to generate the diagonals for Part One. m/diagonal did just what I wanted.</br></br>As for Part Two, I didn't immediately see a way to re-use my initial (regex over string lines) approach... so I didn't bother. Instead I generated a list of all the three-by-three sub-matrices and simply matched characters.
20245Proud of myself today. Started down the road towards brute forcing... but stopped before I got too far, and found a neat trick instead! :)</br></br>In short, consider: (1) each 'update' implies its own set of rules; and (2) if one or more of these rules is backwards with regards to the actual rule set, the 'update' is out-of-order.</br></br>That's it!</br></br>As for Part 2, the rule set trivially entails a comparator that can be passed to sort-by. Fun!
20247Fun problem! Solved it rather quickly, including Part Two as the only difference between them was an extra 'op'... at least, that's quicky in terms of development time! My first Part Two solution took nearly a minute to churn through all the combinations of +, *, and ||. So I had to do something about that.</br></br>Naturally, I reached right for clj-async-profiler. Which immediately put the spotlight on (what came to be called) apply-ops-v1. Swapping a recusive solution for one based on reduce improved performance by ~2x. Then, solve-v2 swapped a keep for a pmap for another ~2x speedup.</br></br>In retrospect—and after seeing how folks in Clojurians Slack approached Day 7!—I was maybe a bit too attached to, well, my brute-forcey solution. And rather than try to eke out little incremental gains... at least one really neat trick was waiting there to be found that would have sped things up by orders of magnitude instead. Oh well. Flame graphs are pretty. :D

Feedback welcome!