Jesper Dramsch , , read in 3 minutes

Cracking some advent of codes!

What is Advent of Code?

In this little series, I want to write about the thought processes I have behind solving the puzzles presented in Advent of Code.

During the Advent of Code small coding puzzles are presented with varying levels of difficulty. They're always Christmas-themed text puzzles where you help elves out of some mess to save the holidays. The puzzles are deliberately ambiguous to not bias puzzlers into a certain solution, they always have an example input in the text to explain some details and an input file for each day that comes in the form of a text file you can download. The solution is a simple number or a string you enter, which is checked by the website automatically. After you finish part 1, part 2 unlocks, which is a variation on part 2. This can be a little twist on part 1 or a large twist that changes the problem formulation into a problem that would take brute force solutions to compute longer than the heat death of the universe would take.

Find my solutions here: github.com/JesperDramsch/advent-of-code

These descriptions won't be a perfect narrative, but rather how I think about these problems and where I see different solutions. I apologise for the possibility of rambling!

The example input

The name is "Tuning Troubles" and this as the only example? We're cracking codes today!

mjqjpqmgbljsphdztnvjfqwrcgsmlb

Let's explore!

The implementation

So we need to find the first "unique" start marker in a stream of data.

It feels like part 1 is fairly easy to solve and I have no idea what part 2 could be, so I don't want to optimise early for what I anticipate to come.

Don't over-complicate, when the specification is really that simple.

I'm going back to sets, because the task is to find non-unique items. So I'd easily have the length of just the variable, instead of having to come up with some logic of comparing everything to everything.

(x, set(day.data[x-i] for i in range(4))) for x in range(3, len(day.data))

Part Deux

Keeping it simple turned out well, some refactoring into a function, and I was able to abstract both marker finders into a one-liner

def find_marker(data, length):
    for x in range(length - 1, len(data)):
        items = set(data[x - length : x])
        if len(items) == length:
            return x

When these get long enough, it'd be smart to build in a way to skip indices, once we have a duplicate. But this ran quick enough, so I'll keep it for now, because it'd also imply a pretty significant change away from the set logic.

Error Log

A couple of indexing errors in this one, the usual...

  • Got an empty list, but caught that early, because I didn't want to mess up with this new data. There are no splits and it's a singular string, so I figured my standard loader might not love it.
  • Put the data mjqjpqmgbljsphdztnvjfqwrcgsmlb as the solution to the test example. That was a simple enough brain fart.
  • day.data = [i, set(day.data[x-i] for i in range(4)) for x in range(3, len(day.data))] SyntaxError: invalid syntax, forgot parentheses
  • IndexError: list index out of range messing up the index shifting in the stream
  • Off-by-one error, because the puzzle expects 1-indexed numbers.
  • Didn't change the variable name from day.data to data when refactoring into a function for part 2.