Ask HN: How was your Advent of Code 2018 experience?
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 ] threadI’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.
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!
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.
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.
It made me go back to Hackerrank and try a few of those out.
Plus time is always hard to find.
Fantastic learning experience.
https://github.com/meheleventyone/aoc-2018-zig
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/
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
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.
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...
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.)
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.
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.
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
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.
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!
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.)
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).
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.