Skip to content

AOC 2024, Day 03: Mull It Over

Day 3 of Advent of Code 2024, Mull It Over, is all about parsing and interpreting a simulated computer memory dump. This puzzle introduces conditional execution and multiplication operations, blending regex wizardry with state management.

Elf Shenanigans

The input consists of lines representing operations on a simulated memory:

  1. mul(x, y): Multiply x and y, and add the result to the total.
  2. do(): Enable operations.
  3. don't(): Disable operations.

Part 1: Basic Computation

For the first part, we simply compute the total result by summing the products of all mul(x, y) operations. There are no conditional statements; every operation is applied.

Part 2: Conditional Execution

In the second part, the do() and don't() commands toggle whether subsequent operations are executed. When do() is called, operations resume as normal; when don't() is called, operations are ignored until a do() command appears again.

Santa's Ingenious Solutions

using System.Text.RegularExpressions;
using AdventOfCode.Lib;
using State = (bool Enabled, long Total);

namespace AdventOfCode.Y2024;

[AocPuzzle(2024, 3, "Mull It Over", "C#")]
public sealed partial class Day03 : IAocDay<long>
{
    public static long Part1(AocInput input) =>
        input.Text.Pipe(text => ComputerMemory().Matches(text).Sum(Instructions));

    public static long Part2(AocInput input) => input.Text
        .Pipe(text => ComputerMemoryWithConditionals().Matches(text)
            .Aggregate(
                new State(true, 0),
                (state, m) => m.Value switch
                {
                    "do()" => state with { Enabled = true },
                    "don't()" => state with { Enabled = false },
                    _ when state.Enabled => state with { Total = state.Total + Instructions(m) },
                    _ => state
                }
            )
        )
        .Pipe(state => state.Total);

    private static int Instructions(Match m) =>
        int.Parse(m.Groups[1].Value) * int.Parse(m.Groups[2].Value);

    [GeneratedRegex(@"mul\((\d+),(\d+)\)", RegexOptions.Compiled | RegexOptions.NonBacktracking)]
    private static partial Regex ComputerMemory();

    [GeneratedRegex(@"do\(\)|don't\(\)|mul\((\d+),(\d+)\)", RegexOptions.Compiled | RegexOptions.NonBacktracking)]
    private static partial Regex ComputerMemoryWithConditionals();
}
open System.Text.RegularExpressions
open AdventOfCode.Lib

[<AocPuzzle(2024, 3, "Mull It Over", "F#")>]
module Fay03 =

    [<Struct>]
    type State = { Enabled: bool; Total: int64 }

    let instructions (m: Match) : int64 =
        int64 (m.Groups[1].Value) * int64 (m.Groups[2].Value)

    let conditionalInstructions (state: State) (m: Match) =
        match m.Value with
        | "do()" -> { state with Enabled = true }
        | "don't()" -> { state with Enabled = false }
        | _ when state.Enabled -> { state with Total = state.Total + instructions m }
        | _ -> state

    let part1 (input: AocInput) : int64 =
        input.Text |> Regex(@"mul\((\d+),(\d+)\)").Matches |> Seq.sumBy instructions

    let part2 (input: AocInput) : int64 =
        input.Text
        |> Regex(@"do\(\)|don't\(\)|mul\((\d+),(\d+)\)").Matches
        |> Seq.fold conditionalInstructions { Enabled = true; Total = 0 }
        |> _.Total
from aoc.core import AocInput
from dataclasses import dataclass
from functools import reduce
from typing import Match
import re


@dataclass(frozen=True, slots=True)
class State:
    enabled: bool
    total: int


def instructions(m: Match) -> int:
    return int(m.groups()[0]) * int(m.groups()[1])


def conditional_instructions(state: State, m: Match) -> State:
    match m.group(0):
        case "do()":
            return State(True, state.total)
        case "don't()":
            return State(False, state.total)
        case _ if state.enabled:
            return State(state.enabled, state.total + instructions(m))
        case _:
            return state


def part1(input: AocInput) -> int:
    return sum(instructions(m) for m in re.finditer(r"mul\((\d+),(\d+)\)", input.text))


def part2(input: AocInput) -> int:
    state = reduce(
        conditional_instructions,
        [m for m in re.finditer(r"do\(\)|don't\(\)|mul\((\d+),(\d+)\)", input.text)],
        State(True, 0),
    )
    return state.total

Santa's & Elves' Reflections

Day 3 of Advent of Code 2024 introduced a fun mix of parsing, conditional logic, and basic arithmetic. The challenge lay in correctly interpreting the state changes introduced by do() and don't() commands while processing the input.

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