I think the "rule" that predicates should return booleans is a bit silly
There nothing wrong with truthiness
I like how Dan Dorman's solution uses a transient that is eventually discarded (no persistent!
needed to derive value from the transient).
https://github.com/dandorman/advent-of-code-2018/blob/master/src/aoc2018/d01.cljc#L18
Amazing how this speeds up the calculation. I had the solution without transient and it took my mac around 10 minutes to get the result. With Dormans one it had no calculation time at all.
oh that input->vec
is also very nicely clever
Oh wow. Nice hack.
wish I had thought of that. I didn’t even think to reach for the reader like the rest of ya’ll; I pieced together a solution using Integer/parseInt
@lilactown same here
i prefer traditional parsing steps. more like real life. I would never ship production code that calls read
on input like that. i also don't like when the language makes some things more easy like that
like when the syntax they pick happens to align with literals in the language you are using. unless you make a language like that a la racket
I think Rich himself strayed from this guideline for at least one predicate in spec
true. It just ate up about 80% of the time of part 1 for me :P
gotta get those leaderboard spots!
Oh, come on, how often do you get to do something like
(eval (read-string (str "(apply + [" input "])")))
😜Shia LaBeouf / Chuck Norris, style programming
🙂 That’s pretty much what I did 😄
here's a solution in grep for one task in 2015 https://github.com/ihabunek/aoc2015-elixir/blob/master/src/day16.sh 🙂
Hah
(eval (read-string
(str "(+ " input ")")))
"This solution does not require programming." Just pure thought.
I didn’t know Integer/parseInt
and js/parseInt
both accept +1
and -1
, else I would have used that instead of read-string
To put things in perspective, when I mentioned this problem to my 15-yo, he first said he would take the absolute value of each, but remember the sign, so you would know whether to add or subtract the absolute value.
that's where i went at first. they just happened to encode the data in a convenient literal
Cool, I was getting a stack overflow on my input size for this.... wondering why.
I decided to try parseInt +5
first, but if it hadn’t worked I was planning on just removing all +
’s before parsing
same^
I forgot to even look for +
in the input, and just proceeded Leroy Jenkins-style.
Yesss
The way most code is written.
:truestory:
omg… the waste!
Unless the hammock calls.
just |
into a single grep
process!
sry — I’m a bash dev by training 😛
I recently bought an iPad so that I could still computer without being near a dev workstation, so that I would spend less time writing code and more time hammocking
that went OK until I figured out how to setup ssh / emacs / tmux 🤪
I probably shouldn't mention http://repl.it then... ;D
😱
My mac is in the shop so I'm working there: https://repl.it/@RalphPrescott/AoC-2018
The difficulty of entering forms into Replete gives you plenty of time to think if you go that route.
haha. I did mess with replete. it’s pretty impressive!
I threw up an issue about being able to save to disk or gist :P I know it’s just a wish-list thing
I'm curious what fraction of the solutions fail to handle the "back to 0" case. (For input [+1 -1], for example)
Mine did until I started adding tests. At that moment I realized why your solution had consed the reductions onto 0 😛 Although passing 0 as init to reductions worked for me.
is the correct answer 1 for that input?
depends if you consider a sequence of 0 elements having a sum of 0, then the sequence of 2 elements would have a sum of 0. or most likely the sequence of [1] an then [1 -1 1] having sums of 1 is what they most likely mean
oh, I’m thinking specifically about part 2
well that's what i'm talking about as well. there are arguments for 0 or 1
ohh I see now, one argument is that the starting frequency of 0 should be considered when looking for the first duplicate
in that case, my solution fails 🙂
>+1, -1 first reaches 0 twice.
but I suppose I can just start with #{0}
instead of #{}
and handle that
it's easy to miss this subtlety. not sure which way to fall but i guess good to be conscious of which one you think is the right answer rather than whatever your reduce expression returns
the AoC test cases seem to indicate the answer should be 0
Which test case?
It's written in the description of the puzzle
I hope I'm not the only one who smashed the stack trying part 2 😞
2 mins gentlemen 😛
sad, rank 757
Day 2 https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_02.cljc
very clever
thats fun 🙂
Ah. The day 1 first duplicate is clever
I didn't think of deleting and checking
This problem will lead to a richer variation of solutions. 🙂
I just realized mine is not funny general. I compare them to their neighbors after sorting. But there is no reason the single difference would not move their position in the sorted list
Funny = fully
Although now I can't think of a better approach than your brute force
Day 2 https://gitlab.com/randall.mason/advent-of-code/blob/master/src/advent_of_code_2018/day02.clj Happy about some of it, other parts seem like they could be MUCH better. Perfomance is fine.
You can drop the first two comparisons in your levenshtein since all the strings are either equal or replaced. There are no deletions or additions to worry about
Ah ok you use simple cost only :)
https://github.com/dpsutton/advent/blob/master/2018/src/advent/02.clj
Day 2 part 1 took me 2 hours to do ooof.. Can't come up with a solution for part 2, too tired >.<
Woof, I solved day2 part2 but mfikes has already contributed his data to advent-of-cljc. How do I submit a patch instead of a PR to Github? 🤪
Day2: https://github.com/orestis/advent-of-cljc/blob/master/src/aoc/y2018/d02/orestis.cljc — I need to finally figure out how to get a CLJS REPL setup so I can see why the CLJS tests are failing. Most likely something to do with chars/ints etc.
So in part2, instead of considering one string against all others, repeating, you are dropping the first character, search for duplicate, second character, search for duplicates etc? Neat!
I'm interested to see different approaches that are sound. Mine was probabilistic
here's mine: https://github.com/Heliosmaster/advent-of-code-2018/blob/master/src/adventofcode_2018/day2.clj but i liked @mfikes answer a bit more 😉 there are some functions (like keep
) that I have used rarely so I tend to forget about them 😄
@orestis about failing CLJS-tests: if you change the deftest
to clojure.test/deftest
you will see the error. I’m not sure why it’s not showing right now. I wrapped the deftest body in time to see the performance. PR welcome that fixes this
In the end cider can happily jack in to a CLJS REPL for me so I fixed my code interactively.
@borkdude I've invited a few more people as collaborators to help with merging pr's
@thegeez thanks
My solution to Day 2: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle02.clj#L60
4 solutions in advent-of-cljc so far: https://github.com/borkdude/advent-of-cljc/tree/master/src/aoc/y2018/d02
This time I spent most of my time on setting up rebel-readline, and on writing a lazy pairs
function
I didn’t try to write clever code, just did the most straightforward thing to get to the solution fast, because I had a coffee meeting coming up
No excuses!! 🙂
haha 🙂
is there a cutoff time when you need to submit solutions? https://clojurians.slack.com/archives/C0GLTDB2T/p1543726681192500
No, not at all. You could do these next year.
https://github.com/kfirmanty/advent-of-code-2018/blob/master/src/advent_of_code_2018/day2.clj my solution is also rather not optimized, but it might be fun to look back after few days and try to create most performant solution (but probably with lesser readibility)
I especially have a feeling that there is a simpler way to do: (defn without-diff [id1 id2] (apply str (map #(when (= %1 %2) %1) id1 id2))) so I will check other solutions 😉
Anyone hooked in something like https://github.com/gobanos/cargo-aoc I got jmh setup for Java now, would be nice to compare results. I don't know if I have the time, but otherwise I might setup a project, comparing several solutions.
@pesterhazy the countdown was for the new puzzle release 🙂
@gklijs are you aware of https://github.com/borkdude/advent-of-cljc or is that a different thing?
I know it's there and like to look at the solutions, but don't know if there is some performance measure there?
if you go to the CircleCI icon, open a build and then look at the tests, you will see something like that
ok
not anything fancy, just time
, not criterion
found them
but it would be trivial to hook that up. I’m only concerned about the time to build
You don't want it in your build, it takes really long. I now have a separate profile to run them, just putting the result back with the method and then remove the annotation in java, so I can easily run the other ones.
you could make a branch, replace the time call with criterium quickbench, push the branch and watch the build. if we don’t merge it to master, it should be fine.
Very clever solution from @mfikes. It ismy first advent-of-code. Do the solutions often build on previous days's solutions? Do we build up code for 23 days to make writing the solution on the 24 a bit easier?
Can of related to that I often struggle with how generic a solution should be, for my java colleagues I also see them putting some effort in nicely handling edge cases.
Default settings, at least in java take about 15 minutes for each method.
If I remember correctly in 2017 there was once a day to built upon solution of previous day but I think it was a exception to the rule
the @mfikes solution is also very fast compared to the others
Testing aoc.y2018.d02.borkdude
part-2 took 54.986879 msecs
part-1 took 0.38845 msecs
Testing aoc.y2018.d02.dfuenzalida
part-2 took 126.335371 msecs
part-1 took 5.086755 msecs
Testing aoc.y2018.d02.mfikes
part-2 took 4.250777 msecs
part-1 took 7.145989 msecs
Testing aoc.y2018.d02.mrmcc3
part-2 took 82.483809 msecs
part-1 took 4.544113 msecs
Testing aoc.y2018.d02.orestis
part-2 took 103.404907 msecs
part-1 took 8.286482 msecs
Hmm. I didn’t write it with speed in mind.
I actually wonder if day 2 had day 1 in mind… in this case there was the concept of “sameness / duplication” in both problems.
no, I was also surprised, gonna use it in my javaRx now, and compare to me previous solution.
On the surface, when count
is applied to filter
vs. keep
, you essentially get the same result for this problem.
So you might wonder why I was using keep
... it was because the intermediate output in the REPL looked a little simpler, that's all.
ok, thanks.
Turned out to be slightly faster than the previous solution, 3.445 msecs on a warmed up vm
day 2 was fun. I feel like there’ll be more variety in the solutions, here’s mine https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/2.clj
just finished
https://github.com/bhauman/advent-of-clojure/blob/master/src/advent-2018/day02.clj
now to look at the other answers 🙂
So it seems brute Force is the only strategy?
for the most part one way or the other you are going to have to compare until you find
one interesting thing is that sorting the list may increase the likelyhood that the search ends sooner
as you normally generate combinations from the original order
actually this is not true for my data it increased the number of cycles quite a bit
actually a tree search would probably provide the best performance
as you are eliminating prior comparisons
It is possible to parallelize the search. For the algorithm I'm using, the problem is essentially linear in the input, but with it doing a linear search over each character position, one at a time. The answer happens to be at position 20 for my input data.
Those searches per character position can be done in parallel. The problem size isn't really big enough to benefit greatly from this, but it can cut it down from 3 ms to 1.5 ms.
https://gist.github.com/mfikes/d2cf0c9de3808564f7b039f10635ede4#file-parallel-clj-L34-L44
my tree solution is 7ms
compared to lazy search of 99ms
the tree search intelligently eliminates large swaths of search area
https://github.com/bhauman/advent-of-clojure/blob/master/src/advent-2018/day02.clj#L50-L63
@mfikes ^
Is that with warm up? Rust is doing around 0.25 ms for each of day two
lol
of course it is
With RxJava it's about 3/6 ms, measured with jmh. I'm still kind of figuring out what I like best/want to get better in.
Very cool. Gonna need to study this for a while :face_with_monocle:
Hi all! I love this time of year! My solutions aim for leaderboard points rather than elegance and best practices. It’s great to see all the unique ways other clojurians come up with!
My day2-one has more lines than day2-two https://github.com/vijaykiran/aoc-2018/blob/master/src/aoc_2018/two.clj#L279 🙂
@bhauman i was reading your tree search and it prunes a bit too heavily (search ["abc" "ddd" "zbc" "ahg" "zzz"])
should match abc/zbc => "bc" but it fails to find them
Are these from CI ?
part-1 "Elapsed time: 5.87954 msecs"
part-2 "Elapsed time: 0.829347 msecs"
These are mine from (time …)
< it is super-ugly-code though@dpsutton oh cool thanks, I think thats a base case lemme check it out
oh I broke it when I refactored
> TFW you accidentally leave that println inside the inner loop of your solution and you run it on your real input 🤦
at least in CIDER/Emacs outputting that much text to a buffer wrecks me
Tempted to ask this on another channel - but it's also some hints on the first few problems. Are there any more idiomatic approaches to these short helpers?
@dpsutton nope its just wrong 🙂
Mine too :)
a sort and compare with neighbor works on the input but is not right in general. (i realized after doing that)
I found the problem but of course it slows it down 🙂
yes you have to be more cautious of when you can prune things
is it instead of apply intersection you look for duplicates?
The list is from CI, the 3,445 is from jmh benching.
right now I’m intersecting two by two
i was mulling that idea just now
which is searching for duplicates
look for things with the first two characters have non-empty intersection
oof, ya’ll are making me feel bad. my day2 part2 solution is ~600ms 😆
okay! I only ran (time ..)
I’m thinking that its better to do this as a tree as well
As long as it works 🙂 We are not in a hurry
@lilactown but the "fast" versions we are talking about are unsound 🙂 slow and steady
still, going fast is fun!
Hey - my version is fast and it is very sound (as in very noisy) 😄
I have something similar in Java now, and the rust create also has it, will be adding some CI config to get some numbers there
For the second one, I was even considering not writing code and Cmd+F and eye-ball the similar strings
@bhauman - i'm missing something. I don't see how you can do this other than pairwise. What would you use as the comparison in your tree?
I can't think of anything that (properly) constrains the solution space.
hold on committing
@rmprescott https://github.com/bhauman/advent-of-clojure/blob/master/src/advent-2018/day02.clj#L50-L63
in this solution I’m doing a depth first search
so it should eliminate comparisons
its takes a third of the amount of time as my straight forward solution
now breadth first search would really be interesting
as well
@dpsutton mines updated
and updated again with comments
IIRC, we will probably see a few perf-critical ones in a couple weeks (where your algorithm is important if you want it to complete in a few minutes)
Or within the RAM you have 🙂
answer: just throw a naive solution at a cluster and come back the next day 😛
slow and steady!
surely @mfikes's solution must be the fastest no?
Oddly, mine wasn't at all meant to be fast. It got lucky.
was there a problem like that last year? it does say this in the about page: >every problem has a solution that completes in at most 15 seconds on ten-year-old hardware.
although my first attempt at day 1 part 2 would have taken at least 15 minutes to finish :rolling_on_the_floor_laughing:
my super-inefficient solution completes in 47ms
There was that one with the particle simulation that was a real PITA, where you had to almost eyball the solution.
Day 20 last year.
ooo. this is my first year so looking forward to any problems that places me in a rut
IIRC, one pattern is where part 1 can be done with a naive algorithm, and then Wastl asks you to do it for a problem with a billion iterations in part 2.
yep^
It's my first year as well. What will Day 3 bring? More duplicate detection? 🙂
That was hard https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2017/20.clj
@vijaykiran try [“abc” “ddd” “zbc” “ahg” “zzz”]
your solution fails for me on that
wow part 2 was pretty cumbersome my solution was kinda hacky but it got the job done 😛 https://github.com/HeyItsMario/AdventOfCode2018/tree/master/day2
let’s see. last year’s day 1 was pretty similar (summing things). day 2 was doing some integer math (finding min/max, divisors)
yeah. and then you start trying to code generically for part 1 and then you don't get to reuse any for part 2 sometimes
there were a few times last year where if you solved part 1 a certain way, part 2 fell out of it quite nicely
but most of the time I spent trying to make part 1 “generic” without knowing part 2 was a waste, yes
Day 16 was of last year was an example of naive part 1 could in theory solve part 2, but it involved a dance of some sort that went out a billion iterations
@gklijs I’d love to see your Rust/RxJava example
sorted stuff breaks it - I made some assumptions after sorting my puzzle input
did you do any optimizations or is it basically brute force?
I can’t get my brute force below ~130ms or so
I did do the mfikes trick, but that didn't do much to performance, did lose half the needed code. In Rust I'm really inexperienced, so need to google for a lot of stuff,and just happy when it runs. But I figure especially the second one really does well, since it's just moving pointers around. Code at https://github.com/gklijs/advent_of_code_2018 'Gerard' is RxJava, 'Rust/oac_2018' is rust, the other folder are Java from colleagues.
It could also be your problem is harder, that's the nice thing about https://github.com/borkdude/advent-of-cljc they all use the same data
ah, didn’t even consider that
I mean… also just hardware
It's the first year for me, and also for the company, maybe next year I set something up with GraalVM
the mfikes trick (w/ transducers) gets me down to ~2ms
actually… holy hara
for early puzzles I just write really long oneliners in a repl, they tend to be convoluted and slow 😂
(str (subs s 0 i)
(subs s (inc i)))
^is WAY faster than
(.toString (.deleteCharAt (StringBuilder. s) i))
down to .5ms
Reflection?
I hinted the constructor
in my timing
@nooga I'm the same way, whatever I can possibly squeeze into a one-liner in the repl
@mfikes that was it
only roadblock: rebel-readline, as great as it is, doesn't submit when I hit Return while the cursor is not at the end of the line
(fn [^String s]
(.toString (.deleteCharAt (StringBuilder. s)
^Long i))
is comparableSo, transducers got it down to half a millisecond. Nice.
Rust speed within reach. 🙂
https://clojurians.slack.com/archives/C0GLTDB2T/p1543772430255300
@pesterhazy ctrl-x ctrl-m
Hah! Every time that happens on Apropos, we shout out Bruuuucee!
Now we know they way 🙂
Bad news…
My .5ms was bugged
2.1ms
Damn. 👿
ikr
ah, spent way too much time on part two of day two.
IMHO, day 2 part 2 was a bit harder than you would expect, so early on
@bhauman wow, thanks
I was over complicating things a bit.
I’m probably not so concerned with speed 🙂
Don’t want to spoil anything 🙂
@bhauman is there any way to bind the Enter key to clojure-force-accept-line rather than accept-line?
I tried
cat ~/.clojure/rebel_readline.edn
{:key-bindings { :emacs [["RETURN" :clojure-force-accept-line]] }}
I can bind ^J
, which is nice, but a real Enter/Return would be better
^J or ^m I think
wait! this works
{:key-bindings { :emacs [["^M" :clojure-force-accept-line]] }}
yes control M is a real return
it's always just after bothering someone that you find the answer yourself
so the thing is that you don’t get multiline that way
yeah maybe I can bind that to ^j
honestly I don't often write multiple lines except by mistake
yeah, ^j is bound to accept-line by default - that works well for me
now it's perfect 🎉
Day 2 for Advent of CLJC:
Testing aoc.y2018.d02.borkdude
part-2 took 47.616232 msecs
part-1 took 0.408357 msecs
Testing aoc.y2018.d02.dfuenzalida
part-2 took 118.803809 msecs
part-1 took 5.012151 msecs
Testing aoc.y2018.d02.iamdrowsy
part-2 took 362.461886 msecs
part-1 took 4.806461 msecs
Testing aoc.y2018.d02.mfikes
part-2 took 4.994811 msecs
part-1 took 7.194342 msecs
Testing aoc.y2018.d02.mrmcc3
part-2 took 92.999763 msecs
part-1 took 5.206182 msecs
Testing aoc.y2018.d02.orestis
part-2 took 98.666185 msecs
part-1 took 8.78663 msecs
https://circleci.com/gh/borkdude/advent-of-cljc/91Good job everyone and thanks for contributing.
mfikes really nailed it. when I saw his function that deleted one char from a string I was like: oh yeah, of course… 🙂
very humbling seeing y'alls such succinct solutions
(criterium/quick-bench
(into []
(comp (keep (fn [i]
(first (into []
(comp (map (fn [^String s]
(.toString (.deleteCharAt (StringBuilder. s)
^Long i))))
(dups)
(take 1))
in))))
(take 1))
(range (count (first in)))))
Evaluation count : 828 in 6 samples of 138 calls.
Execution time mean : 702.838769 µs
Execution time std-deviation : 19.556882 µs
Execution time lower quantile : 668.965703 µs ( 2.5%)
Execution time upper quantile : 718.893138 µs (97.5%)
Overhead used : 1.830592 ns
where dups
is a transducer that emits duplicates
I wish I understood the reasoning behind @mfikes solution to todays second problem.
Maybe I could draw a picture of it
I visualize it as first eliminating a column of characters and then seeing if that causes a duplicate to appear in the remaining strings
abc
axc
def
Eliminate the middle column in that exampleac
then appears twice
Quite cheeky to use yesterdays solution though 🙂
he factored out a function that he could re-use: https://github.com/borkdude/advent-of-cljc/commit/17c8f768c75fbb69187eb4ecf892d17612172cdd it could have ended up in some utils namespace as well
I'm trying to recreate my solutions in Elixir as a sort of lift-and-shift approach. A lot of common utility between Clojure and Elixir, though the latter is certainly far more verbose and doesn't have quite the same expressiveness for its core lib. Still not bad.
divide and conquer -- nice!
wow, did not think i'd wind up using reductions on problem 1 😄
one of my favorite functions that i keep in my back pocket
Reductions and iterate always feel so fancy and sophisticated to me ha
wow, that's actually kind of interesting
i feel like early on when i was using clojure i used iterate
a lot
but i don't use it very often these days
like when you mentioned it, i was like "oh right, that exists"
I don't use it very often in our webapp or backend stuff but I like to model solutions to "clever" problems with it
i guess i used it pretty often in 4clojure problems when golfing
and in project euler solutions
which is why i remember it being a "back in the day" kind of thing
That makes sense. It doesn't seem to align with real world things I have to do so it really feels insightful when it works
btw, reductions is "fancy", but i remember using it for a problem where i had a sequence of lines of chat, similar to the way they're presented in slack, so you'd see a nickname, and then you wouldn't see it on any lines they typed immediately after, but i wanted it filled in everywhere