Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/cj81499/advent-of-code/llms.txt

Use this file to discover all available pages before exploring further.

Advent of Code 2025 is the most recent event in this repository. As of the current snapshot, 12 days are covered — all with both parts fully solved — spanning a wide variety of puzzle types including string parsing, column-wise arithmetic, range merging, graph path-counting, and computational geometry.
Puzzle inputs are personal and are not included in the repository. To run solutions against your own input, use aocd after setting your session cookie. See the Solution Structure page for full setup instructions.

Progress Table

DayTitlePart 1Part 2Tests
01Secret Entrance
02Gift Shop
03Lobby
04Printing Department
05Cafeteria
06Trash Compactor
07Laboratories
08Playground
09Movie Theater
10Factory
11Reactor
12Christmas Tree Farm

Personal Leaderboard

Times are relative to puzzle unlock (midnight EST). Entries marked >24h indicate the puzzle was solved more than a day after release.
Day   -Part 1-   -Part 2-
 12   10:14:58   10:15:36
 11   00:12:23   00:15:40
 10       >24h       >24h
  9   07:39:49   08:48:10
  8   07:07:48   07:14:51
  7   16:26:08   16:46:26
  6   04:08:11   04:23:53
  5   02:28:26   02:57:32
  4   02:58:44   03:03:19
  3   01:51:07   02:08:59
  2   04:18:34   04:24:54
  1   01:17:13   01:21:42

Notable Puzzles

Day 6 — Trash Compactor

Day 6 involves evaluating arithmetic problems laid out in a grid where the columns themselves encode the operands and the operator. The solution transposes the input to work column-by-column, parsing + and * operators from the last row of each column group. Part 1 applies the operator row-by-row (treating each row as an independent integer), while Part 2 concatenates each column into a single large number before applying the same operator. The use of Python’s zip(*it, strict=True) transpose idiom and a StrEnum-based Operator abstraction keeps both parts neatly unified.
def part_1(txt: str) -> int:
    return sum(map(Problem.solve_1, parse_problems(txt)))

def part_2(txt: str) -> int:
    return sum(map(Problem.solve_2, parse_problems(txt)))

Day 9 — Movie Theater

Day 9 is a computational-geometry puzzle. Points are parsed from the input and treated as vertices of a polygon. Part 1 finds the pair of points that forms the largest axis-aligned rectangle, regardless of containment. Part 2 adds the constraint that the rectangle must lie inside the polygon formed by all the points — solved elegantly using the Shapely library’s Polygon.contains() check. This is a great example of reaching for a well-established geometry library rather than re-implementing containment tests from scratch.
def part_2(txt: str) -> int:
    points = tuple(map(parse_point, txt.splitlines()))
    region = shapely.Polygon(points)
    return max(area(r) for r in itertools.combinations(points, r=2) if region.contains(rectangle(r)))

Day 11 — Reactor

Day 11 presents a directed-graph path-counting problem. Given a device graph where each node has a set of named outputs, Part 1 counts the number of distinct paths from "you" to "out". Part 2 adds the requirement that every path must pass through both a "fft" node and a "dac" node before reaching "out". The solution uses @functools.cache to memoize recursive path counts, carrying seen_fft and seen_dac boolean flags through the recursion to avoid redundant re-computation. The Part 2 traversal starts from "svr" (the entry node in the actual puzzle input).
@functools.cache
def count_paths(current: str, *, seen_fft: bool, seen_dac: bool) -> int:
    if current == "out":
        return 1 if seen_fft and seen_dac else 0
    seen_fft = seen_fft or current == "fft"
    seen_dac = seen_dac or current == "dac"
    f = functools.partial(count_paths, seen_fft=seen_fft, seen_dac=seen_dac)
    return sum(map(f, attached_outputs[current]))

return count_paths("svr", seen_fft=False, seen_dac=False)

Build docs developers (and LLMs) love