This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-12-20
Channels
- # adventofcode (38)
- # announcements (8)
- # aws (4)
- # babashka (131)
- # beginners (263)
- # calva (2)
- # clj-kondo (12)
- # cljdoc (12)
- # cljsrn (3)
- # clojure (122)
- # clojure-europe (3)
- # clojure-finland (2)
- # clojure-nl (13)
- # clojure-uk (80)
- # clojured (1)
- # clojuredesign-podcast (3)
- # clojurescript (78)
- # core-async (19)
- # cursive (19)
- # datomic (7)
- # duct (10)
- # events (1)
- # fulcro (7)
- # graalvm (12)
- # graphql (3)
- # juxt (4)
- # malli (10)
- # music (3)
- # nrepl (4)
- # off-topic (25)
- # pathom (4)
- # pedestal (1)
- # re-frame (78)
- # reagent (8)
- # shadow-cljs (91)
- # sql (8)
- # vim (3)
- # xtdb (2)
1. Seal up dead-ends (including doors that lead to dead ends) 2. Remove trivial key-door pairs, I think every puzzle set has a series of these in one path 3. Remove keys for which there are A. no doors and B. which are automatically retrieved en route to another key I suspect you should reduce the mazy to a dependency graph - the obvious route for mine can be worked out by hand and a couple of assisting tools (distance between points); I just haven't had the time yet. Of these, the first is the biggest aid to visualizing the shape of the data you've been given and understanding its quirks.
One key optimization I used is that the state after getting keys a,b,c and b,a,c are the same. So if you have a fn shortest-path(curpos, collectedkeys) you can memoize it.
The second one is that I created a map from key/entrancepoint to the possible other keys with their distance and doors in between. You can compute this map once and use it to efficiently get the next possible steps given your current position(s) and collected keys
There's a whole path in mine that has nothing but keys; you can fetch each of them with optimal efficiency with a thorough traversal, and that unlocks the next dependency in the graph as well given which ones are placed in there. I'm presuming based on what I saw in other inputs that each maze is very similar in logical layout.
Well, took long enough. Spent way too much time parsing by hand which probably could have been spent manually encoding the maze coordinates. ... And that's just part one. Part two will have to come later, but I'm intrigued.
That parsing was annoying. My first version had a bug because it read labels in the order away from the maze point .
. But all labels read left-to-right or up-to-down.
I lied, finished it. It was too interesting to resist. The changes aren't that significant between phases.
that was fast.
I wasted time debugging because of bug in outer-portal?
fn, which I wrote first, and assumed it fails last
My first answer was off because I mis-counted where the bottom/right inner portals were placed; converting that to a calculated value instead of a hand-measured one was more robust for using the sample scenarios to test, anyway
a tube, and you obviously have to use BFS, or you risk chasing infinity on very first path walk
Got behind a bit due to travel. Caught up today: Day 19 https://gitlab.com/dmarjenburgh/adventofcode/blob/a159992a5123919594d95471ed7fae0fd2afdbc8/src/adventofcode/year_2019.clj#L587-617 Day 20 https://gitlab.com/dmarjenburgh/adventofcode/blob/a159992a5123919594d95471ed7fae0fd2afdbc8/src/adventofcode/year_2019.clj#L619-663 Again searching on a grid, finding neighbours above,below,left and right. I’ve written that code so many times I’m wondering if I should find a way to reuse it 😄
I used to feel Clojure is not the best language for things like AoC, but in many situations it is and in others I now feel it probably requires a different way of approaching the problem. With the right solution, I think the Clojure code is always fast enough. For day 19 with the tractor beam, I wrote an infinite lazy-sequence that gets more of the beam with each item (the beam points for the next y-coordinate). Then the stopping condition was a separate fn and I could use take-while
. It decouples generating the next iteration from calculating the stopping condition (square), the lazy-sequence could be used for both part 1 and 2. In in imperative loop, these things would have been coupled.
you can just find first bottom-left corner for which all 4 corners will be within beam. even no need for lazy seqs there
Doesn’t that amount to the same amount of calculations? You iterate until you can fit the square
tbh your code is hard to glance over with all the inline fns with nested inline destructuring, so maybe you did exactly what I wrote.
(defn beam? [cpu x y]
(when (-> cpu (assoc ::cpu/input [x y]) cpu/step ::cpu/output (= 1))
[x y]))
(defn score [x y]
(-> x (* 10000) (+ y)))
(defn f2 [input size]
(let [cpu (make input)
size (dec size)]
(loop [x1 0
y2 size]
(if-not (beam? cpu x1 y2) ;;left bottom corner
(recur (inc x1) y2)
(let [x2 (+ x1 size)
y1 (- y2 size)]
(if (and
(beam? cpu x2 y2) ;;right bottom corner
(beam? cpu x2 y1)) ;;right top corner
(score x1 y1)
(recur x1 (inc y2))))))))
It’s the same in going down increasing y per iteration and stopping when the square fits. I have some optimization based on the assumption that the min-x/max-x coords of the beam change by 1 unit at most (which held true). Therefore I run the intcode program twice per y coordinate.
it depends on what you consider "fast enough". seconds? yes. But c++ and rust people start to cringe if stuff takes 10ms+ to run
I’d rather save on development time
altho, some of the python/c aoc solutions are just 2-3variables and 2-4 nested loops, for 7-10 lines total, less characters than my usual parse-input fn
I doubt anyone ever got global top100 gold star with clojure for any mid month-ish puzzle
I feel like part of the reason was the instant RDD feedback and being able to directly get a feel of the shape of the data and manipulate it, definitely makes up for some of the verbosity
but elegance is just one of dimensions, and is rarely a top1 one would consider while solving puzzles under time limit