Advent of Code 2022
Published November 26, 2022
Another year, another 25 curious code challenges from Advent of Code! This year, I'll be attempting to make as many solutions as possible something you can run right here in your browser window via PyScript.
Table of Contents
Day 0 - Testing the Machinery
In preparation for this year's AoC, I've set up a Hugo templating system to allow me to quickly write and share each day's code. The setup will look much like this, with a brief explanation here, the code below, and an option to run live demos. The get_input
function handles getting input from the textarea or file upload.
Paste Input Here:
Or upload file:
- day0.py
|
|
Day 1: Calorie Counting (Part 1)
And we're off! As common for day 1 of AoC, this puzzle is is about making sure you can read input and identify line breaks, and do some very simple parsing.
One way to solve this problem would be to calculate the sum of calories in every elf's pack, then find the max of those. Astute coders will notice that you don't need to actually hold all the packs in memory at once; you can calculate them one at a time and retain the highest value seen so far, which avoids undue memory usage. Python more-or-less does this for us if we use generator expressions for everything.
Paste Input Here:
Or upload file:
- day1_1.py
- day1_1-viz.py
|
|
|
|
Day 1: Calorie Counting (Part 2)
Another common theme with Advent of Code - part 2 on a given day will try to subvert the optimizations you may have made in part 1!
For a quick-and-dirty solution here, I'll use the sorted
function to convert our generator into a sorted list, then sum the last (largest) three elements. If this were a larger list of elements, we could come up with our own generator that injested elements from an Iterable one by one, and retained the largest three.
Paste Input Here:
Or upload file:
- day1_2.py
|
|
Day 2: Rock Paper Scissors (Part 1)
Some slightly more complicated input handling today, with some slightly more involved conditional logic to accumulate a score
It's also quite useful to me to be able to run these examples from the terminal, as well as in PyScript. If you look at the end of today's code, you'll see a use of checking whether we're running in pyodide (if 'pyodide' in sys.modules
), and chosing where to snag the input from based on that determination.
Paste Input Here:
Or upload file:
- day2_1.py
|
|
Day 2: Rock Paper Scissors (Part 2)
I fully admit to my solution here trying to be way too clever. The speediest way to solve this problem (both in execution time and in writing) would almost certainly be to create a looking table of the 9 possible input lines with their resultant scores, and just loop over the input and sum according to those scores.
That said, this is a good chance to start stirring the brain cells on another common theme in Advnent of Code challenges - using one part of the input to determine how to interpret another part of the input.
Paste Input Here:
Or upload file:
- day2_2.py
|
|
Day 3: Rucksack Reorganization (Part 1)
This is one of those neat days where one can use a neat feature of Python - set operations - to make finding common elements between two iterables fast and easy.
On a whim, I hopped on a livestream and whipped up a visualization of this part of the solution, which you can check out if you run the live examples on this page.
Paste Input Here:
Or upload file:
- day3_1.py
- day3_1-viz.py
|
|
|
|
Day 3: Rucksack Reorganization (Part 2)
Similar to part 1, part 2 is much easier if you use your chosen language's set operations to quickly narrow down the given elements to only the ones common between each trio of elves. I suppose the "gotcha" in this part is meant to catch out anyone who implemented a nested-for-loop, check-each-element-one-by-one solution to part 1.
Paste Input Here:
Or upload file:
- day3_2.py
|
|
Day 4: Camp Cleanup (Part 1)
Some year, somewhere, I shant be tricked by forgetting to convert input strings to integers.
This is not that year apparently. The provided example input works if you only compair the inputs alphanumerically, since it only uses single-digit numbers, but the real input only yields the correct solution if you remember to convert the inputs to integers.
Paste Input Here:
Or upload file:
- day4_1.py
|
|
Day 4: Camp Cleanup (Part 2)
I'm certain there's a more clever way to determine whether two ranges overlap; I've used the brute-force method to check if either of the endpoints of each pair lies within (or equals) the endpoints of the other pair. I have a feeling, from the symmetry of the boolean logic, that it could be simplified somehow, but this is functional.
Paste Input Here:
Or upload file:
- day4_2.py
|
|
Day 5: Supply Stacks (Part 1)
As I've experienced in previous years, the process of identifying a strategy or algorithm to solve a problem, and the creating the data structure for that algorithm, go hand in hand.
In today's case, the fact that the input is presented row-by-row, but the data is relevant column-by-column, means that a cerain amount of input processessing is necessary to make the data useful. But once it is, the solution is relatively straightfoward.
Paste Input Here:
Or upload file:
- day5_1.py
- day5_1-viz.py
|
|
|
|
Day 5: Supply Stacks (Part 2)
I was wondering when I would get bit by one of PyScript's core limitations (currently) - all <py-script>
tags are executed in the same global namespace. Meaning if you have two functions with the same name in two separate files/script tags, any objects whos names overlap previous tags overwrite those objects. Hence names like operateOn5_2()
to ensure the functions are unique to this day/part.
Paste Input Here:
Or upload file:
- day5_2.py
|
|
Day 6: Tuning Trouble (Part 1)
Part of the fun of Advent of Code is trying to guess what things in Part 1 of each day are going to get turned topsy-turvy in Part 2. Today's question, involving finding when elements in a sliding window are unique, lead me to a few guesses. Would there be some other criteria for determining success? Only one duplicated letter perhaps? Perhaps the window would need to ignore only its center element, or the window would jump by twos, or something.
Paste Input Here:
Or upload file:
- day6_1.py
|
|
Day 6: Tuning Trouble (Part 2)
Thankfully, it turned out part 2 made the simplest possible adjustment - the length of the window. Hence, the code for the two parts looks almost identical. I suppose the objective was to catch out anyone who "manually" checked each element of the sliding window for uniqueness against the other three.
Paste Input Here:
Or upload file:
- day6_2.py
|
|
Day 7: No Space Left on Device (Part 1)
When running into a challenge like today's, the question is always: "Should I implement my own data structure, or make use of a built-in/pre-existing module?" Today I opted for the later, and discovered the anytree package for the first time. It has all the functionality I could way - children/parent tracking, arbitrary attributes on Nodes, provision for walking/tranversing/searching the tree, importing/exporting dictionaries/JSON, symlinks... I suspect I'm going to get a lot of use out of this.
Paste Input Here:
Or upload file:
- day7_1.py
- day7_1-viz.py
|
|
|
|
Day 7: No Space Left on Device (Part 2)
Another part-2 problem which requires taking the data discovered in part 1, sorting it (by some key), and finding the smallest (largest) value, possibly beyond some threshhold. Using anytree.search.findall
makes it easy to find the folders, and sorted(key = lamabda node: node.folder_size)
allows us to sort by the relevant key.
Paste Input Here:
Or upload file:
- day7_2.py
- day7_2-viz.py
|
|
|
|
Day 8: Treetop Tree House (Part 1)
More parsing, more fun! I suspect there's some data structure that makes it simpler to iterate over both the rows and columns of a grid... or perhaps I should create my own, as that's the kind of thing that seems to come up often in Advent of Code.
Paste Input Here:
Or upload file:
- day8_1.py
- day8_1-viz.py
|
|
|
|
Day 8: Treetop Tree House (Part 2)
Figuring out all the indices, ranges, and exactly what was being asked was a bit hairy in this second part, but the ultimate stumbling block for me ended up being multiplying the running score by itself, rather than by the new trees seen in a given direction. Oops!
Paste Input Here:
Or upload file:
- day8_2.py
- day8_2-viz.py
|
|
|
|
Day 9: Rope Bridge (Part 1)
I felt quite clever during this first part of today's problem, when I noticed that, when the tail of the rope has to move, it always moves to where the head was in the previous step. This saves a fair amount of figuring out the logic of exactly where the tail moves to in each step - it can just reuse the previous position of the head, if necessary.
Paste Input Here:
Or upload file:
- day9_1.py
|
|
Day 9: Rope Bridge (Part 2)
Of course, I was being too clever by half, and the logic in part 1 doesn't hold in part two; I ended up chasing a nasty typo in the logic of determining where each tail segment moves for quite awhile. I've left my rudimentary testing code and print statements in place and commented out for illustrative purposes.
Paste Input Here:
Or upload file:
- day9_2.py
|
|
Day 10: Cathode Ray Tube (Part 1)
I had a very long dog walk this morning, during which I chose to vastly over-engineer today's problem. Partly for the fun of visualizing the solution on a quiet walk, and partly because this is the kind of problem that tends to come back in later days.
I also thoroughly type-hinted my solution, which I find tremendously helpful in keeping new data structures straight when developing them.
Paste Input Here:
Or upload file:
- day10_1.py
- day10/computer.py
- day10/parser_10_1.py
- day10/register.py
- day10/instruction.py
- day10/addition.py
- day10/noop.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Day 10: Cathode Ray Tube (Part 2)
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Vero recusandae sint illo ab ullam deserunt. Fugiat debitis, harum velit corporis facilis modi perferendis consequuntur et eaque libero rem minima voluptatum?
Paste Input Here:
Or upload file:
- day10_2.py
- day10/computer.py
- day10/screen.py
- day10/parser_10_1.py
- day10/register.py
- day10/instruction.py
- day10/addition.py
- day10/noop.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|