Advent of Code Solutions

I have set myself a personal challenge to try and get up to date with advent of code, a set of programming challenges released each December.

Each day has 2 related problems, for a total of 50 problems per year. Each button below will show my code solving that problem. Green buttons where I have solved both problems of the day, orange where I have only solved the first one and red where I haven't solved either.

2015 2016 2017 2018 2019 2020 2021 2022 2023 2024
Not started
Part 1 completed
Both parts completed
from util.input import get_input

test_input = """89010123
78121874
87430965
96549874
45678903
32019012
01329801
10456732
"""

def part_1():
    
    puzzle_input = get_input(2024, 10)

    pos_to_val = {}
    trailheads = set()
    for i, row in enumerate(puzzle_input.splitlines()):
        for j, c in enumerate(row):
            pos_to_val[(i,j)] = int(c)
            if int(c) == 0:
                trailheads.add((i,j))

    def find_reachable_peaks(current_pos):
        
        reachable_peaks = set()
        possible_steps = [
            (current_pos[0]-1, current_pos[1]),
            (current_pos[0]+1, current_pos[1]),
            (current_pos[0], current_pos[1]-1),
            (current_pos[0], current_pos[1]+1),
        ]

        for next_pos in possible_steps:
            if next_pos not in pos_to_val:
                continue

            if pos_to_val[next_pos] - pos_to_val[current_pos] != 1:
                continue
            
            if pos_to_val[next_pos] == 9:
                reachable_peaks.add(next_pos)
            else:
                reachable_peaks = reachable_peaks | find_reachable_peaks(next_pos)

        return reachable_peaks
    
    score = 0
    for trailhead in trailheads:
        score += len(find_reachable_peaks(trailhead))

    return score

def part_2():
    
    puzzle_input = get_input(2024, 10)

    pos_to_val = {}
    trailheads = set()
    for i, row in enumerate(puzzle_input.splitlines()):
        for j, c in enumerate(row):
            pos_to_val[(i,j)] = int(c)
            if int(c) == 0:
                trailheads.add((i,j))

    def count_paths(current_pos):
        
        possible_steps = [
            (current_pos[0]-1, current_pos[1]),
            (current_pos[0]+1, current_pos[1]),
            (current_pos[0], current_pos[1]-1),
            (current_pos[0], current_pos[1]+1),
        ]

        n_paths = 0
        for next_pos in possible_steps:
            if next_pos not in pos_to_val:
                continue

            if pos_to_val[next_pos] - pos_to_val[current_pos] != 1:
                continue
            
            if pos_to_val[next_pos] == 9:
                n_paths += 1
            else:
                n_paths += count_paths(next_pos)

        return n_paths
    
    score = 0
    for trailhead in trailheads:
        score += count_paths(trailhead)

    return score