adventofcode

Happy Advent 2020! Please put answers in the pinned threads or create one if it does not exist yet. | https://github.com/adventofcode-clojurians/adventofcode-clojurians | Join the private leaderboard with code 217019-4a55b8eb
grzm 2017-12-09T00:50:00.000151Z

a little more than 4 hours…

grzm 2017-12-09T08:01:54.000015Z

Once I get a good night's sleep I'm interested in digging into your use of iterate.

grzm 2017-12-09T08:02:40.000057Z

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

grzm 2017-12-09T08:05:10.000031Z

Clojure really does make this kind of stuff concise.

borkdude 2017-12-09T08:20:52.000030Z

My day 9 is up. Fairly straightforward.

fellshard 2017-12-09T08:28:05.000042Z

I do love my iterate, but now that you say something reduce is probably more appropriate.

fellshard 2017-12-09T08:30:36.000057Z

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.

fellshard 2017-12-09T08:34:40.000050Z

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

jmb 2017-12-09T08:36:27.000031Z

Day 9 solved! yeeeeeeeee

borkdude 2017-12-09T08:37:53.000010Z

@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 < >

fellshard 2017-12-09T08:39:44.000014Z

I'm seeing them outside in my input, at least

fellshard 2017-12-09T08:40:29.000012Z

Searching for >! will show cases where the ! must be outside garbage, in fact

borkdude 2017-12-09T08:40:29.000096Z

@fellshard ok, if you have a link to your input + your expected answers I can give it a ty

fellshard 2017-12-09T08:41:15.000037Z

https://github.com/armstnp/advent-of-code-2017/blob/master/day-9.clj Score: 17390 Garbage: 7825

borkdude 2017-12-09T08:41:21.000054Z

>! doesn’t necessarily mean you’re outside garbage

fellshard 2017-12-09T08:41:28.000022Z

True

fellshard 2017-12-09T08:42:16.000003Z

Wait, yes it does. > will exit a garbage block if you're in one, or have no effect if you're not.

borkdude 2017-12-09T08:43:26.000031Z

Same answer for score, different for garbage. Guess I got lucky by input.

borkdude 2017-12-09T08:43:45.000054Z

Maybe I’ll fix later today. Thanks.

fellshard 2017-12-09T08:44:24.000008Z

Lucky! But hey, turned out nice and tidy. 🙂

bhauman 2017-12-09T11:21:22.000043Z

take out the trash

borkdude 2017-12-09T13:13:18.000042Z

Hey, are you sure your garbage output is 7825? just asking

borkdude 2017-12-09T13:16:25.000009Z

@fellshard my program works for my input + the examples

borkdude 2017-12-09T13:16:31.000041Z

but I get a different number

borkdude 2017-12-09T13:20:32.000013Z

@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

borkdude 2017-12-09T13:35:01.000079Z

Very nice PureScript solution: https://github.com/krisajenkins/AdventOfCode/blob/master/src/Year2017/Day9.purs

borkdude 2017-12-09T13:35:09.000091Z

I wonder if anyone used InstaParse for this one

borkdude 2017-12-09T14:10:43.000038Z

I’m going to try spec

2017-12-09T14:12:14.000063Z

I went with straightforward automaton to count and filter garbage “in parallel”

bhauman 2017-12-09T14:20:34.000104Z

@borkdude I tried his input and got the correct results

bhauman 2017-12-09T14:23:33.000060Z

@nooga mine is similar but I reduced the states of the automaton by handling the score separately

bhauman 2017-12-09T14:25:06.000079Z

and looking at yours I'm wondering why i didn't just use a vector for state

2017-12-09T14:25:08.000040Z

@bhauman nice, reading it right now

2017-12-09T14:25:42.000064Z

@bhauman no reason, I just typed this in one go 😄

2017-12-09T14:26:17.000017Z

I could use a vector and change loop to reduce or something

2017-12-09T14:26:38.000074Z

oh, sorry, misread that

bhauman 2017-12-09T14:26:46.000038Z

no worries, easy to do

bhauman 2017-12-09T14:36:21.000077Z

@borkdude string/replace takes a function arg that should do it

bhauman 2017-12-09T14:37:01.000024Z

coming up with a much shorter solution now

bhauman 2017-12-09T14:46:52.000044Z

so I'm thinking I can clean the garbage up with string/replace now that I know it takes a fn arg

bhauman 2017-12-09T14:47:21.000043Z

including counting it I'm pretty sure

mfikes 2017-12-09T14:48:15.000010Z

@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.

2017-12-09T14:51:57.000044Z

nice @mfikes

2017-12-09T14:53:17.000018Z

I did basically the same but in even more condensed form

mfikes 2017-12-09T14:54:46.000039Z

@borkdude Hah, your solution is practically isomorphic to mine. 🙂

mfikes 2017-12-09T14:59:30.000003Z

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)

2017-12-09T15:04:12.000121Z

nice

2017-12-09T15:04:34.000096Z

so not only is it short, it’s also fast ;d

bhauman 2017-12-09T15:20:02.000038Z

OK much more concise and simple

bhauman 2017-12-09T15:20:20.000119Z

and fast

borkdude 2017-12-09T15:20:32.000121Z

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 exception

bhauman 2017-12-09T15:21:13.000037Z

are you generating test input?

borkdude 2017-12-09T15:21:18.000061Z

nope, just conforming

grzm 2017-12-09T15:21:39.000048Z

@mfikes nice. I'll give that a shot. It's working at sub 10ms already.

bhauman 2017-12-09T15:21:40.000074Z

it can't find a match so its continuing to search?

mfikes 2017-12-09T15:22:25.000056Z

@grzm Yeah, for this problem, case is only better than condp = for readability IMHO

borkdude 2017-12-09T15:22:58.000032Z

I noticed case doesn’t work when you’re aliasing stuff…

borkdude 2017-12-09T15:23:33.000026Z

@mfikes Oh cool (isomorphic), but mine is incorrect for one out of three inputs I tried

grzm 2017-12-09T15:25:10.000085Z

I was also thinking of rewriting it to dispatch on both args to move all dispatch logic into the multimethod.

borkdude 2017-12-09T15:26:42.000034Z

@mfikes I noticed yours failed too for @fellshard’s input (returns 8373 for garbage count instead of 7825)

mfikes 2017-12-09T15:27:08.000012Z

😵

bhauman 2017-12-09T15:27:15.000067Z

lol

mfikes 2017-12-09T15:27:37.000084Z

So, some part of the problem definition seemed underspecified to me, and I ended up assuming.

bhauman 2017-12-09T15:29:28.000006Z

@borkdude mine now uses regexes like yours did and it works for @fellshard's input

borkdude 2017-12-09T15:32:31.000045Z

@bhauman wow, I didn’t know str/replace took a function!

bhauman 2017-12-09T15:32:49.000070Z

I sent you a message above stating just that!! 🙂

borkdude 2017-12-09T15:33:57.000134Z

@bhauman > string/replace takes a function arg that should do it it being?

bhauman 2017-12-09T15:34:10.000037Z

yeah 🙂

borkdude 2017-12-09T15:34:43.000076Z

I meant: what do you mean with "it"?

borkdude 2017-12-09T15:35:10.000019Z

I get it now, but I didn’t understand that message in the context of the thread 🙂

bhauman 2017-12-09T15:35:28.000001Z

yeah not clear at all

borkdude 2017-12-09T15:36:24.000083Z

@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

borkdude 2017-12-09T15:37:04.000063Z

so I guess that’s fine

bhauman 2017-12-09T15:37:44.000042Z

yes we have to assume there isn't stray chars

borkdude 2017-12-09T15:38:18.000052Z

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 🙂

bhauman 2017-12-09T15:40:46.000044Z

thats the cool thing about str/replace taking a function, is you can call str/replace again inside that fn

mfikes 2017-12-09T15:41:03.000022Z

Wait, that's exactly the part that I thought was underspecified in the problem definition @borkdude

borkdude 2017-12-09T15:41:22.000134Z

@bhauman that’s so good to know — thanks!

2017-12-09T15:41:42.000086Z

> 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 !.

bhauman 2017-12-09T15:42:44.000090Z

so one way of reading that, is that ! only occurs inside garbage

borkdude 2017-12-09T15:43:18.000061Z

yeah you could also deduce it from the examples

grzm 2017-12-09T15:43:56.000076Z

Using case dropped part 1 from sub 10ms to sub 7ms

bhauman 2017-12-09T15:44:11.000018Z

it seems like a fair assumption

mfikes 2017-12-09T15:44:14.000094Z

Yes, my reading is that ! only has meaning inside garbage.

borkdude 2017-12-09T15:44:28.000125Z

that’s what our solutions are doing too I believe mfikes

borkdude 2017-12-09T15:44:59.000128Z

there has to be some edge case only occurring in fellshard’s input

mfikes 2017-12-09T15:45:10.000015Z

@borkdude Is the problem that {aaa{foo}xxx} can occur?

borkdude 2017-12-09T15:45:30.000041Z

@mfikes my code should interpret that too

mfikes 2017-12-09T15:45:43.000110Z

My code would interpret that as a single group.

mfikes 2017-12-09T15:45:58.000021Z

Or at least I didn't code for that case.

borkdude 2017-12-09T15:46:35.000124Z

I get a score of 3 for that one

borkdude 2017-12-09T15:46:54.000070Z

but it’s not likely that our code should handle it

mfikes 2017-12-09T15:47:01.000050Z

Yeah, my code does that as well, but I would claim my code is undefined for that kind of input.

grzm 2017-12-09T15:47:06.000033Z

That's invalid, per the spec

borkdude 2017-12-09T15:47:25.000118Z

I shouldn’t affect the outcome though

grzm 2017-12-09T15:48:01.000011Z

Depends on your stance on Postel's law 🙂

borkdude 2017-12-09T15:48:09.000060Z

tl;dr?

mfikes 2017-12-09T15:48:23.000088Z

Accept bad input? Accept bad AoC problem definitions?

grzm 2017-12-09T15:48:39.000039Z

Be liberal in what you accept, conservative in what you emit.

borkdude 2017-12-09T15:48:48.000055Z

I subscribe to that law

grzm 2017-12-09T15:49:49.000137Z

For me, it depends on whether or not I've had breakfast.

borkdude 2017-12-09T15:50:13.000002Z

For nutrition, I subscribe to the reverse

borkdude 2017-12-09T15:52:32.000055Z

@mfikes What should the garbage count for this one be?

(solve “{{&lt;!!!&gt;}}“)

mfikes 2017-12-09T15:52:42.000015Z

I'm leading towards {aaa{foo}xxx} being a single group, because "things" are separated by commas

borkdude 2017-12-09T15:53:08.000001Z

@mfikes I ignored commas too, I treat all things like whitespace if it’s not a group / garbage separator

mfikes 2017-12-09T15:53:08.000032Z

There is no closing of the garbage in your example @borkdude

borkdude 2017-12-09T15:53:49.000066Z

yes, of course..

bhauman 2017-12-09T15:55:46.000099Z

the presense of non garbage garbage, doesn't affect the final score or the garbage count

borkdude 2017-12-09T15:56:07.000067Z

I wonder what’s up with the garbage count in our code mfikes…. — yes, you’re right bhauman, I think we’re doing that

bhauman 2017-12-09T15:56:54.000015Z

@borkdude i'd suspect its an odd even escape code thing

bhauman 2017-12-09T15:57:26.000057Z

as thats the only thing that can mess up the count

mfikes 2017-12-09T15:58:02.000055Z

@borkdude My code and fellshard's code produce the same 8373 for garbage cound

borkdude 2017-12-09T15:58:17.000041Z

really?

mfikes 2017-12-09T15:58:23.000015Z

Yeah, perhaps there is no bug

bhauman 2017-12-09T15:58:25.000022Z

@mfikes on fellshards input?

borkdude 2017-12-09T15:58:59.000068Z

but he told me he got 7825 and bhauman + Vik got that too: https://twitter.com/pg_xocolatl/status/939517141606457344

bhauman 2017-12-09T15:59:29.000021Z

both yours and his would probably be the same for your input

mfikes 2017-12-09T15:59:35.000092Z

For fellshards input my code produces 17390 and 8373 and fellshard's produces {:score 17390, :garbage-count 8373}

bhauman 2017-12-09T15:59:51.000054Z

that doesn't sound right

bhauman 2017-12-09T15:59:59.000005Z

at all

borkdude 2017-12-09T16:00:04.000121Z

@mfikes Is your REPL state fresh?

borkdude 2017-12-09T16:00:30.000012Z

Just checking 😄

mfikes 2017-12-09T16:00:45.000126Z

I resarted it. Still getting {:score 17390, :garbage-count 8373}

bhauman 2017-12-09T16:01:11.000134Z

well i get 7825

borkdude 2017-12-09T16:01:14.000011Z

with /his/ code?

bhauman 2017-12-09T16:01:19.000099Z

on fellshards input

mfikes 2017-12-09T16:01:29.000126Z

Indeed.

borkdude 2017-12-09T16:01:51.000024Z

@mfikes Did you also upgrade to clojure 1.9.0? maybe it’s a bug 😄

bhauman 2017-12-09T16:02:02.000066Z

👏

mfikes 2017-12-09T16:04:09.000097Z

@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

mfikes 2017-12-09T16:04:56.000032Z

So, I'm getting the incorrect answer for the file, but the correct one from the literal code

mfikes 2017-12-09T16:05:45.000085Z

In other words, the problem is here https://github.com/borkdude/aoc2017/blob/master/resources/day9-fellshard.txt at the first escaped quote

bhauman 2017-12-09T16:05:57.000052Z

makes sense

borkdude 2017-12-09T16:06:18.000040Z

aaaaaaaaaargh

borkdude 2017-12-09T16:06:24.000097Z

thanks.

borkdude 2017-12-09T16:06:51.000057Z

so maybe my solution was correct to being with… let’s test

borkdude 2017-12-09T16:17:12.000127Z

ok, so my first solution this morning was correct…

1
bhauman 2017-12-09T16:20:03.000014Z

@borkdude @mfikes I mentioned this yesterday but have either of you tried TIS-100?

bhauman 2017-12-09T16:20:04.000014Z

http://www.zachtronics.com/tis-100/

borkdude 2017-12-09T16:22:15.000039Z

Turned out my first solution was correct after all. I just copied the quoted input to a file, which yielded a different answer. DOH.

mfikes 2017-12-09T16:24:17.000035Z

No. That looks interesting!

bhauman 2017-12-09T16:34:41.000011Z

its way more fun than I expected

borkdude 2017-12-09T16:37:07.000107Z

Sorry, not enough time for that right now 🙂

2017-12-09T16:37:08.000070Z

I tried TIS-100

2017-12-09T16:37:16.000055Z

it’s harder than it looks

2017-12-09T16:37:38.000101Z

never finished it, requires lots of free time

bhauman 2017-12-09T16:49:52.000012Z

@nooga yeah its not easy but I hurt my back the other day so i'm kinda stuck on the couch

bhauman 2017-12-09T16:50:41.000060Z

and I was watching "Halt and Catch Fire" so I was a bit nostalgia driven

😁 2
borkdude 2017-12-09T16:52:16.000103Z

I think my spec is correct now, but it’s still slow: https://github.com/borkdude/aoc2017/blob/master/src/day9_spec.clj#L56

grzm 2017-12-09T16:52:35.000058Z

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

grzm 2017-12-09T16:52:48.000078Z

They're all pretty close, though. Within 2 ms.

borkdude 2017-12-09T16:53:18.000054Z

Maybe I should try instaparse

grzm 2017-12-09T16:54:29.000088Z

It's pretty impressive how flexible spec is.

grzm 2017-12-09T16:55:23.000096Z

What kind of speeds are you seeing with your spec solution?

borkdude 2017-12-09T16:55:24.000014Z

yeah, but I think the data it’s generating for this thing becomes too big maybe?

borkdude 2017-12-09T16:55:45.000042Z

@grzm Nothing yet. I can’t parse the whole input

borkdude 2017-12-09T16:55:51.000065Z

Halting problem

grzm 2017-12-09T16:56:00.000054Z

That makes sense. It's building up some sort of structure to be able to explain failures.

borkdude 2017-12-09T16:56:52.000018Z

I love how you can just eval your boot file and it will pick up on new deps

2017-12-09T17:04:17.000069Z

@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

borkdude 2017-12-09T17:05:50.000110Z

hmm yeah, how to improve that

2017-12-09T17:12:20.000109Z

replace char? with a more specific predicate, same for :children and :comma

orestis 2017-12-09T17:17:38.000023Z

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

👍 1
orestis 2017-12-09T17:27:17.000071Z

Seems like similar to @nooga but with two functions for each state.

grzm 2017-12-09T17:36:48.000054Z

@borkdude I've been eyeing your resource-reducible. I've been focusing on using more tranducers. Is that something you worked out yourself?

borkdude 2017-12-09T17:37:57.000054Z

@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

borkdude 2017-12-09T17:38:09.000026Z

The link to the full blog post is at the bottom

grzm 2017-12-09T17:38:35.000086Z

Ah! That post came up in my search for IReduceInit.

grzm 2017-12-09T17:39:02.000005Z

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!

grzm 2017-12-09T17:40:06.000089Z

And it's only Day 9 🙂

borkdude 2017-12-09T17:40:27.000044Z

To be honest I didn’t really need it, line-seq or slurp is sufficient

grzm 2017-12-09T17:42:34.000086Z

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.

orestis 2017-12-09T18:09:08.000120Z

Ah, I should have used letfn for my mutually recursive functions instead of pre-declaring them.

borkdude 2017-12-09T18:18:43.000041Z

Instaparse! https://github.com/borkdude/aoc2017/blob/master/src/day9_instaparse.clj

👍 1
fellshard 2017-12-09T18:22:41.000100Z

D'oh. Yeah, I should've considered the escaped quotes in my input 😞

fellshard 2017-12-09T18:23:52.000078Z

I was wondering if someone would make a grammar for this, it's perfectly suited 😄

fellshard 2017-12-09T18:24:33.000120Z

Instaparse looks really neat, should pick that up for one of these.

fellshard 2017-12-09T18:25:45.000024Z

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.

2017-12-09T19:34:02.000088Z

funny, I’m writing a ghetto parser combinator lib atm

borkdude 2017-12-09T19:49:58.000065Z

Inlined the grammar now, so you see the entire solution one file. See above link. Really happy with it 🙂

borkdude 2017-12-09T19:50:51.000057Z

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.

borkdude 2017-12-09T19:53:00.000031Z

Here’s a screenshot of the parsetree: https://twitter.com/borkdude/status/939583561568604160

👌 3
2017-12-09T20:26:26.000033Z

😮

2017-12-09T21:21:05.000043Z

@grzm for resource-reducible there's also https://github.com/cgrand/xforms/blob/master/src/net/cgrand/xforms/io.clj#L14

borkdude 2017-12-09T21:21:39.000047Z

yes, I think it’s more or less the same thing (unless I’m missing something)

gnejs 2017-12-09T21:25:00.000099Z

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?

borkdude 2017-12-09T21:26:53.000063Z

@gnejs There is a possible solution with a single pass using a couple of values in a state with reduce

borkdude 2017-12-09T21:27:24.000011Z

@mfikes also has one

mfikes 2017-12-09T21:29:30.000033Z

For reference here is my solution https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_09.cljc

gnejs 2017-12-09T21:29:51.000053Z

@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.

gnejs 2017-12-09T21:31:59.000052Z

So my question is really - how do you implement a stateful filter (transducer-like) without resorting to using mutable state as I did?

mfikes 2017-12-09T21:33:17.000060Z

@gnejs I think it is normal to keep state (usually using volatiles instead of atoms). See (source distinct)

gnejs 2017-12-09T21:34:55.000018Z

@mfikes ah, cool. So it's not really an anti-pattern then :thumbsup:

mfikes 2017-12-09T21:35:30.000028Z

I honestly don't know too much about it other than "stateful transducers have mutable state in them using volatiles"

gnejs 2017-12-09T21:37:41.000051Z

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

mfikes 2017-12-09T21:38:26.000033Z

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.)

grzm 2017-12-09T21:57:50.000099Z

@thegeez yeah, it looks like there's a lot of goodness in xforms