Initial commit: AoC solutions 2023-2025

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Samuel Enocsson
2025-12-02 10:39:09 +01:00
commit 549f0c4382
90 changed files with 17360 additions and 0 deletions
+17
View File
@@ -0,0 +1,17 @@
"""Advent of Code 2025 utilities."""
from .helpers import (
read_input,
read_lines,
read_ints,
read_grid,
read_blocks,
)
__all__ = [
"read_input",
"read_lines",
"read_ints",
"read_grid",
"read_blocks",
]
+52
View File
@@ -0,0 +1,52 @@
"""Input parsing and common utilities for Advent of Code."""
from pathlib import Path
from typing import Callable, Any
import numpy as np
def get_input_path(day: int) -> Path:
"""Get the path to input file for a given day."""
return Path(__file__).parent.parent / "inputs" / f"day{day:02d}.txt"
def read_input(day: int) -> str:
"""Read raw input for a given day."""
return get_input_path(day).read_text().strip()
def read_lines_and_split(day: int, split: str) -> list:
"""Read input as lines, optionally parsing each line."""
return [line for line in read_input(day).split(split)]
def read_lines(day: int, parser: Callable[[str], Any] = str) -> list:
"""Read input as lines, optionally parsing each line."""
return [parser(line) for line in read_input(day).splitlines()]
def read_ints(day: int) -> list[int]:
"""Read input as list of integers (one per line)."""
return read_lines(day, int)
def read_grid(day: int, dtype=str) -> np.ndarray:
"""Read input as a 2D numpy grid of characters or digits."""
lines = read_input(day).splitlines()
if dtype == int:
return np.array([[int(c) for c in line] for line in lines])
return np.array([list(line) for line in lines])
def read_blocks(day: int) -> list[str]:
"""Read input split by blank lines (paragraphs)."""
return read_input(day).split("\n\n")
# Common grid directions
DIRS_4 = [(0, 1), (1, 0), (0, -1), (-1, 0)] # right, down, left, up
DIRS_8 = DIRS_4 + [(1, 1), (1, -1), (-1, 1), (-1, -1)] # + diagonals
# Direction mappings
DIR_MAP = {
"R": (0, 1), "L": (0, -1), "U": (-1, 0), "D": (1, 0),
">": (0, 1), "<": (0, -1), "^": (-1, 0), "v": (1, 0),
}
+62
View File
@@ -0,0 +1,62 @@
"""Day 1: Advent of Code 2025."""
from aoc import read_lines, read_input
def get_pointer(dial, move, pointer):
dir = move[0]
n = int(move[1:])
if dir == 'L':
pointer = (pointer - n) % len(dial)
elif dir == 'R':
pointer = (pointer + n) % len(dial)
return dial[pointer]
def part1(data):
dial = range(100)
password = 0
pointer = 50
for line in data:
move = line.strip()
pointer = get_pointer(dial, move, pointer)
if pointer == 0:
password += 1
return password
def get_new_index(dial, move, pointer):
dir = move[0]
n = int(move[1:])
if dir == 'L':
pointer = (pointer - n)
elif dir == 'R':
pointer = (pointer + n)
return pointer
def part2(data):
dial = range(100)
password = 0
pointer = 50
for line in data:
move = line.strip()
if len(move[1:]) > 2:
n = int(move[1:][:-2])
move = move[0] + move[-2:]
password += n
idx = get_new_index(dial, move, pointer)
if pointer != 0 and (idx < 0 or idx > len(dial)):
password += 1
pointer = idx % len(dial)
if pointer == 0:
password += 1
return password
if __name__ == "__main__":
data = read_lines(1) # or read_input(1), read_ints(1), read_grid(1)
print(f"Part 1: {part1(data)}")
print(f"Part 2: {part2(data)}")
+52
View File
@@ -0,0 +1,52 @@
from aoc import read_lines, read_input
from aoc.helpers import read_lines_and_split
def part1(data):
ids = []
for line in data:
n = line.strip().split("-")
r = range(int(n[0]), int(n[1]) + 1)
for rr in r:
ss = str(rr)
if (len(ss) % 2) == 0:
f = ss[:len(ss)//2]
s = ss[len(ss)//2:]
if f == s:
ids.append(rr)
return sum(ids)
def find_pattern(s):
if len(s) < 2:
return False
n = int(s)
if all_same(n):
print(f"Found pattern: {n}")
return True
for i in range(2, len(s) // 2 + 1):
pattern = s[:i]
repeated = pattern * (len(s) // i)
if str(repeated) == s:
print(f"Found pattern: {pattern} in {s}")
return True
return False
def all_same(n):
return len(set(str(n))) == 1
def part2(data):
ids = []
for line in data:
n = line.strip().split("-")
r = range(int(n[0]), int(n[1]) + 1)
for rr in r:
ss = str(rr)
if find_pattern(ss):
ids.append(rr)
return sum(ids)
if __name__ == "__main__":
data = read_lines_and_split(2, ",") # or read_input(2), read_ints(2), read_grid(2)
print(f"Part 1: {part1(data)}")
print(f"Part 2: {part2(data)}")
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
52500467-52574194,655624494-655688785,551225-576932,8418349387-8418411293,678-1464,33-79,74691-118637,8787869169-8787890635,9898977468-9899009083,548472423-548598890,337245835-337375280,482823-543075,926266-991539,1642682920-1642753675,3834997-3940764,1519-2653,39697698-39890329,3-21,3251796-3429874,3467-9298,26220798-26290827,80-124,200638-280634,666386-710754,21329-64315,250-528,9202893-9264498,819775-903385,292490-356024,22-32,2663033-2791382,133-239,56514707-56704320,432810-458773,4949427889-4949576808
+10
View File
@@ -0,0 +1,10 @@
[project]
name = "aoc2025"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"numpy",
]
[tool.uv]
dev-dependencies = []