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
2017-12-07T02:42:27.000086Z

Never really used reduced before.. useful!

2017-12-07T03:40:52.000235Z

how about (drop max-idx (take (+ max-val max-idx) (cycle (range memory-length))))

mfikes 2017-12-07T03:45:41.000117Z

Cool. Nice way to avoid mod 🙂

cjmurphy 2017-12-07T03:59:12.000016Z

@minikomi Yes (cycle (range num-memory-banks)) is better than (mapcat identity (repeat (range num-memory-banks))). Now that I know about cycle I won't have to coerce it from other functions. Thanks @mfikes 🙂

mfikes 2017-12-07T04:05:58.000216Z

cycle can also be useful in the day 1 problem, where the problem definition indicates "The list is circular"

☝️ 1
2017-12-07T04:38:13.000141Z

Got a banana and my cup of tea. Ready.

grzm 2017-12-07T05:10:42.000141Z

done yet?

2017-12-07T05:10:48.000126Z

nope lol

grzm 2017-12-07T05:11:31.000083Z

I'm about to start

grzm 2017-12-07T05:11:37.000054Z

no pressure 🙂

2017-12-07T05:16:52.000103Z

oops.. emacs locked up when i pasted in the input lol

2017-12-07T05:17:34.000185Z

I think all the parenthesis messed with it

2017-12-07T05:55:18.000225Z

stuck on part 2 😕

2017-12-07T06:01:53.000031Z

Getting the "right" answer for the test input, but being denied on my actual input

grzm 2017-12-07T06:32:38.000185Z

crikey

dyankowsky 2017-12-07T06:34:17.000065Z

it's a good one

grzm 2017-12-07T06:35:14.000042Z

yeah, I need practice with trees 🙂

dyankowsky 2017-12-07T06:36:04.000196Z

I managed to get the correct solution partially "by hand", now I'm going back to finish the code

dyankowsky 2017-12-07T06:36:08.000122Z

to part2 that is

2017-12-07T06:39:28.000155Z

got it but ... but what a mess lol

2017-12-07T06:46:07.000174Z

"Elapsed time: 3.052496 msecs" ... quick though

dyankowsky 2017-12-07T06:53:29.000132Z

heh, mine's about 3x slower

dyankowsky 2017-12-07T06:53:33.000089Z

but I'm OK with that

2017-12-07T06:53:37.000064Z

ah, input probably different haha

dyankowsky 2017-12-07T06:53:41.000133Z

good point

2017-12-07T06:53:48.000054Z

can you send me your input private message?

2017-12-07T06:53:56.000236Z

i'll give it a whirl

2017-12-07T06:54:33.000091Z

also works 😜

grzm 2017-12-07T07:28:00.000091Z

okay. I think I'm going for the most baroque solution

val_waeselynck 2017-12-07T08:29:54.000197Z

Today's problem with DataScript + ex-info: https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/src/aoc2017/day07.clj

2017-12-07T08:36:04.000158Z

ooh nice!

borkdude 2017-12-07T08:38:28.000046Z

Solved the problem, but have to clean up the code. Also used ex-info 🙂

2017-12-07T08:38:44.000006Z

https://github.com/minikomi/advent-of-code/blob/master/src/advent/2017/day7.clj here's my loop-de-loop solution

2017-12-07T08:57:37.000081Z

I bet there's a good way to use some kind of walk here

2017-12-07T09:23:39.000242Z

ah -- tree-seq was what i wanted

borkdude 2017-12-07T10:25:32.000249Z

FWIW, my code for day 7: https://github.com/borkdude/aoc2017/blob/master/src/day7.clj

2017-12-07T10:25:56.000221Z

I discovered tree-seq and went crazy with it on my refactor hahaha

borkdude 2017-12-07T10:27:39.000009Z

To keep it sustainable, I’ll try not to think about this puzzle and to tweak things all day 😉

2017-12-07T10:28:10.000170Z

yeah, you know how it is when you find a new tool though 😉

borkdude 2017-12-07T10:29:42.000385Z

right 😉

orestis 2017-12-07T11:46:58.000347Z

I had a very bad night sleep so I solved part 2 almost by hand.

orestis 2017-12-07T11:47:32.000038Z

This is one I would like to go back to and see how trees work in clojure!

2017-12-07T11:56:41.000149Z

this is mine: https://repl.it/repls/KaleidoscopicOrangeTragopan

2017-12-07T11:57:09.000110Z

it’s ugly and I forgot about tree-seq existence

2017-12-07T11:57:16.000172Z

but it seems to work 😄

2017-12-07T13:03:39.000212Z

my goal with these is to arrive at the solution asap, without too much tinkering with performance and algorithmic elegance

2017-12-07T13:23:42.000015Z

Well that was the first actual challenge of this years calendar for me

val_waeselynck 2017-12-07T13:24:55.000008Z

Getting to try some libs that make it easy to solve the problems can be a good value add too. Working on last year's problems, I've been able to use Clara Rules for example

2017-12-07T13:27:08.000206Z

Looking through your datascript solution now, never applied datascript or datomic to any advent problems yet

val_waeselynck 2017-12-07T13:29:08.000177Z

Frankly, for this problem, DataScript turned out to be more overkill than I hoped.

val_waeselynck 2017-12-07T13:29:24.000050Z

still, quite comfortable for representing graphs.

borkdude 2017-12-07T14:18:40.000556Z

I thought I would need a delay construction like with 2015's day 7, but this problem didn’t require it because of the regularity in the graph

borkdude 2017-12-07T14:26:46.000207Z

nice viz of today: http://raevnos.pennmush.org/images/day07.svg

borkdude 2017-12-07T14:39:25.000471Z

Fun useless fact: both part 1 and 2 run at about 6.8 ms (using criterium)

borkdude 2017-12-07T14:43:52.000307Z

All you needed to parse this one was clojure.edn/read-string and destructuring (SPOILER in thread) 🙂

borkdude 2017-12-07T14:45:50.000267Z

[[name [weight]
    & [arrow & names]]]

👍 1
borkdude 2017-12-07T14:46:43.000236Z

I like what thegeez did with the underscore for the arrow, to emphasize this is just a separator

mfikes 2017-12-07T14:57:11.000765Z

My day 7 solutions are up https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_07.cljc

mfikes 2017-12-07T15:00:08.000720Z

Nice parsing approach @borkdude I like it!

borkdude 2017-12-07T15:01:45.000315Z

@mfikes Ah, set/mapinvert and oh yes, .indexOf

borkdude 2017-12-07T15:02:05.000498Z

@mfikes Nice solution again!

mfikes 2017-12-07T15:03:12.000428Z

I too had difficulty with part 2, trying perhaps 3 incorrect solutions until I figured out what was needed. And I did that part by hand, and backfilled the code 🙂

borkdude 2017-12-07T15:04:47.000625Z

This year my extra challenge is to finish before coffee, so I wasn’t too concerned of making it the most beautiful

mikelis 2017-12-07T15:05:26.000592Z

has anyone tried an approach with inverting the whole tree?

borkdude 2017-12-07T15:05:56.000419Z

I don’t know about inverting the whole tree, but I keep a map of name -> ancestors and I’ve inverted that one in the second part

mikelis 2017-12-07T15:05:58.000109Z

in part 1 i iteratively pruned off all leaves and references to them until only the root is left

mikelis 2017-12-07T15:06:14.000118Z

right, well that’s essentially inverting it i guess

borkdude 2017-12-07T15:06:24.000157Z

in part 1 I simply found the name without any ancestors

mikelis 2017-12-07T15:06:44.000257Z

that’s simpler

borkdude 2017-12-07T15:06:44.000355Z

set/difference as mfikes did

mikelis 2017-12-07T15:06:49.000120Z

didn’t think of that

mikelis 2017-12-07T15:07:01.000160Z

the puzzles publish at 7am local time 😅

borkdude 2017-12-07T15:07:14.000120Z

local time, really?

mikelis 2017-12-07T15:07:16.000783Z

for me part 2 is an ugly solution with println which kinda works like throw in some of the other solutions

mikelis 2017-12-07T15:07:36.000227Z

i rewrote it to use reduced but it’s uglier than the throw variant

borkdude 2017-12-07T15:07:48.000591Z

yeah, exceptions really helped me too 😉

borkdude 2017-12-07T15:07:56.000852Z

ex-data ftw

mikelis 2017-12-07T15:08:02.000685Z

sometimes that’s really nice for an early return

mfikes 2017-12-07T15:08:23.000276Z

For me, I started with reduced for early return, and then went with some

mikelis 2017-12-07T15:08:28.000788Z

i’m hoping to try a solution with walk

mikelis 2017-12-07T15:09:07.000095Z

can you explain more?

mikelis 2017-12-07T15:09:21.000393Z

did you get rid of the reduced and replaced it with some, or used both?

mikelis 2017-12-07T15:10:00.000058Z

(let [[w tops] (get tower root)
        top-res (group-by #(find-unbalanced tower %) tops)]
    (or (some (comp #(when (reduced? %) %) first) top-res)
the problem that prevented me from an elegant solution is the fact that I need frequencies or group-by and only one of the values is reduced?

mikelis 2017-12-07T15:10:13.000245Z

but I haven’t spent much time trying to make it prettier

mikelis 2017-12-07T15:10:44.000042Z

since in the morning I wasted around 20 minutes because my parsing regex was using (....) for the name part since in the test input all names were 4 chars long

mikelis 2017-12-07T15:11:51.000752Z

and I thought I had an error in the solution itself which I couldn’t find… until i fixed the regex to be ([^ ]+)

mfikes 2017-12-07T15:12:31.000471Z

I started by reduceing over the data, but I had a nil (and ignored) accumulator, and had it stop with reduced when it found the unbalanced bit. I then took this reduce, and took the accumulator out of the reducing function, and essentially turned it into a predicate for some. Example:

(reduce (fn [_ x] (when (odd? x) (reduced x))) nil [2 4 2 7 2])
can be simplified to
(some (fn [x] (when (odd? x) x)) [2 4 2 7 2])

mfikes 2017-12-07T15:16:27.000538Z

I'm curious about people using Spec to parse this one. Digging through the solutions now...

borkdude 2017-12-07T15:17:05.000497Z

I found spec a bit overkill for this one

mfikes 2017-12-07T15:17:21.000278Z

Yes, I like your destructuring

borkdude 2017-12-07T15:18:07.000486Z

haha, even using the mapping from "(20)" to 20 by first 😉

borkdude 2017-12-07T15:18:38.000331Z

or (nth 0) is what destructuring is using

mfikes 2017-12-07T15:18:38.000425Z

Yes. I couldn't figure out how to get Spec to do that for me.

borkdude 2017-12-07T15:19:04.000311Z

Sometimes things just map co-incidentally well to edn

mfikes 2017-12-07T15:20:27.000361Z

Hmm. A lot of silver stars right now. I wonder if that is normal for this time of day.

borkdude 2017-12-07T15:20:49.000223Z

If you have kids and have to start early at work, I can imagine this is not something you do on the bus

mfikes 2017-12-07T15:21:48.000397Z

Yeah. Perhaps part 2 is challenging. I found the spiral more challenging.

borkdude 2017-12-07T15:23:04.000279Z

I found this one more challenging, but when I found out about the squares at the bottom right, I felt really dumb

mfikes 2017-12-07T15:23:59.000299Z

Yeah, I'm not like Gauss. I would have started adding 1, 2, 3...

borkdude 2017-12-07T15:26:15.000772Z

Ulam’s spiral, it’s a thing

mfikes 2017-12-07T15:26:34.000201Z

Yep, Ulam is what immediately came to mind for me as well 🙂

borkdude 2017-12-07T15:27:15.000750Z

Never heard of it before. These are not typical problems you run into in day to day coding

borkdude 2017-12-07T15:28:43.000102Z

But now I love it. Will never forget Ulam again 😛.

mfikes 2017-12-07T15:29:30.000664Z

Do the AoC problems get progressively more difficult over the month?

mfikes 2017-12-07T15:29:52.000698Z

(Like 4Clojure?)

borkdude 2017-12-07T15:30:30.000138Z

I hope not. 😛

val_waeselynck 2017-12-07T15:32:05.000458Z

@mfikes @borkdude From what I saw in AoC 2016, they do get more difficult 😛

mfikes 2017-12-07T15:32:35.000321Z

I recall some of the 4Clojure problems getting into the 4-hour range near the end

val_waeselynck 2017-12-07T15:32:37.000096Z

(only did a subset of AoC 2016)

mfikes 2017-12-07T15:49:39.000233Z

Interestingly, if you look at tentamen's part 2 solution (https://github.com/tentamen/adventofcode/blob/master/src/adventofcode2017/day7.clj), you can see that the input resulted in the unbalanced node being at the root of the tree, and if you are lucky with such a data set, you can skip some coding. (If I try that code on my input, it exhausts the stack somewhere in it)

val_waeselynck 2017-12-07T15:52:15.000490Z

Since we've been talking a lot about performance lately: I've been working on problem 23 of AoC 2016, in which performance ends up being rather critical. (The problem is to implement an interpreter about a very basic assembly that self-modifies code: https://adventofcode.com/2016/day/23) I first did a "Clojure-idiomatic" solution, with immutable state and multimethods (https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/src/aoc2016/day23.clj#L44). Then I saw it tooks at least 30min to run on part 2, and did a second version that uses more primitive Java stuff (arrays, primitive, enums): See https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/src/aoc2016/day23.clj#L165 and https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/java/aoc2016/Day23.java The second version turned out to be about 100 times faster (16 seconds instead of 20 minutes).

val_waeselynck 2017-12-07T15:52:33.000345Z

Thought people might find this interesting

mfikes 2017-12-07T15:55:08.000569Z

Yeah, @val_waeselynck it seems like this assertion might be true: "If you solve any problem with Clojure, you can come up with a succinct, maintainable, readable solution. If you need perf, there is often an order of magnitude or more available by switching to lower level constructs, and you can often get away with going down that path for the perf-critical portion of your code."

mfikes 2017-12-07T15:57:05.000508Z

One a large project I was on recently (where overall perf was critical), it felt like 80–90% of the code could be Clojure, and the rest could still be "Clojure", but really Java in disguise.

mfikes 2017-12-07T15:58:08.000163Z

I think this assertion is true for the ClojureScript compiler, in a sense. Most of it is normal code, but the hot spots have been optimized in ways that deviate from "normal"

val_waeselynck 2017-12-07T15:58:49.000140Z

@mfikes Totally agree with that. It should also be noted that even if I had started with the Java thing, it would have taken me more time overall to debug it and run it, given the time it took me to debug it 🙂 (granted, that may be because my Java is a little rusty)

mfikes 2017-12-07T15:59:21.000069Z

Also, lots of the highly-performant and desirable algorithms that were invented in the 60s and 70s heavily rely on mutation. Perhaps that caused a lot of what I saw when working on the large project.

val_waeselynck 2017-12-07T15:59:41.000625Z

However, I saw Martin Odersky say in a talk that a compiler typically has no hot spots - but that may be more true of compilers that have to do a fair amount of static inference

mfikes 2017-12-07T15:59:51.000189Z

(Literature is thin on functional algorithms.)

mfikes 2017-12-07T16:01:00.000878Z

Hmm. Very odd. The ClojureScript compiler seems like any other program to me. It has bits that are very hot compared to others. Martin is a genius so perhaps I'll dig up that talk.

val_waeselynck 2017-12-07T16:01:02.001Z

@mfikes I would argue SQL query engines are examples of highly-performant functional algorithms - i.e they yields highly performant programs that manipulate only immutable values

mfikes 2017-12-07T16:01:42.000060Z

Good point. I wonder if they are functional on the outside but inside it is like "transient city"

val_waeselynck 2017-12-07T16:02:27.000135Z

I believe they totally are transient inside - but it's a good testimony that being declarative makes a lot of room for global optimizations

val_waeselynck 2017-12-07T16:02:49.000080Z

The virtual DOM is another such example

mfikes 2017-12-07T16:02:58.000371Z

This entire subject is, of course, important. If it weren't for the availability of these tradeoffs, you really couldn't use Clojure for a large class of problems.

val_waeselynck 2017-12-07T16:03:59.000163Z

I think it was this one https://www.youtube.com/watch?v=WxyyJyB_Ssc

mfikes 2017-12-07T16:04:02.000828Z

In other words, if you buy into using Clojure, I think you have to accept that for parts of your program, you can't insist on the ideal Clojure approach. (Unless your problem has no perf aspects, of course.)

borkdude 2017-12-07T16:04:16.000913Z

@mfikes about the input, I checked if I wasn’t just lucky with my input so I took yours: https://github.com/borkdude/aoc2017/blob/master/src/day7.clj#L111

mfikes 2017-12-07T16:05:12.000894Z

Yeah, for tentamen you can see that part of the code has a comment showing that the root is where the unbalanced node is. Then the remainder of the code leverages that fact. Fair.

val_waeselynck 2017-12-07T16:05:26.000139Z

@mfikes I even find that Clojure can be a more elegant solution to some problems in the high-performance space, what with macros and the runtime compiler as zero-cost abstractions

borkdude 2017-12-07T16:06:15.000243Z

yeah, or take Om vs React being faster due to immutable state

mfikes 2017-12-07T16:06:25.000339Z

Definitely: Here is another effect I've seen. Since it is so damned easy to change Clojure code to do something in a different way, it is often feasible to explore different approaches and end up with a faster solution than if you were working in Java.

mfikes 2017-12-07T16:06:51.000122Z

If you were in Java, you get calcified in an approach quickly.

mfikes 2017-12-07T16:07:57.000806Z

Time is money. If you can't explore alternatives you often have to accept the perf you have.

val_waeselynck 2017-12-07T16:08:43.000873Z

@mfikes Funnily, you could say that Clojure programmers are to Java Programmers what JITs interpreters are to AOT compilers: the first start very quickly and spend a little time optimizing the critical parts based on experience, the other ones start slowly and spend a lot of time speculating on what is going to be critical (and being pessimistic about it)

mfikes 2017-12-07T16:08:55.000275Z

Think about the extreme of programming in machine code. Once you've solved a problem, you are pretty challenged to try a different approach, no matter how fasts your machine code runs.

mfikes 2017-12-07T16:10:11.000450Z

This has led to a philosophy: Develop in the highest-level programming paradigm you can find that also affords you the opportunity to delve lower when needed.

👍 2
borkdude 2017-12-07T16:10:25.000085Z

Breadth first

borkdude 2017-12-07T16:11:35.000757Z

Also, when correctness isn’t an issue (you want to research solutions first, handling all edge cases is not a problem) then types can get in the way a bit, where you have to be explicit when you don’t want to be

mfikes 2017-12-07T16:12:13.000173Z

@val_waeselynck I like your JIT to AOT analogy

borkdude 2017-12-07T16:12:52.000113Z

Also, the REPL helps a lot in this

mfikes 2017-12-07T16:13:52.000827Z

Exactly. The fact that ClojureScript can be thought of as a compiler is the wrong way of thinking of it, IMHO. The best way to think of ClojureScript is just as a Lisp, but with a mode that can be AOT'd to produce a small artifact when you really need it.

val_waeselynck 2017-12-07T16:14:09.000934Z

@borkdude totally. Being able to use Criterium and Tufte on the fly helps a lot when optimizing stuff

borkdude 2017-12-07T16:15:15.000257Z

tufte… hmm, never used it before. @mfikes I see it’s crossplatform…

grzm 2017-12-07T16:58:21.000263Z

That was like slogging through mud. I posted it, only because I want to be able to look back in the future and say "Oh, my! I have improved!"

grzm 2017-12-07T16:58:44.000322Z

I don't even want to look at the other solutions yet. I feel like I need to keep pounding on it.

grzm 2017-12-07T17:12:26.000272Z

And speaking of datomic and databases, Vik Fearing has been solving them using postgres: https://github.com/xocolatl/advent-of-code-2017

mikelis 2017-12-07T18:34:38.000614Z

I’m surprised.. for few (3) elements, maps seem faster than vectors

mikelis 2017-12-07T18:36:43.000511Z

that is, mapping to

{:id     name
     :weight   (parse-int weight)
     :children (some-> top (str/split #", "))}))
and then indexing on :id is some 5-10% faster than doing the same with a 3-tuple and first

grzm 2017-12-07T18:43:17.000025Z

Any different when using (get x 0)?

mikelis 2017-12-07T18:44:07.000058Z

I’m using destructuring for both, didn’t try get or nth

borkdude 2017-12-07T18:44:40.000222Z

@grzm how are you profiling?

grzm 2017-12-07T18:44:56.000128Z

I'm not, for the most part.

grzm 2017-12-07T18:45:23.000051Z

I'm trying to focus on habit at a time. And in this case it's been transducers and cljc. It's too easy for me to yak shave.

borkdude 2017-12-07T18:45:50.000696Z

@grzm I’d be happy to throw it against criterium if you have the full snippet

grzm 2017-12-07T18:47:06.000037Z

Is this in reference to my "mud" comment? Or perhaps you mean @mikelis.vindavs? The performance of mine was pretty good: 78ms iirc.

borkdude 2017-12-07T18:47:24.000065Z

Ah sorry. I meant @mikelis.vindavs 🙂 about the 3-tuples

mikelis 2017-12-07T18:48:04.000274Z

just (time (dotimes [_ 1000] (solve)))

borkdude 2017-12-07T18:48:44.000271Z

That may not render realistic results

grzm 2017-12-07T18:48:44.000400Z

And when I did a bit of refactoring, the mud cleaned up a bit. I don't like throwing to get a result, but that's what I ended up doing.

borkdude 2017-12-07T18:49:16.000248Z

@grzm Me too. I don’t see that as a problem. Could easily refactor it, but I find it a creative way of solving the problem 🙂

borkdude 2017-12-07T18:49:38.000669Z

Try with criterium and then quick-bench

grzm 2017-12-07T18:50:53.000446Z

an application of creative destruction 😉 shows my bias with respect to throwing: I'm inclined to view it as something negative, rather than the tool it actually is.

mikelis 2017-12-07T18:50:54.000236Z

I’ll try your suggestions , thanks

borkdude 2017-12-07T18:51:54.000218Z

Detecting an error is fine with throw/catch and that was what the puzzle was about 😉

grzm 2017-12-07T18:52:24.000534Z

True!

grzm 2017-12-07T18:52:52.000118Z

Also think I applied destructuring as deeply as I ever have: https://github.com/grzm/advent-of-cljc/blob/master/src/main/com/grzm/advent_of_code/advent_2017/day_07/part_2.cljc#L17

grzm 2017-12-07T18:54:12.000272Z

Three levels deep. Once you're there it's revealing a pretty specific solution, but it's cool that destructuring works so robustly.

borkdude 2017-12-07T18:54:39.000698Z

How do you know the common-weight is in the first spot there?

grzm 2017-12-07T18:55:10.000416Z

I'm grouping by the tree weight, so the keys are the weights. Given the constraints of the problem, I know there's only going to be one that's an odd tree weight, so everything else is going to have the same tree weight. Then the sort-by transforms the map into a sequence of two vectors, odd-tree-weight first.

mfikes 2017-12-07T18:58:35.000807Z

@mikelis.vindavs I was a little surprised as well when I changed my solution for yesterday to represent banks of memory as integer-indexed maps instead of vectors, and it ran slightly faster. I did not make this change for perf reasons, but so that the code would be correct when using (merge-with + ,,,) Here is the revision I'm talking about if curious : https://github.com/mfikes/advent-of-code/commit/9a178036eeb2c39b168712fed3388007217933ea

grzm 2017-12-07T18:58:38.000077Z

It's kind of obscured by the destructuring, but that let only has a single binding in it.

borkdude 2017-12-07T18:59:10.000030Z

ah, missed that, I thought it was the argument to the function… getting tired 😉

grzm 2017-12-07T18:59:37.000508Z

Where are you at?

mikelis 2017-12-07T18:59:56.000074Z

benchmarked with criterium, same thing — the difference is small, but still there

grzm 2017-12-07T19:00:04.000363Z

I'm in the US midwest.

borkdude 2017-12-07T19:00:12.000532Z

Europe, Netherlands

mikelis 2017-12-07T19:00:21.000028Z

but what’s even more interesting that maps vs vectors is the fact that for the 1st part of the problem

mikelis 2017-12-07T19:00:30.000018Z

a set difference approach is slower than an iterative pruning one

grzm 2017-12-07T19:01:38.000228Z

I've been staying up and starting AoC at 11PM my time. Not the best to start working on a puzzle, especially ones like this one. Lots of little mistakes getting in the way of getting to the solution.

mikelis 2017-12-07T19:01:40.000127Z

I can’t wrap my head around why that would be true. Is set/difference slow?

grzm 2017-12-07T19:02:04.000831Z

Anyway, thanks for your evangelism wrt AoC! It's made it more enjoyable for me.

mfikes 2017-12-07T19:02:07.000540Z

We may actually be seeing completely different effects, since mine is in ClojureScript. (I don't know JavaScript that well, but it seems like arrays are integer-indexed maps in a sense anyway, at least until the optimizer does something about them.)

borkdude 2017-12-07T19:02:34.000528Z

🙂

mfikes 2017-12-07T19:03:45.000421Z

I've never heard anyone suggesting that set/difference should be avoided for perf reasons.

mikelis 2017-12-07T19:05:25.000554Z

the difference is pretty small, but in the other approach, I’m iteratively - removing nodes that have no children (`filter + into {}`) - removing references to those nodes (`map + filter + into {}`) until there’s only 1 entry left which seems like a ton more work than 2 map + set difference

mikelis 2017-12-07T19:06:23.000130Z

is there a way to load a leiningen project in cljs? i have planck installed but am not very familiar with it

mikelis 2017-12-07T19:06:34.000392Z

also I suppose io/resource isn’t implemented in cljs

mfikes 2017-12-07T19:07:54.000231Z

@mikelis.vindavs You can run lein classpath to spit out a classpath, and Planck -c to take a classpath

mfikes 2017-12-07T19:08:41.000751Z

Planck has a <http://planck.io|planck.io> namespace that defines resource. I've been using it: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_05.cljc#L7

mfikes 2017-12-07T19:10:34.000376Z

To be honest lein classpath dumps out a lot of stuff you may not need, so I often manually specify the classpath, and there is -D sugar that Planck and Lumo have to expand to existing deps in your local Maven repo: http://planck-repl.org/dependencies.html

mikelis 2017-12-07T19:10:43.000665Z

thanks, I’ll try that

mfikes 2017-12-07T19:11:21.000613Z

Yeah, just take a peek at my repo https://github.com/mfikes/advent-of-code to see how I have it set up to run both Planck and Clojure with one source tree.

borkdude 2017-12-07T19:27:06.000318Z

PureScript solution: https://github.com/krisajenkins/AdventOfCode/blob/master/src/Year2017/Day7.purs

mfikes 2017-12-07T19:27:57.000465Z

Wow. Hefty import list. Wonder if that is normal in PureScript.

mfikes 2017-12-07T19:28:28.000126Z

Most of my Clojure solution namespaces are about the same size as that import list

borkdude 2017-12-07T19:28:37.000183Z

_total = _Newtype &lt;&lt;&lt; prop (SProxy :: SProxy "total")
 let childrensTotals = split.right ^.. traversed &lt;&lt;&lt; _total
lenses…

mfikes 2017-12-07T19:32:30.000738Z

I Like how Kris came to the same spot where the last bit of code wasn't necessary (you could do the last bit by hand faster than writing the code for it)

borkdude 2017-12-07T19:33:33.000781Z

Yeah, but I want my part-2 function to always give the answer.. it’s part of my implicit contract

borkdude 2017-12-07T19:33:46.000042Z

Maybe I have to write a protocol for it 😉

borkdude 2017-12-07T19:41:39.000043Z

What’s a better way for this:

(defn find-by-val
  [m v]
  (ffirst
   (filter (fn [[k v’]]
             (= v v’))
           m)))

borkdude 2017-12-07T19:41:46.000207Z

Could have used map-invert, but you’re never sure if the map has duplicate values

mfikes 2017-12-07T20:00:07.000233Z

@borkdude If you want early termination and nil is not a concern, this seems to read nicely

(defn find-by-val
  [m v]
  (some (fn [[k v']]
          (when (= v v')
            k))
    m))

mikelis 2017-12-07T20:03:51.000177Z

I’m using

(defn find-where [pred coll]
  (some #(when (pred %) %) coll))

mfikes 2017-12-07T20:03:53.000651Z

Hmm. Maybe they both produce the same result, even with nil in the map as key or value

mikelis 2017-12-07T20:04:01.000698Z

ahh but that’s sequences not maps

borkdude 2017-12-07T20:29:14.000288Z

first + filter is also early termination, but yeah, some is also nice

mikelis 2017-12-07T20:30:56.000459Z

it’s unfortunate this isn’t in core

borkdude 2017-12-07T20:40:33.000513Z

I tried .indexOf but this time it didn’t work 😜

borkdude 2017-12-07T20:55:49.000201Z

Nope, lein findfn "{:a 1}" 1 :a, nothing 😉

mfikes 2017-12-07T21:08:18.000623Z

Ahh, right yeah ffirst / filter is indeed lazy

grzm 2017-12-07T21:08:37.000277Z

@mfikes I was there, too (with you and Kris). I had a prn stuck in my recursive search function which printed out the unbalanced nodes. Did that by hand, then went back and finished the code.

grzm 2017-12-07T21:09:28.000279Z

Makes me think there's something getting in the way of me using the machine to explore the problem space. Either practice, or tooling.

grzm 2017-12-07T21:10:41.000323Z

Or technique (which is coupled with practice)

bhauman 2017-12-07T21:10:52.000630Z

busy day finally got my pushed: https://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day07.clj

bhauman 2017-12-07T21:11:30.000128Z

now to read the chat log and see whats up ...

borkdude 2017-12-07T21:13:57.000237Z

@bhauman Creative, rand-nth, just start at some random node in the tree: https://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day07.clj#L30

borkdude 2017-12-07T21:14:44.000293Z

(time (part-2 data)) 1864, is that milliseconds — or probably the solution 🙂

bhauman 2017-12-07T21:15:44.000224Z

yeah the solution

bhauman 2017-12-07T21:16:06.000190Z

@borkdude our data setup is spooky similar

mfikes 2017-12-07T21:35:27.000344Z

@chrisblom Ahh, you got away with calling set/difference with a non-set smaller 2nd argument. For example this works (set/difference #{:a :b :c} [:a :b]) while this doesn't (set/difference #{:a :b :c} [:a :b :c :d :e])

2017-12-07T21:38:49.000027Z

ow, thats nasty

2017-12-07T21:40:27.000038Z

pretend you did not see that

mfikes 2017-12-07T21:40:34.000303Z

Hah. I can't unsee it.

2017-12-07T21:43:17.000220Z

i forgot how wonky clojure.set functions are for a moment

borkdude 2017-12-07T21:47:51.000108Z

@bhauman indeed, great minds alike 😜

mikelis 2017-12-07T21:48:00.000162Z

that’s a beautiful solution!

mikelis 2017-12-07T21:49:57.000089Z

but does it assume that the weight will always need to be adjusted up?

2017-12-07T21:51:56.000424Z

hmm, yeah, thought that was ok, but on second thought its probably not

2017-12-07T21:52:03.000464Z

just got lucky with my input

mikelis 2017-12-07T21:54:04.000212Z

I found that getting the “odd one out” was surprisingly complicated

borkdude 2017-12-07T21:55:09.000380Z

Yeah. This is mine, but I’m sure there are other solutions:

(defn unbalanced-balanced
  [vals]
  (-&gt;&gt; (frequencies vals)
       (group-by val)
       sort
       (map #(second %))
       (map #(ffirst %))))

mfikes 2017-12-07T21:59:28.000019Z

I went with a construct like

((set/map-invert (frequencies [2 2 17 2])) 1)

borkdude 2017-12-07T21:59:44.000270Z

I wanted both numbers in fixed order

mfikes 2017-12-07T22:01:34.000407Z

Yeah, I needed both as well, went with (.indexOf [2 2 17 2] 17) for the second bit

grzm 2017-12-07T22:03:41.000087Z

.indexOf is something I don't often reach for. I take it it's available in cljs?

mfikes 2017-12-07T22:04:39.000503Z

@grzm Yes, but attempting to formally address that with this proposed page https://github.com/mfikes/clojurescript-site/blob/c552daa145ce7005446fa315f042d82ddc4d51f8/content/reference/javascript-api.adoc

borkdude 2017-12-07T22:04:49.000579Z

Actually this works too:

(defn unbalanced-balanced
  [[a b c]]
  (if (= a b)
        [c a]
        [a b]))

borkdude 2017-12-07T22:04:53.000331Z

much simpler 🙂

grzm 2017-12-07T22:05:03.000498Z

That is nice

mfikes 2017-12-07T22:05:58.000276Z

But what if you call it like (unbalanced-balanced [2 2 2 2 17 2])

☝️ 1
borkdude 2017-12-07T22:06:07.000212Z

ah crap

mfikes 2017-12-07T22:07:22.000417Z

I think we do know there are at least 3 items, because if there were 2 it would violate the constraint that "exactly one program is the wrong weight."

borkdude 2017-12-07T22:08:01.000132Z

yeah, that was my thought too

mfikes 2017-12-07T22:08:06.000400Z

Maybe something like the triplet comparison can yield an answer though.

mfikes 2017-12-07T22:08:27.000305Z

Maybe a recursive version of that somehow?

borkdude 2017-12-07T22:08:34.000265Z

Maybe partition and then moving over those

mfikes 2017-12-07T22:15:18.000488Z

This might be correct

(let [[a b :as all] (sort [2 2 17 2])]
  (if (= a b)
    (last all)
    a))

👍 1
❤️ 1
mfikes 2017-12-07T22:17:32.000149Z

^ Inspired by @borkdude’s comparison

borkdude 2017-12-07T22:18:28.000252Z

Somewhat ugly but fast:

(defn unbalanced-balanced
  [[a b c &amp; nums]]
  (let [[balanced maybe-unbalanced]
        (cond (= a b) [a c]
              (= a c) [a b]
              (= b c) [b a])]
    [(some #(when (not= balanced %) %)
           (cons maybe-unbalanced nums))
     balanced]))

mfikes 2017-12-07T22:18:55.000011Z

Nice

borkdude 2017-12-07T22:20:00.000104Z

In fact, in the third condition, we know for sure that a is the unbalanced one, but I didn’t want to write a special case for that

mfikes 2017-12-07T22:23:01.000058Z

The computational complexity of this game https://www.youtube.com/watch?v=Sm-zWDaoCtI

borkdude 2017-12-07T22:28:33.000350Z

Another version, more optimized:

(defn unbalanced-balanced
  [[a b c &amp; nums]]
  (let [find-other (fn [v nums]
                     (some #(when (not= v %) %)
                           nums))]
    (cond (= a b) [a (find-other a (cons c nums))]
          (= a c) [a (find-other a (cons b nums))]
          (= b c) [b a])))

borkdude 2017-12-07T22:29:29.000213Z

Something is wrong maybe, because I don’t get the right output

borkdude 2017-12-07T22:31:05.000122Z

oh yes, wrong order of returned numbers, but apart from that it should work

borkdude 2017-12-07T22:33:03.000068Z

anyway, in theory this should be faster, but in reality, I get 7 ms instead of 6 ms… this is BS 🙂

borkdude 2017-12-07T22:34:27.000228Z

moving the function to its own defn works

borkdude 2017-12-07T22:42:58.000365Z

Final call for “the odd one out”:

(defn unbalanced-balanced
  [[a b c &amp; nums]]
  (cond (= a b) [(some
                  #(when (not= a %) %)
                  (conj nums c))
                 a]
        (= a c) [b a]
        :else   [a b]))