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:
A | src/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)