Just as I did last year, and the year before, I competed in the local Advent of Code competition this year. I had a lot of fun doing this year’s puzzles and even managed to get on the global top 100 a few times!


Day 1:

Day 1 part one was, of course, pretty easy, typical for day 1, but part two was a bit of a suprise with overlapping find & replace.

Day 2:

Day 2 was honestly easier than day 1, another pretty easy task (with somewhat annoying parsing…).

Day 3:

Day 3 wasn’t so fun for me, I did pretty badly compared to my fellow competitors in MN and at the time I was pretty confused by the problem, it hit pretty hard for day 3, but part 2 was easy.

Day 4:

Probably my favorite problem of the first 5 because it was a great teaching tool at one of our computer science club meetings as a practical example of how sets can be used in Python, otherwise pretty simple and also a good introductory DP problem, if you can even call it that.

Day 5:

Wow, this was a doozy for only day 5! Part one was a fun implementation task but part 2 really threw me for a loop with the range operations. I decided to do a bit more practice with range/interval manipulation after this problem.

Day 6:

By all means the easiest problem of them all, easy enough to solve with a scientific calculator, part 2 wasn’t much harder and ran perfectly fine even with my dumb brute force solution.

Day 7:

My first spot on the leaderboard!! I credit Project Euler #54 - Poker Hands with my success on this problem, I didn’t make the p1 leaderboard (#282) but somehow managed to get #94 on part 2! functools.cmp_to_key was essential for this problem.

Day 8:

The first graph problem! how fun! I’m glad I jumped directly to cycle finding & LCM instead of manual input analysis and thanks to that I managed to rank much better on part 2 than on part 1!

Day 9:

I was honestly quite confused by the problem description, but once I got it, parts 1 and 2 were both a pretty straightforward implementation task.

Day 10:

A pretty tough puzzle for day 10, but nonetheless quite fun. I took too long on part 1 because I messed up my adjacency table for the pipe types, but did a little bit better on part 2 thanks to remembering the even–odd rule.

Day 11:

Another problem that I overthought and didn’t do so well on… I guess my brain just immediately jumped to BFS when I saw the .s and #s… I had to totally redo my solution for part 2 but offsetting the coordinates based on empty rows/cols was pretty straightforward and satisfying.

Day 12:

Probably the first serious DP problem of the year, for part 1 I did a naive brute force just checking all of the possible values, which worked fine. I totally redid my solution for part 2 after working out a better DP solution, not very elegant but worked fine.

Day 13:

Flashback to 2021 day 13! Working out the folding/mirror checking was a bit of a chore for me at least, but after that was done, part 2 was an easy (and suprisingly fast) brute force.

Day 14:

More cycle finding! And a fun simulation! I didn’t really have a pre-implemented cyclefinding tool for part 2, so I just plotted the changing score and did it semi-manually, which suprisingly worked first try!

Day 15:

My second leaderboard spot! #41 on part 1!! A pretty basic implementation task in my opinion. Part 2 was a bit more interesting but also just implementation, I could certainly have done it in a more clever way but oh well.

Day 16:

Without a doubt one of my favorite days this year! What a fun simulation with a great visualization! And to top it off, part 2 was nice and easy. I initially jumped to recursion, but with the limitations of Jupyter notebooks (max 1000 recursion depth or the kernel crashes) using BFS was fine.


Day 17:

A pretty tricky graph problem indeed! The map immediately reminded me of 2021 Day 15 (Chiton) but the max-3-straight constraint is really interesting! I realize that there is probably another common way of doing this (keeping track of distance walked straight) but I’m glad I chose to implement it directly in the neighbor generation, because it made part 2 (min 4 steps, max 10) much easier than with the alternative.

Part 1 solution
Part 2 solution

Day 18:

I was certainly not expecting to have to use some obscure geometry formulas during AoC! Part 1 was fun, I just used a basic floodfill, but part 2 required a bit of research: luckilly I found the shoelace formula pretty quickly and implemented it just in time to beat some of my other local competitors. Thanks Google! After looking at the subreddit, I saw a lot of other people used geometry libraries like shapely, definitely something to add to my toolbelt for future years!

Day 19:

Well, part 1 was fun at least! Finally succombed to using eval to parse the input and managed to get #80 on the global leaderboard!!! Unfortunately I spent way too long thinking I was clever trying to do part 2 with z3 and totally forgot about using interval division until I got stuck… A satisfying solution nonetheless, but I’m disapointed I spent so much time on a fruitless approach.

Day 20:

What a fun and well-made problem! I immediately jumped on using an “event queue” for part 1 and after a bit of debugging, it worked just fine. Part 2 was pretty fun and after realizing it was taking way too long to process, I plotted my input with the ever-useful graphviz and figured out the cycle-finding pretty quick! I usually don’t really like puzzles that require manual input analysis, but this year I’ve become a bit more used to it, especially with the help of visualization tools.

Day 21:

Nice BFS for part 1, but gosh… I struggled with part 2 for a long time… and what I eventually came up with (polynomial fitting for the first couple of repetitions) just feels like a hack. Not my favorite day by far!

Day 22:

Yay! I’ve always wanted to play 3D sand Jenga! I really enjoyed how the simulation of the bricks turned into a graph problem in part 2. Having already built the adjacency lists (above and below) in part 1 made part 2 a breeze!

Day 23:

Probably my favorite problem this year! First of all, it’s a graph problem… with a satisfying solution… and a great visualization!!! Before this I had never really investigated finding max-length paths on a graph before, and I didn’t even realize it was a NP-complete problem until after the fact! I started out with something like Dijkstra’s but ended up with a weird queue-based implementation of DFS for part 1. For part 2 I immediately jumped on the idea of “compressing” the maze into a smaller weighted graph after looking at the input and just reused my part 1 solution on the compressed graph!

Compressed Graph
Maze sections to be compressed

Day 24:

Part 1 was super annoying for me, I could have saved a lot of time if I had caught a stupid error earlier: My intersection finding code was correct, but on getting the wrong answer no less than 4 times, I spend an aggravating half hour debugging only to find that I had swapped a * for a + in my dot product code… Honestly, part 2 was much more fun! What a suprise! With my previous experience using z3, it was pretty easy to set up and solve the system of equations.


Day 25:

55th place! What a way to finish it all off!!! I did 2018 day 25 a few minutes before this puzzle as practice and I just copy-pasted my DSU/union find code over and used it to find the groups! To find the 3 connections (apparently it’s called minimum-edge-cut), I just plotted the graph with networkx and copied down the node names! I got 49th place for part 2 (well… it’s just pressing a button) and I feel great knowing that I’m the 49th person to complete the entire Advent of Code 2023!