Skip to content

AOC 2024, Day 05: Print Queue

Day 5 of Advent of Code 2024, Print Queue, brings us to the North Pole's printing department, where safety is key as the Elves prepare for the sleigh launch. Our task is to ensure that updates to the safety manual are printed in the correct order. The challenge combines order validation, sorting, and some arithmetic to guarantee a smooth process.

Elf Shenanigans

Part 1: Checking the Order

For the first part, we verify that the updates follow the specified ordering rules. For each rule X|Y, page X must appear before page Y. Once the updates are validated, we calculate the middle page number of the valid updates and sum them.

Part 2: Fixing the Order

For the second part, we need to reorder the updates that don't follow the rules. After applying the correct order, we, like in part 1, find the middle page number for each corrected update and sum them up.

Santa's Ingenious Solutions

using Pages = string[];
using PageUpdates = string[][];
using PagePrecedenceRules = System.Collections.Generic.Comparer<string>;

namespace AdventOfCode.Y2024;

[AocPuzzle(2024, 5, "Print Queue", "C#")]
public sealed class Day05 : IAocDay<int>
{
    public static int Part1(AocInput input) => 
        input.Text
            .Pipe(SleighLaunchSafetyManual)
            .Pipe(manual => manual.Updates
                .Where(pages => ElfPageSorting(manual.PrecedenceRules, pages))
                .Sum(ExtractMiddlePage)
            );

    public static int Part2(AocInput input) => 
        input.Text
            .Pipe(SleighLaunchSafetyManual)
            .Pipe(manual => manual.Updates
                .Where(pages => ElfPageSorting(manual.PrecedenceRules, pages) is false)
                .Select(pages => pages.OrderBy(p => p, manual.PrecedenceRules).ToArray())
                .Sum(ExtractMiddlePage)
            );

    private static SafetyManual SleighLaunchSafetyManual(string text)
    {
        var parts = text.Split("\n\n");
        var ordering = parts[0].Split('\n').ToHashSet();
        var updates = parts[1].Split('\n').Select(u => u.Split(',')).ToArray();
        return new SafetyManual(
            updates,
            PagePrecedenceRules.Create((p1, p2) => ordering.Contains($"{p1}|{p2}") ? -1 : 1)
        );
    }

    private static bool ElfPageSorting(PagePrecedenceRules precedenceRules, Pages pages) =>
        pages.SequenceEqual(pages.OrderBy(p => p, precedenceRules));

    private static int ExtractMiddlePage(Pages pages) => 
        int.Parse(pages[pages.Length / 2]);

    private readonly record struct SafetyManual(PageUpdates Updates, PagePrecedenceRules PrecedenceRules); 
}
open AdventOfCode.Lib

[<AocPuzzle(2024, 5, "Print Queue", "F#")>]
module Fay05 =

    type Pages = string array
    type PageUpdates = string array array
    type PagePrecedenceRules = System.Collections.Generic.Comparer<string>

    type SafetyManual = {
        Updates: PageUpdates
        PrecedenceRules: PagePrecedenceRules
    }

    let sleighLaunchSafetyManual (text: string) =
        let parts = text.Split("\n\n")
        let ordering = parts[0].Split('\n') |> Set.ofArray
        let updates = parts[1].Split('\n') |> Array.map _.Split(',')

        let precedenceRules =
            PagePrecedenceRules.Create(fun p1 p2 -> if ordering.Contains $"%s{p1}|%s{p2}" then -1 else 1)

        { Updates = updates; PrecedenceRules = precedenceRules }

    let elfPageSorting (precedenceRules: PagePrecedenceRules) (pages: Pages) =
        pages = Array.sortWith (fun p1 p2 -> precedenceRules.Compare(p1, p2)) pages

    let extractMiddlePage (pages: Pages) = int pages[Array.length pages / 2]

    let part1 (input: AocInput) =
        input.Text
        |> sleighLaunchSafetyManual
        |> fun manual ->
            manual.Updates
            |> Array.filter (elfPageSorting manual.PrecedenceRules)
            |> Array.sumBy extractMiddlePage


    let part2 (input: AocInput) =
        input.Text
        |> sleighLaunchSafetyManual
        |> fun manual ->
            manual.Updates
            |> Array.filter (fun pages -> not (elfPageSorting manual.PrecedenceRules pages))
            |> Array.map (Array.sortWith (fun p1 p2 -> manual.PrecedenceRules.Compare(p1, p2)))
            |> Array.sumBy extractMiddlePage
from aoc.core import AocInput
from dataclasses import dataclass
from functools import cmp_to_key
from typing import Callable

type Pages = list[str]
type PageUpdates = list[Pages]
type PagePrecedenceRules = Callable[[str, str], int]


@dataclass(frozen=True, slots=True)
class SafetyManual:
    updates: PageUpdates
    precedence_rules: PagePrecedenceRules


def sleigh_launch_safety_manual(text: str) -> SafetyManual:
    parts = text.split("\n\n")
    ordering = set(parts[0].split("\n"))
    updates = [u.split(",") for u in parts[1].split("\n")]
    precedence_rules = lambda p1, p2: -1 if f"{p1}|{p2}" in ordering else 1
    return SafetyManual(updates, precedence_rules)


def elf_page_sorting(precedence_rules: PagePrecedenceRules, pages: Pages) -> bool:
    return pages == sorted(pages, key=cmp_to_key(precedence_rules))


def extract_middle_page(pages: Pages) -> int:
    return int(pages[len(pages) // 2])


def part1(input: AocInput) -> int:
    manual = sleigh_launch_safety_manual(input.text)
    return sum(
        extract_middle_page(p) 
        for p in [
            p for p in manual.updates if elf_page_sorting(manual.precedence_rules, p)
        ]
    )


def part2(input: AocInput) -> int:
    manual = sleigh_launch_safety_manual(input.text)
    return sum(
        extract_middle_page(p)
        for p in [
            sorted(p, key=cmp_to_key(manual.precedence_rules))
            for p in [p for p in manual.updates if elf_page_sorting(manual.precedence_rules, p) is False]
        ]
    )

Santa's & Elves' Reflections

Day 5 of Advent of Code 2024 presents a logical challenge in dependency management and sorting. The key to solving both parts lies in understanding how to validate page orders and using sorting techniques for reordering. With the right approach, we've ensured that the North Pole's safety manuals are properly updated for the upcoming sleigh launch!

Check out the repository for solutions: AdventOfCode & AdventOfCode.Lib.