My day 2. Based on other solutions, I need to learn to use for a bit better, but happy overall. https://github.com/SNordlinger/advent2019/blob/master/2/clj/src/comp.clj
My day AOC (up to day2) : https://repl.it/@ben_w_trent/aoc2019
Lessons learned: (for [x (range 99) y (range 99)] [x y])
Did not know about for
for generating sequences 😄. I was doing some super complex combinatorics and thought that there HAD to be a better way. Glad there is
Also beware range is exclusive upper bound but I think the problem calls for inclusive range
day 2 was a bit simpler since there was only multiplication and addition involved. and they chose quite easy numbers to solve it
Ah, cool. Well, my solution was under 99 :).
Same 😌
part 2 is a particularly nice way to add core.logic as well
order of operations tripped me up at the end
#lisplyfe
I’ve brain-dumped all order of operations rules
(ns advent.day02.day02
(:require [clojure.math.combinatorics :as combo]))
(def blah (combo/selections (range 100) 2))
Gets only half the combinations 😉
It gets 'em all, doesn't it?
advent.day02.day02> (combo/selections (range 3) 2)
((0 0) (0 1) (0 2) (1 0) (1 1) (1 2) (2 0) (2 1) (2 2)
one thing that came up in my brute force search was it wasn’t clear what the best way to break from the search was. I ended up using some
, but is there a better way to basically do:
for i in coll:
if i == search_item:
return i
thus avoiding searching the rest of the collection?
I’ve read the docs a bunch of times and :when
and :while
still confuse me for for
I did like this: https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day2.clj#L37
for
is lazy so when you get the first
it terminates early
I thought since sequences are lazy, they might "chunk"? After thinking about it, I think that might be true even for my some
usage. The only way to avoid chunking is using reduce
/`reduced`, or maybe bypass chunking with lazy-seq
?
Why would chunking be a problem?
Because chunking would eval until 32 possible matches are found, or the source coll is exhausted, then first returns to first one. This would be the opposite of termination at the first found.
reduced
can exit early from a reduction
Ooh, good idea re: core.logic
. I'll have to try it, definitely cleaner than for ...
@risinglight one thing you can take advantage of is the fact that for
is lazy
So instead of “breaking” from a for
loop, you instead can read each element from the sequence it produces until you get your result
usually if i want to break i’d reach for loop/recur, or as mentioned reduce/reduced
ugh I can’t remove the preview on mobile
github .com/Lokeh/advent-2019/blob/master/day2.org#part-2 (pasting it again so that Slack won’t show the rich preview... which I can’t delete on mobile)
reduced
is also fine but if your data can be reasonably done using for
, then take-while
is usually a better answer than turning to reduce
and reduced
take-while
seems like the wrong thing for what is essentially a find of a single item. some
I guess is good enough, I was just annoyed I had to modify the pred to rerun the found value
https://github.com/KennyMonster/aoc_2019/blob/737ec52c74fea4dc42f856b6b69cb73588e016ba/src/day_2.clj#L66
Would be nice to have the predicate just be a predicate in this particular case
And… we’re off!
it is lazy infinite positive quarter of a xy plane. Sweet, but yeah, ranges are known, so for
is more readable and sufficient here
@alex.lee.jackson aoc is not a good way to learn clojure. Maybe the first puzzle of each day is, but most of the 2nd ones steer you towards the loop recur
pretty consistently, if you don't want to wait for results forever.
thanks for the explaination! 🙂
np. but if reduce fits nicely (whatever that means in the moment) - use it!
For me, depends on how much state I'm juggling. Too much and I'll reify it as a reduce fn.
wow, I tend to loop too much coupled state instead. (in context of aoc. in another context: too much coupled state usually means you have issues somewhere else)
I checked my last years code and never used any loop. I used recur sometimes, once custom type to speed the things up. But never needed to use loop/recur. I suppose that what's crucial is a selection of best matching data structure to the problem and to the Clojure.
(get [] 1)
=> nil
(nth [] 1)
Execution error (IndexOutOfBoundsException)
([] 1)
Execution error (IndexOutOfBoundsException)
Day 3 done. This has escalated.
just a bit
can't even hear CPU fan noises on take-while
:kappa:
I wasn't sure if those values where necessarily bounded. But yeah.
loop recur
can be decomplected into state & reducing function.
I'm curious if you prefer loop recur
over a sequential approach. or is it only desireable on 2nd ones for performance reason?
Done. Whew. Thank goodness part2 was a small increment if you chose the right grid representation.
which one did you chose? I went with a map of sets and changed it to a map of map for the part2 which was a small change
I used a simple list of x,y pairs. Once I had the intersections I could just drop everything after that point and the remaining points were the path length.
That is, for each intersection point search the full path (ordered list of points) for it. All the points before it are the length of the path to get there. The shortest path wins.
it ends up being the same amount of eager code, same early termination, a bunch of state "variables", but reduce is 2 things, 1 of which now has a very hairy fn signature and loads of destructuring
besides, most reduces are implemented via loop recur under the hood, so might as well just skip the middle man (especially in context of average aoc part 2 puzzle)
https://github.com/armstnp/advent-of-code-2019/blob/master/src/advent_of_code_2019/day3.clj http://quil.info/sketches/show/3045c99a9e8afbecc5e229977f6a828c0747e3073eb54b45111cd5e3717aa7db Using line segments instead of points made for easier viz, but harder solving. Heh.
Whoops, left my reminder comment at the top
part2 was actually easier today
Probably because I am storing separate points on the line
:when (not (and (= (first segment-1) [0 0])
(= (first segment-2) [0 0])))]
can be just (disj [0 0])
from all collisions 2 lines belowbesides, how do you know that [0 0] is only first in segment? and that lines do not go through [0 0] ever again
The problem statement explicitly says to ignore it. Otherwise, definitely just an assumption. 🙂
My solution for today's part2 is sloow: "Elapsed time: 7919.040046 msecs" I'm getting flashbacks from last year when my part2 solutions were too inefficient to compute in time 😓
yeah, it says ignore [0 0], but I mean, you assume it appears only on segment start, and no segment ends at [0 0]
so segment [[0 -2] [0 -1] [0 0]]
might leak [0 0] into collisions set
stick transient in there :kappa:
or rather rethink your datastructures
mine takes 75ms with maps
did you go with some lists/vectors?
yes, I went with a vector of all the coordinates for a line, then turned it into a set for running intersection
same here and same perf
finally, day3 done https://github.com/genmeblog/advent-of-code-2019/blob/master/src/advent_of_code_2019/day03.clj
Would you mind sharing your solution? I'm curious how it looks with maps.
I am doing everything on my phone this year, would be much more difficult with other other languages. But works great with clojure and jupyter
Interesting (positive) side effects, I make more granular functions and think more before starting to type.
Hardcore coding 🙂
Holiday time waster 🙂
Let's see how long I can keep it up
Writing anything on the phone (even simple messages) is so inconvenient that I can't even imagine editing the code.
The trick is to type less (so think first) and a good soft keyboard helps.
For sure. The idea to think more before typing is always beneficial
2019 day 3 is similar to 2016 day 1. Just absolute moves instead of relative turns. I wound up putting that code into a aoc.grid
library.
Got the first part done — running 500-700 ms. Traded the leaderboard points for sleep. Will finish part 2 later today..
It might; one of the keys to AoC is figuring out which assumptions you can make safely, sometimes the hard way. Sometimes your solution only works for your input, just because it doesn't challenge that particular assumption. The primary reason I expect there's no [0 0] collision is that it would be a 'trivial solution' to part 1, too easily accidentally guessed for a quick leaderboard time, even if by a fraction of people; that's just not how he operates.
haha, already planning ahead for 2020! 🙂
https://gist.github.com/yenda/fcc8ae88ef5318b966b450bc7ed7802b
Just finished day 3. This one was tedious. Gonna look at other solutions. I modeled my solution based on lines (two points) and intersections (points). Perhaps it may have been easier to build a grid.
https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day3.clj not a masterpiece - don’t see how to improve the clojure or the performance.
NOTE: peek
instead of last
to get last element of a vector led to running twice as fast.
Oh I did not
I will try that 🙂 hehe
Didn’t think about that
Initial: “Elapsed time: 1323.049568 msecs” With clojure.set/intersection “Elapsed time: 861.311297 msecs” 😉
For part 1
Nice solution. But I see you were lucky. Intersections can have negative coordinates and you should sum absolute values rather than filtering negative results (see manhattan distance definition).
Aha so sum absolute values and remove zero?
Thanks 🙂
did you try using clojure.set/intersection
and measure the performance? curious.