Ask HN: How was your Advent of Code 2018 experience?

77 points by keithnz ↗ HN
I really enjoyed this year, the thing that made it quite interesting for me was the amount of people streaming in all kinds of languages with all kinds of approaches.

For me I found it quite a nice learning exercise, though oddly enough ( I was trying to do them as fast as I could ) I often resorted to mega functions and basic data types to solve the problems. This worked out well early in the event, but later it would lead to many simple bugs. I also found that it's nice when your language has a lot of toys to make life easier. I started with Go, as a learning exercise, but swapped to C# as so many problems fit nicely with "Linq", however there were lots of missing niceties, so I spawned a NuGet package with a library of extension methods which I hope to polish now that AoC is over

What are your takeaways?

54 comments

[ 0.26 ms ] story [ 114 ms ] thread
First few days were great! Fortan was interesting (...) and wow that C++ was not the same beast I used in college. Then uh... kind of got sidetracked.
It was loads of fun. Decided to try out go, so the first couple of days were a bit slow but from then on it was pure fun. Even though the elves VS goblin game was a bit too much to handle in one single day...
Super fun.

I’m not caught up yet. Finished day 17 earlier today.

I’ve been using the advent to learn Rust. I’m pretty happy with my progress so far. A few things were more difficult than had I used C++. But for the most part it’s gone swimmingly.

I love the advent of code subreddit. Every time I solve a puzzle I check how other people did it in Rust. I learned several new things this way.

This year i wanted to learn Common Lisp (https://git.sr.ht/~ttt/aoc18). I think that there had been way to many problems this year that had huge descriptions with many small details to miss. When you add to it huge puzzle state (2d arrays for maps) it makes debugging simple mistakes needlessly hard - in fact solving day 15 for me was almost like working :(
Yeah, I’m not a massive fan of the “implement this huge spec” puzzles (like the insanity of the knots last year). Give me a geometric or algorithmic one any day.
I still haven't caught up yet as well as the time zone was not the best for me, but it was a fantastic success.

As a mainly Python dev, I tried solving them in Golang during work breaks or afternoons with what little mental energy I had left :P to upload them on Github.

I learned so much more about Go, as some puzzles allowed me to use some nifty language features, and really liked the puzzles that featured recursion! In the end of the day, visiting the subreddit, there were tons of ingenious answers, people willing to help, or discuss the problem on a more theoretical basis. I still missed some of Python's minimalistic style, though.

Thanks Eric Wastl for this Christmas Gift!

I solved all of the problems in Go. I feel like I programmed pretty quickly, but I rarely made it onto the leaderboard. I attribute this to Go's verbosity -- needing to write for loops manually instead of just map/filter/reduce. In 2019 I plan to learn a new language (perhaps Crystal?) that will enable me to solve Advent problems faster.
Never started. No time when you have family+little kid
Great fun, I was another solving in Go (Python programmer by day). I loved AoC, and learned a lot about Go!

The hardest puzzles were definitely the fiddliest ones, day 15 in particular.

I wish there was a way for non US people to get a leaderboard in different timezones, appreciate it's hard (impossible) to do fairly.

I used the first few days for learning Elixir.

On one day I just did not know how to create a solution at all, so I stopped.

Also, I did not have much time, since work and my musicianship were too time consuming. Did not want to come home late in the evening just to lose my mind on more problems that need solving.

They might have been easier using an imperative language, but using Elixir had been a joy nonetheless, despite my occasional cravings for indexes and imperative for-loops.

But I will definitely come back to AoC to further practice Elixir and watch some of Jose Valim's streams. They always add some further insight into the language.

I'm not ashamed to say I found it too hard and didn't make it beyond day 3, but that's still great. It's a useful way to know what you don't know — although because I couldn't move on to the next puzzle, I still don't know what I don't know.

It made me go back to Hackerrank and try a few of those out.

Indeed. I suppose it might make me less of a developer, but I’m not sure I find pure algorithmic work that fun

Plus time is always hard to find.

You can skip days, though. Some are easier than others.
You can, but some puzzles depend on knowing the solution to another puzzle, or are basically advanced versions of the same thing.
Some do, but most don't. For most puzzles the only dependency is part 2 on part 1.
I’ll tell you in March when I’m finished!
I've made it up to Day 14 using Elixir after which I got sidetracked, but still followed the Twitch streams from the Elixir community by Jose (Elixir's creator) and James.

Fantastic learning experience.

If anyone is interested in programming challenges like this, I've also been working on a programming puzzle. The solution will be a private key worth 0.125 BTC (~$500 USD.) And there will also be a few smaller amounts when solve the intermediate stages.

It's going to be posted on my company's blog at 12pm EST on the 30th of December: https://formapi.io/blog

I also did one last year [1], but this time it will be more of a programming challenge instead of a "treasure hunt". Anyway, hope you enjoy it, and good luck!

[1] https://formapi.io/blog/posts/bitcoin-treasure-hunt/

I actually finished them all, most on the day on which they were published (I had the entire day, since the problems open at 06:00 in my timezone; I didn't try for any leaderboards :p). Some problems took me far too much time (day 15 with its huge simulation!), and overall I agree with the general sentiment that the problems were too finicky, with a lot of details to implement without much real thought.

Day 23 part 2 (teleportation nanobots one) was fairly difficult as well; I tried to implement an actual solution, but failed because of wrong assumptions about its correctness. (I tried to represent the intersection of a number of octahedrons with the bounded volume of 8 planes, but it seems that representation is redundant, so there are invalid configurations. I didn't feel like fixing that anymore after 8+ hours.) Looking at the solutions board on reddit, I wrote a smtlib2 script for Z3 that solves it; it works, but isn't all that satisfying.

The sheer amount of pathfinding amazed me; some of the plain pathfinding problems were good (day 22 with its pathfinding in the implicit graph where you split nodes up into the various combinations of tools), and I was happy to see that day 25 was just an unordered graph component analysis (i.e. a few floodfills).

I liked yesteryear more, and in general I'd like to see smaller problem statements (and thereby also less details to implement!), and possibly slightly more of an algorithmic challenge, though the latter is definitely not necessary (this is not a competitive programming competition, it's an advent calendar of all things!).

Still, big thanks to Eric for giving us this!

(I did the problems in Rust, to become more familiar with the language. See my implementations here[1].)

[1]: https://git.tomsmeding.com/AOC/tree/2018/src

Finished them all, and enjoyed it, but Day 23 part 2 (part 1 was trivial) was a real bugbear.

In particular, Day 23 was pretty remarkable for the sheer number of "solutions" posted to the solutions board that worked for the person's own input, but only by luck -- they failed for other peoples'. The only possibly general solutions I've seen are the ones that set up external solvers -- either z3 or some integer programming package. (I wound up using the latter, and may have lucked out myself -- whether due to numerical instability or some fault in problem setup, I only got close enough to optimum to find it with a little local hill-climbing.) I'm not sure that's what Eric had in mind; everything else can be solved in Python or Ruby with no recourse to large external libraries.

For the most part, I had fun with this stuff -- even day 24, which I had to set aside for hours before a careful desk check found the reason why the answers I was getting weren't quite right. But rules that matter for some people, but not others, do take a bit of the shine off. There were more minor problems along the same lines with some of the other problems -- day 15 and day 24 had a lot of fiddly rules which didn't matter at all for some peoples' inputs.

> Day 23 [...] I'm not sure that's what Eric had in mind

There is an algorithm for finding a maximum clique in a graph, and some people on Reddit seem to have used it: the Born-Kerbosch algorithm [1]. Your graph has a connection between two nodes if their ranges overlap. It relies on the assumption that overlapping of manhattan regions is transitive; no-one on Reddit seemed to know whether that assumption is true, and I don't know either. :)

[1]: https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorith...

It's not -- the Reddit thread has a counterexample:

https://www.reddit.com/r/adventofcode/comments/a8s17l/2018_d...

That said -- one visualization posted elsewhere showed that that person's particular input was a bunch of singletons, plus one colossal clique that all intersected at a single point. That may have been structure that people were meant to discover -- but it's not clear that anyone did until after the fact. (The person with the visualization identified the clique as all the "bot ranges" intersecting with a solution point that they'd already found by other means.)

A friend gave me the problem for day 2 part 2, and I found it really cute.

Given a set of n strings, each of length m, find if there is a pair that differs in exactly one position.

It was not trivial to come up with an optimal and elementary O(nm) time algorithm. (by elementary, I mean something does not need a few hours to implement).

I've seen people getting running times of the form O(n^2m), O(n(n+m)) and O(nm^2) on multiple Reddit posts, and was surprised at all kind of different approaches.

It was not trivial to come up with an optimal and elementary O(nm) time algorithm.

Compute the hashes of the nm strings formed by taking each of the n strings and zeroing out one of the m characters. If you get any hash collisions, compare the strings.

Isn't that O(n∙m²)?

    for each string (n)
      for each char (n∙m)
        zero out char, compute hash (n∙m²)
If you hand code your own hash function you can compute hash(string with zeroed out i-th character) from hash(string) in O(1)

An example of such a hash is a polynomial hash (sum c_i * p^i modulo M, with p and M prime) such as the one used to explain https://en.m.wikipedia.org/wiki/Rabin–Karp_algorithm

Right, I meant using a polynomial hash.
Indeed, but I want an algorithm with deterministic O(nm) time.
I loved it (and donated to Eric for his amazing work on AoC). I do all the problems in Ruby on CoderPad, and stream it on Twitch. I love stumbling on problems that have incredibly concise solutions in Ruby (day 25 comes to mind) where you end up with roughly 20 lines of code that crunch the whole thing in a few seconds.
I used it as a workout for the compiler that I'm writing. I solved every problem in my own language, so that was pretty cool. The language is now almost as powerful as C. I kept all the code in one file, which now has grown to 4500 LoC (non-empty, non-comment), producing 38k LoC in LLVM.

On day 6 I got a stack overflow, so I had to quickly implement new/delete. For the Elf processor I had to add in binary operators. Design-wise it taught me that good literals can be really helpful, e. g. an initializer expression for an array of structs. With Python's dict/tuple/array literals e. g. you could sometimes replace parsing entirely with a couple text transformations in Sublime. Maybe this is specific to these kinds of problems, but I think it would also be helpful for unit tests.

It was fun to learn a new algorithm (A*) and implement it. Day 23 part 2 was my favorite. I was stuck for hours, tried two solutions that didn't work out. Went to bed frustrated, then implemented the solution the next morning. I'm still thinking about it, it's an interesting problem.

Is there any particular technical reason behind the decision of having 4500 LoC in a single file? It sounds like a pain to maintain and extend.
I wanted to always compile everything, and I don't have modules yet. Every problem is in one function, so for AOC it wasn't a problem.
That sounds awesome! Do you have any published code for your compiler/language yet? I'm curious :)
Thanks! Sorry, I haven't published anything. My inspirations are Jai, Zig, Ante, and Odin, if that helps.
Stopped at day 15 as it was starting to spend too much time on it all :D wouldn't mind picking back up where I left off over my holiday.
I've been doing it in Scheme this year, as a major branch of the LISP family I've never tried before. Super-impressed by the speed and solidity of the Chez Scheme implementation, but still a little undecided about how much I like Scheme for day-to-day use. (After Clojure, both Scheme and Common LISP seem to have a fair number of "why is this taking so many keystrokes?" moments).

I know a number of people thought some of the "simulation with lots of details to keep track of" problems were a bit over the top this year. Personally, I rather enjoyed them, and in particular found day 15 really satisfying to complete. Not something you'd want to do every day, but it's good to have some problems which pose a bit of a challenge without turning into a "can you pattern-match this against an algorithms textbook" exercise. The overall breadth and balance of problem types was impressive as ever.

I hope it's back next year!

> why is this taking so many keystrokes?

I used to Scheme a lot, and this was a significant part of how Python ended up beating it for regular work. This year I tackled AoC in my own pet new Scheme descendant which tries to fix this problem: https://github.com/darius/squeam -- I'll check in my solutions later today.

Incidentally one thing I learned on Day 1 was that Chez Scheme's built-in hash function is not very good. Chez is generally awesome, so maybe it does work well in the context of Chez's built-in hashtable type, or something -- I didn't check. (My Squeam interpreter runs on top of Chez.)

Darn, totally forgot about this. December is a hard time for puzzles, too much crunching. Anything like this coming up in the next few months?
The good : - I used it as an opportuity to learn Rust and it is definitely a great way to practice with a new language. - I managed to do all but two puzzle within 24h of their publications. - There are some gems (solving the nanobots part2 was very satisfing).

The bad : - Some problem took a lot of time because of sentences I found unclear. - Some problems had very long specs (goblin vs elfes).

I will probably do it again next year (hoping that rough corners get smoothed).

I took part for the first time this year, as an exercise in learning Rust (I have got up to day 20 so far). It's been pretty good for moving from "I sort of know this language" to being a bit more comfortable with it just by spending more time writing code, and I liked the way the problems get gradually more complicated and tricky. Plus, since each day is a fresh problem you can try different coding approaches without being constrained by having to rewrite a pile of existing code.

There are some aspects where things are easier if your language has good support for features which AoC leans on. Notably, almost every problem requires parsing an input text file, so good regex support is really useful. I found myself wishing for a serde regex backend so I could initialize into structs from a regex match without a lot of tedious Point { x: cap[1].parse().unwrap(), y: cap[2].parse().unwrap(), ... } boilerplate. And since a lot of problems use 2D grids of ascii characters, Rust's lack of native 2D arrays and insistence that strings are utf8 and thus not trivially indexable makes things a bit more awkward than they might have been in a different language. I definitely agree with you that a language with a wide ranging standard library helps a lot to make life easier, too.

I found quite frustrating that any non-zero score depends only on time of submission in a specific time zone. It makes it a race and a race for certain people only. But of course one can just take it as an opportunity to practice a language and learn new stuff.
Really time-consuming and also an eye-opening experience to see how good some of the participants are. I haven't participated before and went into the forums for the first time after having spent 8+ hours coming up with a solution - only to find a video of someone solving the problem in 5 minutes!