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
bhauman 2018-12-04T02:12:16.484700Z

and I finally got around to doing day 3 https://github.com/bhauman/advent-of-clojure/blob/master/src/advent-2018/day03.clj

rmprescott 2018-12-04T03:03:49.485200Z

Why do you say APL is a different paradigm? Aside from laziness it's pretty similar - just a very different notation.

pesterhazy 2018-12-04T06:50:00.486400Z

Because I don’t know APL :)

3Jane 2018-12-04T08:33:07.487200Z

Day 4 discussion, with spoilers

3Jane 2018-12-04T08:33:25.487300Z

[1518-09-19 23:52] Guard #2083 begins shift
[1518-02-25 00:51] wakes up
[1518-02-28 00:34] wakes up
[1518-04-29 00:54] wakes up

3Jane 2018-12-04T08:35:57.487500Z

Rather sneakily, the example data isn’t in the same format the actual input is.

3Jane 2018-12-04T08:37:16.487700Z

They don’t give you any hint of that apart from > consider the following records, which have already been organized into chronological order

pesterhazy 2018-12-04T08:41:42.488Z

My solution to day 4 https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle04.clj#L42

pesterhazy 2018-12-04T08:42:14.488600Z

Spent around half the time on parsing/understanding the file format

pesterhazy 2018-12-04T08:43:11.488700Z

yeah I found the description less than clear

pesterhazy 2018-12-04T08:43:43.488900Z

but I guess vague specifications is a real-world programming scenario 🙂

athos 2018-12-04T09:06:03.489100Z

In the description they say: > While this example listed the entries in chronological order, your entries are in the order you found them. You’ll need to organize them before they can be analyzed.

fellshard 2018-12-04T09:09:28.489300Z

It was a key realization that there's only one useful chunk of info per line. Also, the specific line format they give means you can sort it in standard lexicographic order to get the correct sequence of events right off the bat, no interpretation of the data required. 🙂

pesterhazy 2018-12-04T09:16:51.489500Z

I did sort lexicographicallz

pesterhazy 2018-12-04T09:17:29.489700Z

but you still need to match guard-ids, interval starts and ends no?

3Jane 2018-12-04T09:19:08.489900Z

Yeah, you’re right. I missed it because it’s not in the place I expected to find it (task description, rather than input format description)

3Jane 2018-12-04T09:19:28.490100Z

That also is a real-world programming scenario: don’t read specs before first coffee :woman-facepalming:

pesterhazy 2018-12-04T09:45:54.490300Z

Reminds me

fellshard 2018-12-04T09:53:55.490500Z

Yep. One piece of info to parse per line: Guard ID or minute.

pesterhazy 2018-12-04T10:04:09.490700Z

And event type 🙂

fellshard 2018-12-04T10:06:00.490900Z

True; I attached that as a tag afterwards, though, since you need to know which type it is to parse correctly in the first place

borkdude 2018-12-04T10:14:02.491300Z

Solved day 4: https://github.com/borkdude/advent-of-cljc/tree/master/src/aoc/y2018/d04

👍 2
borkdude 2018-12-04T10:14:20.491600Z

In CLJ:

Testing aoc.y2018.d04.borkdude
part-2 took 40.23 msecs
part-1 took 3.80 msecs

borkdude 2018-12-04T10:44:56.492300Z

@pesterhazy It seems our solutions are quite similar

borkdude 2018-12-04T10:47:45.493300Z

When reading the puzzle, I thought “strategy 1” was trying to mislead me, since they wrote that there were two strategies and I thought you had to come up with another better strategy 😉

ihabunek 2018-12-04T11:27:09.493900Z

took me a while to parse it, but as usual, regex to the rescue 🙂

taylor 2018-12-04T13:36:39.495200Z

here’s my day 4 https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/4.clj reached for clj-time and instaparse b/c why not 🙂

benoit 2018-12-04T14:22:02.496900Z

My solution to day 4 https://github.com/benfle/advent-of-code-2018/blob/master/day4.clj

benoit 2018-12-04T14:47:00.498800Z

If I had time I would have refactored into something like @tsulej. If you have the proper data structure with minute-level stats for each guard, the 2 solutions can be very concise.

genmeblog 2018-12-04T14:54:35.500700Z

Yes, I think that proper data structure is crucial here. I spent most of my time to find one. The same applies for day 3.

borkdude 2018-12-04T14:56:15.501100Z

oh yeah, I always forget you can give sort-by another argument like (sort-by val > the-things)

genmeblog 2018-12-04T14:58:07.501800Z

without it you can always call (last) which can be obviously slower

genmeblog 2018-12-04T15:01:01.502100Z

(comp - val) cool hack 🙂

borkdude 2018-12-04T15:18:06.503Z

yeah I did the comp thing

ClashTheBunny 2018-12-04T15:25:52.503200Z

lol!!

borkdude 2018-12-04T15:48:36.504100Z

of course, (max-key val …)

borkdude 2018-12-04T15:49:02.504400Z

our add-minutes solution is quite the same

borkdude 2018-12-04T15:49:25.504600Z

or wait, no, it isn’t 🙂

borkdude 2018-12-04T15:49:43.504900Z

ah you save a map of guard -> minutes

taylor 2018-12-04T15:53:37.505300Z

nice to see another use of max-key; I rarely ever have a use for it

taylor 2018-12-04T15:54:10.505900Z

the concision of some of these solutions is impressive 👏

2018-12-04T15:55:13.506200Z

@mfikes very nice!

2018-12-04T15:56:49.506800Z

yeah I was surprised at the amount of (first (sort-by ...)) I’ve been seeing.

2018-12-04T15:56:56.507100Z

max-key often gets forgotten

3Jane 2018-12-04T15:57:51.507800Z

I’m not done yet (done 1/2), but took a look at this channel, and max-key instead of sort-by in the existing solution … which slowed things down. Did you find it more performant?

2018-12-04T15:58:37.508200Z

nah, just what I want

taylor 2018-12-04T15:58:42.508300Z

I haven't been concerned with performance for any of the problems yet

taylor 2018-12-04T15:59:02.508500Z

later in the schedule performance becomes more important

fellshard 2018-12-04T16:02:00.509100Z

I looked at it, but passed it by because I thought it wasn't quite what I wanted. I'll take another look to see what I'm missing.

fellshard 2018-12-04T16:04:13.509200Z

Are you thinking (apply max-key...) has a heavier cost for, say, a map of minute tallies?

3Jane 2018-12-04T16:05:10.509400Z

(…actually might have been the effect of something triggering in the background… I need to check again once I’ve got a charger 🙂 )

borkdude 2018-12-04T16:26:15.510Z

@fellshard I had the same: max-key passed my mind but then I thought: oh this is for map keys or something

borkdude 2018-12-04T16:26:40.510500Z

why isn’t it called max-by

fellshard 2018-12-04T16:27:18.511200Z

I think the prospect of (apply max-key... on 60 elements had me a bit worried, I forget what the rules are for slapping a bunch of arguments in there, even rest-args

borkdude 2018-12-04T16:28:03.511400Z

that works

pesterhazy 2018-12-04T16:37:20.512500Z

@fellshard (apply + (repeat 1000000 1)) seems to work ok in CLJ and CLJS, but (apply + (repeat 10000000 1)) is fast in Clojure but very slow in CLJS (at least in Lumo 1.8.0)

pesterhazy 2018-12-04T16:39:14.513500Z

In Java varargs are passed as an array AFAIK so it should be fine. Not sure why it's so slow in CLJS

pesterhazy 2018-12-04T16:39:45.513800Z

Probably GC?

pesterhazy 2018-12-04T16:43:41.514Z

Math.max.apply(null, new Array(1000000).fill(0)) blows the stack...

borkdude 2018-12-04T16:57:31.514300Z

(apply max (range 100000000000)) works though

mfikes 2018-12-04T17:04:02.515400Z

@pesterhazy Update to Lumo 1.9.0. You'll see (apply + (repeat 1000000 1)) a few hundred times faster. Why? This is the result of optimizations made in ClojureScript after last year's Advent of Code. 🙂

🦜 1
borkdude 2018-12-04T17:06:26.516300Z

changed my max-frequency function. I really should use max-key more often. I think I only remember it until Advent of Code comes along again https://github.com/borkdude/advent-of-cljc/commit/24fa6344c3c64a3fc242d7b2a784df7b73bace8a

mfikes 2018-12-04T17:07:57.516800Z

Lumo 1.8.0:

cljs.user=> (type (repeat 1000000 1))
cljs.core/LazySeq
Lumo 1.9.0:
cljs.user=> (type (repeat 1000000 1))
cljs.core/Repeat

quoll 2018-12-04T17:31:19.518Z

I’ve browsed clojure.core, but keep forgetting about many of the functions in there. I totally forgot about max-key and rolled my own. That said, I used what I rolled in a couple of other ways, so it wasn’t a waste

pesterhazy 2018-12-04T18:04:06.518700Z

@mfikes the advent of code comes full circle!

pesterhazy 2018-12-04T18:21:01.519100Z

it's much faster indeed 🎉

pesterhazy 2018-12-04T18:21:17.519400Z

also a good occasion to upgrade lumo

pesterhazy 2018-12-04T18:22:37.519900Z

now it's 10x faster than Clojure

$ lumo
cljs.user=> (time (apply + (repeat 10000000 1)))
"Elapsed time: 65.706720 msecs"
10000000
$ clj
Clojure 1.9.0
user=> (time (apply + (repeat 10000000 1)))
"Elapsed time: 657.798409 msecs"
10000000

pesterhazy 2018-12-04T18:23:04.520200Z

performance is weird

mfikes 2018-12-04T18:26:01.520800Z

In this case, Lumo may be running at native speed. See https://www.youtube.com/watch?v=LopU-kMpe8I

adammiller 2018-12-04T18:26:59.521900Z

anyone know why (read-string "01") or (read-string "02") ... all the way up to 07 work just fine but (read-string "08") and (read-string "09") throw exceptions saying it is an invalid number? Would assume all would or none would.

mfikes 2018-12-04T18:27:12.522100Z

08 is octal

adammiller 2018-12-04T18:27:17.522300Z

ah

mfikes 2018-12-04T18:27:25.522600Z

Well, malformed octal 🙂

lilactown 2018-12-04T18:27:42.523Z

I've used this almost every day so far:

(defn str->int [^String s]
  (Integer/parseInt s))

adammiller 2018-12-04T18:28:31.523600Z

yeah, for cljc read-string was just faster, but better not to use it for these scenarios (in real code)

borkdude 2018-12-04T18:28:36.523800Z

is the type annotation really necessary?

borkdude 2018-12-04T18:29:05.524400Z

@adammiller not sure if you do advent-of-cljc, but there’s aoc.utils/parse-int for cross platform

adammiller 2018-12-04T18:29:41.525Z

yes, I saw that. Actually just moved my day 3 solution there yesterday....just locally though.

borkdude 2018-12-04T18:30:17.525600Z

@adammiller welcome to submit individual puzzles for any day

adammiller 2018-12-04T18:30:50.526100Z

ok, i'll see about moving my day 4 and then submit them. Thanks!

lilactown 2018-12-04T19:09:44.526900Z

@borkdude it was necessary when I tried it with 1.10-RC2

2018-12-04T19:44:14.527300Z

Try it in the REPL!

ClashTheBunny 2018-12-04T19:50:04.527500Z

I thought I tried that and it didn't work. Is fixed by the ^string metadata?

lilactown 2018-12-04T19:50:31.527700Z

It worked for me on day 1 ¯\(ツ)

ClashTheBunny 2018-12-04T19:51:03.527900Z

Hmmm.... Dang. Wonder what I had problems with...

ClashTheBunny 2018-12-04T19:51:46.528100Z

Maybe it was just the int function...

2018-12-04T19:52:40.528300Z

int is a cast to int

2018-12-04T19:53:25.528500Z

but yeah, java Long/parseLong permits + and -: https://docs.oracle.com/javase/7/docs/api/java/lang/Long.html#parseLong(java.lang.String)

quoll 2018-12-04T20:10:52.528700Z

I’m forever wrapping Long/parseLong in a function. It’s a source of never ending frustration for me that Clojure doesn’t have to-long and to-double

➕ 2
2018-12-04T20:30:51.528900Z

The function reader literal syntax is pretty terse: #(Long/parseLong %). Much nicer than a top level (defn ...) form, if that's what you've been using.

uosl 2018-12-04T20:54:22.529500Z

I almost had a heart-attack when I checked out the real data and saw it had multiple "wakes up" in a row, after having written my solution. Then I realized that it just wasn't chronologically ordered. Then sort came to the rescue 🌸