Home

Awesome

AoC-2023

Advent of Code solutions for 2023, in Python (3.11). Code is usually not very good - I'm going for speed (points), not Employee of the Month :)

Requirements

Alas, I know I am very lazy, so I like to take shortcuts and not write extra code wherever I can. Hence, some of my solutions require extra(non-inbuilt) packages:

Common Issues

Given the speedy nature of the code, here are a few common edge cases which ignore.

Template

At some point along the way I decided that manually writing boilerplate code for each day was a waste of time, so I wrote template.py. It's hacky, and consists of getLines, timeAndPrint and timeAvgAndPrint.

The folder structure it requires is as follows:

__init__.py
template.py
inputs/
	1.txt
	2.txt
	...
1.py
2.py
...

Then, in each day's file (e.g., 1.py), add the following:

from template import getLines, timeAvgAndPrint

# ...

if __name__ == "__main__":
    someArgs, someMoreArgs = getLines(0)
    timeAvgAndPrint("Part 1", 100, partOne, someArgs, someMoreArgs)
    timeAvgAndPrint("Part 2", 100, partTwo, someArgs)

The template, although minimal, is resistant against

Solution Outlines

I'm not sure why you've read so far - but since you have, here are some outlines and rationales for my solutions, in case you're interested / need a hint.

DayNotes
1Regex is your friend. Especially in Part 2, overlapping matches is essentially cheating. :)
2
3This one was tricky. convolve2d can help you with Part 1 (use Regex to then get the numbers), since you only had to consider at least one adjacency. But for Part 2, even though the logic is similar, the strict requirement of exactly 2 numbers meant that I had to keep a dictionary of all the gears.
4Remember that Python sets have an intersection method.
5This one was also tricky. Part 1 could literally be hacked together with lists of numbers, but Part 2 required a more efficient solution. I chose IntervalTrees to simplify the numerous numbers to smaller ranges, and implemented custom methods for partial intersection and difference, since the original library does not consider these cases.
6Technically does not even require code to solve - do some maths before you dig in!
7Categorsation and comparison of hands was the key here. I chose to make a custom @dataclass, but there must be more efficient ways.
8Part 1 could be hacked together with a simple while loop, but Part 2 required some more efficiency. I chose to store length of each cycle (time taken to get to a \w{2}Z node), and find their lcm - again, try maths!
9Part one is the tail of the first sequence plus all the subsequent tails of the differences, and part two is the tail of the first minus all subsequent tails.
10Another "curve-ball in part 2". It turns out you can just count the number of "border-crossings" a point has to the left (or right), and if it is odd, that means it is inside of the shape. In fact, since the question guarentees a valid loop, you only have to look for any one of |JL. Or, if you're feeling particularly lazy, use shapely!
11The optimisation in Part 2, as before, is all about considering the empty rows and column in abstract form. Since we are essentially computing a modified cityblock considering expansion factors of empty space, the distances can be precomputed.