Posted on Jul 16, 2022

Advent of Code problems can seem daunting at first, especially if you’re using a new language to solve them. They also get progressively harder as the month goes on.

Premature optimisation is a bad idea

This is a general rule in programming, and it applies here. Unless you are playing Code Golf, don’t try and come up with an optimised solution (e.g. in terms of source code length) on your first attempt. Bear in mind that:

  1. If the solution takes a couple of minutes to run, you are the only person inconvenienced by this.
  2. You have the full resources of your development machine to throw at the problem - as opposed to a shared environment such as a server where you have to consider other users and systems.
  3. The idea is to solve one problem a day.

By all means go back and optimise your solution once it works, but don’t get hung up on trying to make your 2 minute solution run in 2 seconds.

Use the test input

The test input provided each day is a great way to quickly test whether you are on the right lines. It won’t tell you if your solution is optimised - your individual puzzle input is usually substantially larger than the test input - but you will get an indication of whether your algorithms are correct.

I used to jump straight to trying to solve the problem for my individual input, and I often got stuck. Problems became much easier once I started from the test input, and in most cases the code would work with my individual input without any changes. Occasionally however the test input does not include all the edge cases, and you may find that you have a solution that works on one input but not the other.

Break things down into the smallest possible steps

Break each part of the problem into its smallest possible step, and write a function to perform that step and nothing else. For example, if you have a grid of characters, write:

  1. A function to convert one line into a single dimension array.
  2. A function to convert a series of lines into a multi-dimension array (calling the previous function)

Having each step in a sepatate function makes it easier to test and debug. Once you know one function is working, you can build the next one, and if anything goes wrong you know the problem is likely to be with the latest function.

Write tests

A test suite might seem overkill for these puzzles, but one thing that catches many people out is the edge cases in either the test input or your input. Testing every single function with expected outputs means you can find the source of a problem much quicker, even though there is an initial overhead in writing the tests. I’ve generally found that the time spent writing the tests is outweighed by the time saved on debugging, especially on later puzzles.

Build data structures

The first step in every exercise is usually to read data in from a file and then convert it into a data structure. Concentrate on getting this done first, as once you have the data in a structure it can be manipulated for the rest of the challenge.

Think about data dependencies

If each line of data is independent from the others, you can read in the input file one line at a time and process it immediately. In these cases you might not even need to build a data structure if, for example, you are just counting lines matching certain criteria (this is common in early challenges).