a little more than 4 hours…
Yak-shaved today's. (Spoiler alert, obv) Initial solution https://github.com/armstnp/advent-of-code-2017/blob/f013cff13592e2cbffff0cd6fa9aee8662d1cb1c/day-9.clj Refactored solution https://github.com/armstnp/advent-of-code-2017/blob/ff41b881cf016148e927ff01ac44ed65ec445a08/day-9.clj
Once I get a good night's sleep I'm interested in digging into your use of iterate.
Mine's pretty straightforward. Here's the guts. https://github.com/grzm/advent-of-cljc/blob/master/src/main/com/grzm/advent_of_code/advent_2017/day_09/core.cljc
Clojure really does make this kind of stuff concise.
My day 9 is up. Fairly straightforward.
I do love my iterate, but now that you say something reduce is probably more appropriate.
Eh, never mind. Might have worked if I'd kept the stream separate from the accumulated state, but part of the problem is that one of the 'instructions' modifies the stream itself, which makes function outputs weirder.
https://github.com/borkdude/aoc2017/blob/master/src/day9.clj
Hmm. Not sure if you're just lucky or not, but !
only ignores the next character while inside a garbage block, according to the problem statement
Day 9 solved! yeeeeeeeee
@fellshard I read the problem statement as the futile ! were only inserted inside garbage, so I could just strip it away, as I don’t expect ! outside < >
I'm seeing them outside in my input, at least
Searching for >!
will show cases where the !
must be outside garbage, in fact
@fellshard ok, if you have a link to your input + your expected answers I can give it a ty
https://github.com/armstnp/advent-of-code-2017/blob/master/day-9.clj Score: 17390 Garbage: 7825
>!
doesn’t necessarily mean you’re outside garbage
True
Wait, yes it does. >
will exit a garbage block if you're in one, or have no effect if you're not.
Same answer for score, different for garbage. Guess I got lucky by input.
Maybe I’ll fix later today. Thanks.
Lucky! But hey, turned out nice and tidy. 🙂
https://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day09.clj
take out the trash
Hey, are you sure your garbage output is 7825? just asking
@fellshard my program works for my input + the examples
but I get a different number
@bhauman @fellshard pointed out my program was incorrect for his input. I tried yours and get same numbers as you now (not pushed yet). Could you try his input? I get a different number for the garbage. https://github.com/armstnp/advent-of-code-2017/blob/master/day-9.clj Score: 17390 Garbage: 7825
Very nice PureScript solution: https://github.com/krisajenkins/AdventOfCode/blob/master/src/Year2017/Day9.purs
I wonder if anyone used InstaParse for this one
I’m going to try spec
I went with straightforward automaton to count and filter garbage “in parallel”
@borkdude I tried his input and got the correct results
@nooga mine is similar but I reduced the states of the automaton by handling the score separately
and looking at yours I'm wondering why i didn't just use a vector for state
@bhauman nice, reading it right now
@bhauman no reason, I just typed this in one go 😄
I could use a vector and change loop to reduce or something
oh, sorry, misread that
no worries, easy to do
@borkdude string/replace takes a function arg that should do it
coming up with a much shorter solution now
My day 9: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_09.cljc
so I'm thinking I can clean the garbage up with string/replace now that I know it takes a fn arg
including counting it I'm pretty sure
@grzm I think you can convert (condp = c \a (foo) \b (bar) :else (baz))
to (case c \a (foo) \b (bar) (baz))
and in addition to the simplification, you get a perf improvement with constant-time dispatch.
nice @mfikes
I did basically the same but in even more condensed form
@borkdude Hah, your solution is practically isomorphic to mine. 🙂
Nice @nooga. I tried yours on my input, and as you'd expect your version runs more quickly (it shaves off 25–50% or so)
nice
so not only is it short, it’s also fast ;d
OK much more concise and simple
https://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day09.clj
and fast
Why is this so sloooooow?
(s/def ::garbage (s/cat :lab #{lab}
:content (s/* char?)
:rab #{rab}))
(s/def ::group (s/cat :lcb #{lcb}
:children
(s/* (s/cat :child (s/alt :group ::group
:garbage ::garbage)
:comma (s/? #{\,})))
:rcb #{rcb}))
(s/conform ::group (seq "{{},{<x>}}"))
(defn parse-string [s]
(s/conform ::group (seq s)))
(comment
(def p (parse-string (data))))
Heap space exceptionare you generating test input?
nope, just conforming
@mfikes nice. I'll give that a shot. It's working at sub 10ms already.
it can't find a match so its continuing to search?
@grzm Yeah, for this problem, case
is only better than condp =
for readability IMHO
I noticed case doesn’t work when you’re aliasing stuff…
@mfikes Oh cool (isomorphic), but mine is incorrect for one out of three inputs I tried
I was also thinking of rewriting it to dispatch on both args to move all dispatch logic into the multimethod.
@mfikes I noticed yours failed too for @fellshard’s input (returns 8373 for garbage count instead of 7825)
😵
lol
So, some part of the problem definition seemed underspecified to me, and I ended up assuming.
@borkdude mine now uses regexes like yours did and it works for @fellshard's input
@bhauman wow, I didn’t know str/replace took a function!
I sent you a message above stating just that!! 🙂
@bhauman > string/replace takes a function arg that should do it it being?
yeah 🙂
I meant: what do you mean with "it"?
I get it now, but I didn’t understand that message in the context of the thread 🙂
yeah not clear at all
@bhauman you’re replacing the exclamation marks regardless of whether they occur out or inside the question marks… but it seems they don’t ever occur outside
so I guess that’s fine
yes we have to assume there isn't stray chars
if I had a better up front understanding of the structure, e.g. {aaaxx!xxx{<x>}} doesn’t occur, I would have written a better solution… but to eager too find the answer 🙂
thats the cool thing about str/replace taking a function, is you can call str/replace again inside that fn
Wait, that's exactly the part that I thought was underspecified in the problem definition @borkdude
@bhauman that’s so good to know — thanks!
> In a futile attempt to clean up the garbage, some program has canceled some of the characters within it using !: inside garbage, any character that comes after ! should be ignored, including <, >, and even another !.
so one way of reading that, is that ! only occurs inside garbage
yeah you could also deduce it from the examples
Using case
dropped part 1 from sub 10ms to sub 7ms
it seems like a fair assumption
Yes, my reading is that !
only has meaning inside garbage.
that’s what our solutions are doing too I believe mfikes
there has to be some edge case only occurring in fellshard’s input
@borkdude Is the problem that {aaa{foo}xxx}
can occur?
@mfikes my code should interpret that too
My code would interpret that as a single group.
Or at least I didn't code for that case.
I get a score of 3 for that one
but it’s not likely that our code should handle it
Yeah, my code does that as well, but I would claim my code is undefined for that kind of input.
That's invalid, per the spec
I shouldn’t affect the outcome though
Depends on your stance on Postel's law 🙂
tl;dr?
Accept bad input? Accept bad AoC problem definitions?
Be liberal in what you accept, conservative in what you emit.
I subscribe to that law
For me, it depends on whether or not I've had breakfast.
For nutrition, I subscribe to the reverse
@mfikes What should the garbage count for this one be?
(solve “{{<!!!>}}“)
I'm leading towards {aaa{foo}xxx}
being a single group, because "things" are separated by commas
@mfikes I ignored commas too, I treat all things like whitespace if it’s not a group / garbage separator
There is no closing of the garbage in your example @borkdude
yes, of course..
the presense of non garbage garbage, doesn't affect the final score or the garbage count
I wonder what’s up with the garbage count in our code mfikes…. — yes, you’re right bhauman, I think we’re doing that
@borkdude i'd suspect its an odd even escape code thing
as thats the only thing that can mess up the count
@borkdude My code and fellshard's code produce the same 8373 for garbage cound
really?
Yeah, perhaps there is no bug
@mfikes on fellshards input?
but he told me he got 7825 and bhauman + Vik got that too: https://twitter.com/pg_xocolatl/status/939517141606457344
both yours and his would probably be the same for your input
For fellshards input my code produces 17390 and 8373 and fellshard's produces {:score 17390, :garbage-count 8373}
that doesn't sound right
at all
@mfikes Is your REPL state fresh?
Just checking 😄
I resarted it. Still getting {:score 17390, :garbage-count 8373}
well i get 7825
with /his/ code?
on fellshards input
Indeed.
@mfikes Did you also upgrade to clojure 1.9.0? maybe it’s a bug 😄
👏
@borkdude I think the problem is this: In fellshard's code his input is defined in the code. I copied your input file in your repo, but the file is a direct copy, and the file has the quotes escaped in it
So, I'm getting the incorrect answer for the file, but the correct one from the literal code
In other words, the problem is here https://github.com/borkdude/aoc2017/blob/master/resources/day9-fellshard.txt at the first escaped quote
makes sense
aaaaaaaaaargh
thanks.
so maybe my solution was correct to being with… let’s test
ok, so my first solution this morning was correct…
Turned out my first solution was correct after all. I just copied the quoted input to a file, which yielded a different answer. DOH.
No. That looks interesting!
its way more fun than I expected
Sorry, not enough time for that right now 🙂
I tried TIS-100
it’s harder than it looks
never finished it, requires lots of free time
@nooga yeah its not easy but I hurt my back the other day so i'm kinda stuck on the couch
and I was watching "Halt and Catch Fire" so I was a bit nostalgia driven
I think my spec is correct now, but it’s still slow: https://github.com/borkdude/aoc2017/blob/master/src/day9_spec.clj#L56
Surprisingly when I replaced the defmulti with one big multi-tiered case statement, it's slower. https://github.com/grzm/advent-of-cljc/blob/899b18e6e72ce2157d63f9b3b7280b1c35a0f106/src/main/com/grzm/advent_of_code/advent_2017/day_09/part_1.cljc
They're all pretty close, though. Within 2 ms.
Maybe I should try instaparse
It's pretty impressive how flexible spec is.
What kind of speeds are you seeing with your spec solution?
yeah, but I think the data it’s generating for this thing becomes too big maybe?
@grzm Nothing yet. I can’t parse the whole input
Halting problem
That makes sense. It's building up some sort of structure to be able to explain failures.
I love how you can just eval your boot file and it will pick up on new deps
@borkdude I think your specs are slow because the :content and :rab branches are not mutually exclusive because char? will also match rab. So it "blabla>yadayadayada" will parse as the whole string into :content first and then will need to backtrack
hmm yeah, how to improve that
replace char? with a more specific predicate, same for :children and :comma
Hi all! I had to solve this in a real hurry today, here is my solution: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day9.clj
Seems like similar to @nooga but with two functions for each state.
@borkdude I've been eyeing your resource-reducible
. I've been focusing on using more tranducers. Is that something you worked out yourself?
@grzm No, I stole it from a blog post, but you can see the idea here: https://stackoverflow.com/questions/47333668/split-lines-in-clojure-while-reading-from-file/47354316#47354316
The link to the full blog post is at the bottom
Ah! That post came up in my search for IReduceInit.
One more piece to have in my back pocket. AoC, or rather, this community in AoC, has been really helpful for me. Thanks, all of you!
And it's only Day 9 🙂
To be honest I didn’t really need it, line-seq or slurp is sufficient
That may very well be the case, but if you didn't have it there, I wouldn't have been exposed to it. So regardless of whether you needed it, it served a purpose.
Ah, I should have used letfn for my mutually recursive functions instead of pre-declaring them.
Instaparse! https://github.com/borkdude/aoc2017/blob/master/src/day9_instaparse.clj
D'oh. Yeah, I should've considered the escaped quotes in my input 😞
I was wondering if someone would make a grammar for this, it's perfectly suited 😄
Instaparse looks really neat, should pick that up for one of these.
Ick. My bad. I should really get a repl on my personal machine so I can use resource files instead, like you do. Easier to wrangle and share.
funny, I’m writing a ghetto parser combinator lib atm
Inlined the grammar now, so you see the entire solution one file. See above link. Really happy with it 🙂
I think you could do the same with spec in hindsight as @thegeez said, more restricted rules/predicates. The nice thing with Instaparse is that you can hide tags and output. Not sure if that’s possible with spec. That would be nice in fact.
Here’s a screenshot of the parsetree: https://twitter.com/borkdude/status/939583561568604160
😮
@grzm for resource-reducible there's also https://github.com/cgrand/xforms/blob/master/src/net/cgrand/xforms/io.clj#L14
yes, I think it’s more or less the same thing (unless I’m missing something)
Howdy all 🙂. So.. day 9. I ended up with a couple of weirds constructs for dropping cancelled chars (and to drop garbage): https://github.com/metamorph/advent-of-code-2017/blob/master/adv2017/src/adv2017/day9.clj#L1 (`make-drop-!-xf`) where I use an atom to keep state in a filter. I'm thinking that there must be a better way of doing that (and still being "lazy"). Any suggestions?
@gnejs There is a possible solution with a single pass using a couple of values in a state with reduce
e.g. https://github.com/borkdude/aoc2017/blob/master/src/day9_single_pass.clj
@mfikes also has one
For reference here is my solution https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_09.cljc
@borkdude that's cool. 🙂 I was trying to split apart the concerns of "cancelling" and "dropping garbage" into separate transducers to avoid one big reducing function with all aspects mixed.
So my question is really - how do you implement a stateful filter (transducer-like) without resorting to using mutable state as I did?
@gnejs I think it is normal to keep state (usually using volatiles instead of atoms). See (source distinct)
@mfikes ah, cool. So it's not really an anti-pattern then :thumbsup:
I honestly don't know too much about it other than "stateful transducers have mutable state in them using volatiles"
Didn't know about volatile!
before. Thanks for the pointer :thumbsup: This seems to be pretty exhaustive explanation: https://stackoverflow.com/questions/31288608/what-is-clojure-volatile/31319731#31319731
Perhaps the reason is that there is no good way to thread a non-mutable state through. Like the step
function inside the non-transducer version of distinct
can do.)
@thegeez yeah, it looks like there's a lot of goodness in xforms