advent_of_code_2022

My (attempted) solutions to the 2022 Advent of Code
git clone https://git.eamoncaddigan.net/advent_of_code_2022.git
Log | Files | Refs | README

commit 3ae71a1a33ea04c65ce374ba6f50842a30c15ece
parent d80bf49b1568fcee28bddd26f667a5de50943b16
Author: Eamon Caddigan <eamon.caddigan@gmail.com>
Date:   Sun, 11 Dec 2022 14:57:27 -0800

Solution to day 11, part 1.

7 minutes after the "deadline". :(

Diffstat:
Asrc/day_11.jl | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 155 insertions(+), 0 deletions(-)

diff --git a/src/day_11.jl b/src/day_11.jl @@ -0,0 +1,155 @@ +#!/usr/bin/env julia +# https://adventofcode.com/2022/day/11 +using AdventOfCode + +example = readlines(IOBuffer(""" + Monkey 0: + Starting items: 79, 98 + Operation: new = old * 19 + Test: divisible by 23 + If true: throw to monkey 2 + If false: throw to monkey 3 + + Monkey 1: + Starting items: 54, 65, 75, 74 + Operation: new = old + 6 + Test: divisible by 19 + If true: throw to monkey 2 + If false: throw to monkey 0 + + Monkey 2: + Starting items: 79, 60, 97 + Operation: new = old * old + Test: divisible by 13 + If true: throw to monkey 1 + If false: throw to monkey 3 + + Monkey 3: + Starting items: 74 + Operation: new = old + 3 + Test: divisible by 17 + If true: throw to monkey 0 + If false: throw to monkey 1""")) +input = readlines("data/day_11.txt") + +# Parsing this input is going to be a job, so I'm going to give myself +# permission to write as many tiny functions as I want to (easier to debug). + +module MonkeyBusiness + mutable struct Monkey + id::Int + items::Vector{Int} + operation::AbstractString + divisible::Int + throw_id::Tuple{Int,Int} + considerations::Int + end + + # This parses the text and creates a Monkey. Not sure if this is the normal + # Julia approach, but outer constructors are so flexible it seems + # reasonable? + function Monkey(monkeytext::Vector{<:AbstractString}) + monkeyregexes = [ + r"^Monkey (\d+):$", + r"^ Starting items: ([0-9, ]*)$", + r"^ Operation: new = (.*)$", + r"^ Test: divisible by (\d+)$", + r"^ If true: throw to monkey (\d+)$", + r"^ If false: throw to monkey (\d+)$" + ] + monkeymatches = map(match, monkeyregexes, monkeytext) + @assert !any(map(isnothing, monkeymatches)) + + Monkey( + parse(Int, monkeymatches[1].captures[1]), + parse.(Int, split(monkeymatches[2].captures[1], ", ")), + monkeymatches[3].captures[1], + parse(Int, monkeymatches[4].captures[1]), + ( + parse(Int, monkeymatches[5].captures[1]), + parse(Int, monkeymatches[6].captures[1]) + ), + 0 + ) + end + + """ + Apply the operation to see how the worry level changes. + + This is a hacky/brittle approach! But it works for the little code puzzle. + """ + function monkeyinspection(monkey::Monkey, worry::Int) + operation = replace(monkey.operation, "old" => worry) + eval(Meta.parse(operation)) + end + + """ + Test worry level and return the id of the monkey that will receive the item. + """ + function monkeytest(monkey::Monkey, worry::Int) + worry % monkey.divisible == 0 ? monkey.throw_id[1] : monkey.throw_id[2] + end + + """ + Process one monkey's turn. + """ + function monkeyturn!(monkey::Monkey, + monkeys::Dict{Int, Monkey}) + while !isempty(monkey.items) + item = popfirst!(monkey.items) + item = monkeyinspection(monkey, item) + item รท= 3 + push!(monkeys[monkeytest(monkey, item)].items, item) + monkey.considerations += 1 + end + end + + function monkeyrounds!(monkeys::Dict{Int, Monkey}, numrounds::Int) + monkeyids = sort(collect(keys(monkeys))) + for _ = 1:numrounds + for monkeyid = monkeyids + monkeyturn!(monkeys[monkeyid], monkeys) + end + end + end + + """ + Split the input lines into (unparsed text representations) of each monkey. + + Returns an array of string arrays. + """ + function split_monkeys(input::Vector{<:AbstractString}) + monkeystart = 1 + monkeys = Vector{Vector{<:AbstractString}}() + for monkeyend = [findall(==(""), input); lastindex(input)+1] + push!(monkeys, input[monkeystart:monkeyend-1]) + monkeystart = monkeyend+1 + end + monkeys + end + + """ + Read the input and return a dictionary of monkeys. + """ + function makemonkeys(input::Vector{<:AbstractString}) + monkeys = map(Monkey, split_monkeys(input)) + Dict(zip([m.id for m in monkeys], monkeys)) + end +end + +function part_1(input) + monkeys = MonkeyBusiness.makemonkeys(input) + MonkeyBusiness.monkeyrounds!(monkeys, 20) + reduce( + *, + partialsort(map(x->x.considerations, values(monkeys)), + 1:2, rev = true) + ) +end +@assert part_1(example) == 10605 +@info part_1(input) + +function part_2(input) + nothing +end +@info part_2(input)