This will be a small conclusion on my experience working of the advent of code challenge this year. I managed to finish all the problems on the 27th of December. My point was not to race for the 100 first places as other do, but simply complete the problems, which is why I was completing them the morning after they were posted, and didn't mind spending a little more time, especially since some of the problems were pretty complicated. I completed all the problems in 1621th place.
My code for all the problems, including unit tests and data providers for input parsing is available here.
Which problems gave me more trouble?
- 12: The second part for this problem requires calculating a large number of generations and I didn't initially think about looking at what is actually happening after each generation so I initially tried to make it work for the full fifty billion generations. The solution was to find a pattern to reduce the number of iterations to calculate.
- 15: I initially put this one aside as it seemed to take a lot of time to code (and I was right). The problem isn't difficult, but there are a lot of business rules in the description and it's easy to misread or misunderstand one or two.
- 18: The second part for this problem also requires calculating a large number of generations. As for problem 12, I didn't start looking at the actual data to find a pattern which could be used to calculate the solution a lot more efficiently.
- 19: The second part requires reverse engineering the code, and I initially didn't think about that.
- 23: The second part requires finding a point in a very large space that touches the most range "spheres". After a couple of attempts at calculating it, I ended up going on the subreddit for some help and took a solution from there. This is the only problem where I had to look for a solution.
So what did I learn from these problems?
If you want to compete in the race, you need to start the moment the problem goes up and don't think about writing clean code (at least until you've entered your answers). Most of the problems can be solved with less than 100 lines of code in most languages so it's still a manageable size for code you're going to work on only for a couple of minutes or hours. For the problems with more rules (like 15 and 24), I think it starts to become more important to write clean code so you can easily fix the rules to match the problem description.
Units tests were very useful to me, especially since all the problems give some simpler cases that you can use as test cases. For programmers that are used to work with test driven development, this doesn't really slow them down, but some of the test cases took me a lot of time to setup, mainly because I decided to split the input reading from the problem solving, which meant I had to write my test cases using a mock object and mocking the data read instead of simply reading from a different file or starting with a different string or string array. Splitting both helped to solved the problems, because I didn't have to think about input parsing at the same time but it did add a little more work as I had to create more tests and classes for the data providers I created.
What would I change next time?
Working with C# and writing clean solutions was a very good exercise for the blog, but did require a lot more time to solve some of the problems. A lot of the problems require working with matrices and there are some way better languages to do that than C# (like Python or MatLab/Octave). All in all I think Python would probably be one of the best languages to solve these problems: it has a simple syntax which makes it easy to write small programs, it has powerful libraries like SciPy, NumPy, Z3 and many more which can help solve a lot of the problems, it's efficient enough that most solutions won't require minutes to compute and input reading is easy enough that you won't lose time with it.
Thinking outside the box earlier. If the problem requires running a lot of iterations, it's probably because there's a pattern you need to find. If the problem gives you code, you might need to reverse engineer it. If the problem makes you work with strings and characters, don't change it to lists of enums, it just takes too much time for nothing.