happy advent of code 2018 everyone! 🎉
woke up, made coffee, read the puzzle 1 & wasn't sure if I'm still half asleep or is that really a 1-liner.
heh
Day one is usually just a warmup. I use the time I'd normally take to get the environment warmed up, etc.
I have a standard workspace I use now for these, since there's a lot of common core utils - reading from resources file, parsing integers, defining coarsely-curried functions for interpreters, etc.
Happy puzzling! I did today’s in Replete typing on an iPad keyboard :)
@orestis wow!
Yeah but it’s tiny :)
I don’t think I will do another, though with some love replete could easily be much more useful. Being able to save some files locally or even better to iCloud, some helpful keys above the keyboard. I wonder if it’s open source.
It is! Perhaps I’ll pivot from AoC this year then.
Yeah, I maintain Replete. Custom keyboard stuff is always challenging to pull off while preserving the polished feel, but I definitely agree there could be some keyboard improvement. (You can always use a 3rd party keyboard with it.) The ability to save and edit locally or in iCloud would be nice. We can't do this, as it is not allowed http://blog.fikesfarm.com/posts/2015-08-11-loading-clojurescript-into-your-iphone.html but perhaps content created in Replete could be saved without violating any App Store rules.
I feel like there’s a clever use of lazy seqs in the 2nd part that I’m not seeing
Here is a way to do it using only lazy seqs, but in the end, I didn't like that approach compared to just a direct reduce to find the dup. https://gist.github.com/mfikes/53c53673f66257878ab82408635f297d
Yeah, or using cycle
Given my constraints, I just went with a loop recur for part 2. Not much room for experimenting.
my part 2 was def not 1 line
Yeah, more like 10 in my case. It’s gone now so I can’t count :)
Submitted my solution for day 1 to Advent of CLJC: https://github.com/borkdude/advent-of-cljc
curious about your solutions. if you want you can make a PR and add it to the repo
The fun thing is you can see the timing of every day and user here: https://circleci.com/gh/borkdude/advent-of-cljc/55 when you scroll to the test execution
@borkdude where is the private leaderboard? 🙂
wow part 2 was a doozy!
are we allowed to post solutions here?
@helios I don’t know if there is a leaderboard. You might want to create one? @mario.cordova.862 You could also submit a PR to the above repo as an alternative of posting your solution here 🙂
I wouldn’t post your code here directly, a gist would be more appropriate. Of if you’re going to post it, post it only in a thread, so people don’t see the spoiler.
57048-763fafc9
is the code for the private leaderboard
@helios thanks. might also want to add it to the https://github.com/adventofcode-clojurians/adventofcode-clojurians repo
@borkdude done. also added myself
@borkdude Added myself to the readme
@mario.cordova.862 can you rebase your PR? it has a conflict now
⭐ ⭐
@borkdude done!
There used to be an adventofcode-clojurians leaderboard, but I don’t have the invitation code. Perhaps clojurians slack log might have it?
Created pull request for adventofcode-clojurians. Also slightly offtopic does anyone else has a internal conflict of writing things in a simple way vs smart? I ask because as a developers I feel that we are constantly judged on quality of our code and how "smart" it is but when reading other people code I like things rather simple.
@karol Sometimes there’s a balance between keeping it simple and hacking it for performance
of course, and that is why I like advent of code because usually the first part can be done without optimization and you need to be clever in second part 😉 but I am fan of optimize only when needed and don't introduced layers of abstraction "for future", because I saw few clojure codebases that look like Java EE with parentheses but it is morning here so I might be just complaining 😄
I found the old leaderboard code, updated the topic (cc @helios)
didn’t know the leaderboards could be re-used over multiple years
👍
i have no idea how AoC works, are points based on time as well?
the faster you solve the problem, the higher your score in the leaderboard
gotcha
And its nothing to do with when you start solving! Time starts for everyone when the problem appears.
@denis.fuenzalida @dandorman thanks for contributing to advent of cljc https://github.com/borkdude/advent-of-cljc
I just realized what advent-of-cljc is, I’ll be forking that as well.
Should we add more inputs there?
no, the author of advent of code explicitly forbids it
So we’ll have to do with the input of whoever does the first PR
updated the README to reflect this
Worth to do the runs at least a few times to ensure warm up for the timings etc?
Maybe. I’m not sure how this will work out if multiple users contribute all of their days. If it gets too slow on CI, I might filter the tests only for that user. So running tests multiple times might be something you want to do locally
I guess not too important at this point, the corpus is the important thing. Great initiative!
I’ve submitted my PR. I’ll use this for this years puzzles.
Thanks! Merged.
My repl is timing out on my part 2 solution.. 😅
Would anyone have some time to help me? My process keeps running for part 2 with the puzzle input and just never ends, if I use one of the examples as the input though it does seem to work... (I'll post my code as a thread to this message so spoiler alert!)
(def input (mapv read-string (str/split (slurp "./input") #"\n")))
(defn step [{:keys [frequency-changes current-index frequencies]}]
(let [
new-index (mod (inc current-index) (count frequency-changes))
last-frequency (or (last frequencies) 0)]
{
:current-index new-index
:frequencies (conj frequencies (+ last-frequency (get frequency-changes current-index 0)))
:frequency-changes frequency-changes
}))
(defn last-item-double [l]
(and (> (count l) 1) (> (.indexOf (butlast l) (last l)) -1)))
(defn part2 [frequency-changes] (last (:frequencies (step (last (take-while
(fn [state] (not (last-item-double (:frequencies state))))
(iterate step {
:frequencies []
:frequency-changes frequency-changes
:current-index 0
})))))))
(part2 input)
My solution for day 1. https://github.com/benfle/advent-of-code-2018/blob/master/day-1.clj
Here's mine https://git.sr.ht/%7Eihabunek/aoc2018/tree/master/clojure/src/aoc2018/day01.clj
i'm actually doing it in clojure and elixir in parallel, but pretty sure i won't have the time or willpower to do it all the way through in both languages
@me1740 using state, le gasp 😄
Simplified to use cycle
. I forgot about this function. Thanks. Yes state is debatable here but since it improves readability and reusability I opted for it 🙂
You are using a very inefficient algorithm to check for an already seen item. Using .indexOf etc etc means every time this run means it has to “walk” all the previous steps again and again.
Consider keeping the previously seen frequencies in a set instead.
As an aside, also consider formatting your code a little bit better as it can be really hard to follow 😄
I think this problem is going to be a lot of fun on the stream.
I can think of a bunch of different ways to solve it offhand — none of them will take particularly long.
Who is streaming?
M-F @ 12:00 CST (UTC-6)
👍 nice
How would day 2 be solved if we had memory constraints?
day 2?
we have a cheater! 😛
Sorry Day 1 Part 2
Are people ok with discussing solutions here? What is the assumption about spoilers?
Maybe put the spoiler code in a thread?
I tend to not even read this channel until I'm done with my solution. Otherwise you might see solution strategies being discussed.
For example, you can't help from seeing cycle
being mentioned. 🙂
🙂 yeah I realized that after the fact. Sorry.
To be honest, I enjoy seeing solution strategies being discussed. (Otherwise, where would they be, all in side threads?)
Good idea to stay away.
Also, the ability to look at other people's solutions and other ideas is the main value I get out of this. Much more than solving the problems myself. 🙂
So to answer Mario. I think if you stream in the changes and stream out the frequency in a sorted file you could solve it while just keeping one number in memory. But I didn't bother doing this 🙂
There have been some incredibly clever solutions in the past. 🙂
I tend to solve it first then come on here but I am guessing at later days when it becomes more difficult Ill be coming here for pointers :P
Yeah, there's a problem where you are stuck and want a little help, without seeing the solution. :thinking_face:
Heh. Separate channel? #adventofcode-help ?
:moar_channels:
One thing I see now is that, even though my solution works on my data, I have a defect in it 🙂
My solution https://github.com/bhauman/advent-of-clojure/blob/master/src/advent-2018/day01.clj
My solution gives the wrong answer for this input: [5 10 20 -35]
. I suspect this will be a common mistake.
My first solution was not handling the case when there is no duplicate either 🙂
Thanks for submitting your solution to https://github.com/borkdude/advent-of-cljc @mfikes!
Wastl even gives a simpler example of [+1 -1]
in the page
@mfikes good catch
I only learned about this when I saw another solution catering to that case.
My solution https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_01.cljc
TRY ALL THE EXAMPLES
Indeed
that is the lesson I learn every year
cause I forget
https://gitlab.com/randall.mason/advent-of-code/blob/master/src/advent_of_code_2018/day01.clj
and here’s mine, enjoying seeing the different solutions! https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/1.clj
I do wish somebody would make a data oriented source of the examples. I just want to pull in a mapping of input to output.
@taylor wow! Learned something new with reductions, reduced :thumbsup:
feeling pretty cheeky about (drop-while #(apply not= (swap-vals! seen conj %)))
:man-juggling:
nice! it seems a lot of people reached the same conclusion for part 2, though I shamelessly went with atoms for my first attempt
I also have the same issue with my solution. I wish there was a reduce-until function or something like that.
like reduced
?
I really wanted to find a way to reuse distinct
. Here is one way, but I'm wondering if there is some other clever way to reused the underlying capability in the core lib. https://gist.github.com/mfikes/53c53673f66257878ab82408635f297d
I thought about making a variation of distinct
transducer like while-distinct
or something
Damn, time to refactor!!!
my solution: https://github.com/borkdude/advent-of-cljc/blob/master/src/aoc/y2018/d01/borkdude.cljc
I’m not sure why people are using reductions?
To get a sequence of the frequencies after applying the changes.
yeah I ended up using loop-recur and cycles: https://github.com/Lokeh/advent-2018/blob/master/day1/src/advent/day1.clj#L54
To generate a list of accumulations, instead of manually managing in reduce
Thanks!!!
clever
yeah
less efficient, but breaks part of the computation out
is it less efficient since it is lazy? (I'm asking because I genuinely don't know)
(defn while-distinct []
(fn [rf]
(let [seen (volatile! #{})]
(fn
([] (rf))
([result] (rf result))
([result input]
(if (contains? @seen input)
(reduced (rf result input))
(do (vswap! seen conj input)
(rf result input))))))))
(->> (cycle values)
(reductions +)
(eduction (while-distinct))
(last))
though that name isn’t great because it includes the first non-distinct value :man-shrugging:it generates another data structure (the laziness only helps with efficiency).
It’s honestly not something you should think about all the time. But I like running through various levels of efficiency in my head.
so, using cycle+reductions+reduce -> (seq of cycle) + (seq of reductions) + #{set of reduce}
my thought was that pretty much either way a new data structure needs to be generated at least from the solutions I've seen thus far, so I wasn't sure if using reductions was actually less efficient than managing the computations and what has been seen
in a reduce.
reduce is only (seq of cycle) + #{set of reduce}
hmm.. I think I understand that
but it’s evaluated lazily, so you only do the computational work that you must
right.. gotcha
thanks!
yep!
oh man, the reduced
function!! TIL
yo!
Here's my solution: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle01.clj
I'm curious how much room for difference there is in a simple task like this
It seems like most solutions involve a reduce
or a direct loop
/ recur
to essentially walk the sequence looking for the first dup.
@mfikes I saw your tweet and couldn't resist 🙂
I thought a bit about how to just calculate it analytically, but didn't see anything easy. Did anybody come up with a way?
Excellent. 🙂
Of course I spent 90% of the time setting up the clj
tool with nREPL and the Corfield Comma
@mfikes your idea of using two reductions on top of each other is clever
other than that mine is identical almost to a character
reduce the reductions you mean?
yeah
is that a common FP pattern? I wasn't aware
i did something similar. the data to investigate is the reduction. seems not necessarily FP but just this problem to me
Paulus, does your solution handle the sequence [+1 -1]
? (This is a common defect.)
reduce
is a great abstraction (obviously!) because you can swap in reductions
and get a nice debugging output for free. Plus if the sequence doesn't terminate, you can lazily take n
@mfikes yep
Cool
(first-duplicate (drop 1 (reductions + 0 (cycle values))))
yeah something similar
Why the drop 1? This is probably related to why I disagreed with [+1 -1] => 0 rather than 1. But I still don't see why.
yes it gets rid of the 0 sum for the sequence of length 0. i originally didn't have it
nice
Maybe some
could be used to mechanize the linear scan?
I’ll ping back here after the stream with a link to github if you just want to review results.
Your predicate would be stateful 😞
My solution uses a "composite accumulator", in this case a vector [acc-freq acc-seen]
. I find myself reaching for composite accumulators often for less-than-simple reduces but I wonder if it's a good pattern
that’s^ normal — although there’s often other ways of going about it
i do that all the time. i only get annoyed because it usually requires a step to pluck apart the composite accumulator at the end
The (->> xs (reductions step-1 init-1) (reduce step-2 init-2))
pattern avoids the composite acc
@dpsutton right, although when you know that you're going to end with reduced
, you won't need it
it would be interesting to compare performance as well. reductions
must incur some performance cost
I always feel a little bad using reduced. The short circuit makes me feel like I'm abusing reduce
Yeah, it always makes you feel like you failed, in some way. 🙂
😆
It is like an inclusion an an otherwise perfect diamond.
@pesterhazy I have the same pattern
@borkdude ours are practically identical
I've seen reducing functions defined outside of the reduce call where they include reduced and I have no idea what reduced does if it is not in a reducing context
it just returns a special Java class, clojure.lang.Reduced
@me1740's stateful predicate is interesting: https://github.com/benfle/advent-of-code-2018/blob/master/day-1.clj#L16 - I'm not sure how I feel about that
Right, keep
's docstring is at odds with that approach
Perhaps, close to that idea, but safer, would be to take the source of distinct
and produce an opposite function named duplicates
, and then take the first from that
that’s what I did^ for one of mine
can use as a transducer
Yeah, and a nice little reusable fn falls out of the effort 🙂
yep 🙂
I was hoping to do a big unveil on stream then post back here w/ the code!
Hah. It is still a very nice solution. Especially if the transducer version is fast.
yeah I might benchmark them all for fun as well
good point that
I guess a stateful sequence processing function (like distinct
) is safer than a stateful predicate
not safer
but stateful transducers are more idiomatic
"safer" in the sense that using a stateful predicate for filter
or keep
is violating its contract
right
but you could generate a lazy-seq of dups
whereas the contract of sequences has no such provision
that would be fine
right
so the idea would be a while-distinct
function?
just (duplicates coll)
the same as (distinct coll)
does the name duplicates
make sense though?
@mfikes good catch. not sure why keep needs to be free of side effect though.
we're looking for the opposite of duplicates, r ight?
I think so? “I want all of the duplicates in this seq.” As opposed to, “I want the duplicates removed from this seq.”
oh for the problem
yeah it depends on how you’re going about it!
gotcha, you'd use (->> xs duplicates first)
yep
actually while-distinct
would work only if it was inclusive of the dupe (which makes little sense)
yeah I had the same thought earlier, duplicates
makes more sense https://clojurians.slack.com/archives/C0GLTDB2T/p1543684422093600?thread_ts=1543683763.088200&cid=C0GLTDB2T
@me1740 Trying to come up with an example:
cljs.user=> (def x (eduction (keep (duplicate?)) [1 2 3 2 4 2 3]))
#'cljs.user/x
cljs.user=> (into [] x)
[2 2 3]
cljs.user=> (into [] x)
[1 2 3 2 4 2 3]
Oh ok I see, thanks. Also explain why you should initialize your state inside a transducer function.
So I had to rewrite that as a transducer with the state inside it:
(defn duplicates
[]
(fn [xf]
(let [seen (volatile! #{})]
(fn
([] (xf))
([result] (xf result))
([result input]
(if (contains? @seen input)
(xf result input)
(do
(vswap! seen conj input)
result)))))))
haha I’m playing w/Quil to visualize the solution as it’s calculated, but then I just figured out it’ll take ~40 minutes to finish @ 60fps
It’s cool to see to which degree thought processes converge
thanks for the feedback! I got it to work way faster with a different approach, using loop/recur and a set as you suggested
though my initial solution did end after 1h40 or so 🙈
regarding code formatting, is there a general coding guideline for clojure and a linter like there is for python?
having both reductions
and duplicates
transducers would be interesting, I wonder if I would remember to use the duplicates one
cgrand has it in xforms
oh ho ho
reductions
that is
I don’t think duplicates is there
There is the clojure style guidelines by Bbatsov, and a few linters. There’s a big discussion right now going on in ClojureVerse about this so you can find more info there (sorry, on mobile so can’t paste links easily)
I'll have a look at them, thanks for your help!
xforms
is also available in advent-of-cljc, just sayin’ 🙂
@borkdude I just updated the invite code for the leaderboard, I deleted the ones I created this afternoon
who owns this advent-of-clojurians repo, I think @thegeez? can you add more people with PR merge rights? It seems I’m the only one doing that right now
Probably not the ideal use, but I used NextJournal to do the day 1 challenges. Link if anyone wants to remix it with other styles: https://nextjournal.com/akmiller/advent-of-code-2018--day-1
I decided to do the first day in both CLJ and Rust. https://github.com/Lokeh/advent-2018/tree/master/day1
we’ll see how far I get before succumbing to my lack of Rust knowledge (and frustrations with the type system) and just do the rest in CLJ :P
I think I might update my CLJ solution with a duplicates
xf - wanted to in the moment but it was very late for me last night
I like how you name the predicate seen?
, even though it is implemented using a set. Nice.
It is a predicate that doesn't return a Boolean value, but maybe that's OK.
Yeah I thought it felt nice. I often do that when using sets as predicates