You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
2.6 KiB

#!/usr/bin/env julia
using Test
mutable struct Monkey
index :: UInt
items :: Vector{Int}
op :: Function
op_value :: Int
test_divisor :: Int
test_result :: NTuple{2, UInt}
inspected :: Int
end
function parse_monkey(text)
lines = split(text, '\n')
# Monkey 0:
match_index = match(r"Monkey (\d+):", lines[1])
index = parse(UInt, match_index.captures[1])
# Starting items: 79, 98
match_items = match(r" *Starting items: (.*)", lines[2])
items_list = split(match_items.captures[1], ", ")
items = parse.(Int, items_list)
# Operation: new = old * 19
match_op = match(r" *Operation: new = old (.) (old|\d+)", lines[3])
if match_op.captures[1] == "+"
op = +
elseif match_op.captures[1] == "*"
op = *
else
throw(DomainError("Unknown op: " * match_op.captures[1]))
end
if match_op.captures[2] == "old"
op = ^
op_value = 2
else
op_value = parse(Int, match_op.captures[2])
end
# Test: divisible by 13
match_test = match(r" *Test: divisible by (\d+)", lines[4])
test_divisor = parse(Int, match_test.captures[1])
# If true: throw to monkey 1
# If false: throw to monkey 3
match_true = match(r" *If true: throw to monkey (\d+)", lines[5])
match_false = match(r" *If false: throw to monkey (\d+)", lines[6])
test_result = (parse(UInt, match_true.captures[1]) + 1,
parse(UInt, match_false.captures[1]) + 1)
return Monkey(index, items, op, op_value, test_divisor, test_result, 0)
end
function read_monkeys(infile)
open(infile) do io
monkey_strings = split(read(io, String), "\n\n")
return parse_monkey.(monkey_strings)
end
end
function simian_shenanigans(monkeys :: Vector{Monkey})
for m in monkeys
for item in m.items
new_value = m.op(item, m.op_value)
new_value = Int(floor(new_value / 3))
new_monkey = (mod(new_value, m.test_divisor) == 0
? m.test_result[1] : m.test_result[2])
push!(monkeys[new_monkey].items, new_value)
m.inspected += 1
end
empty!(m.items)
end
end
function monkey_business(monkeys; rounds=20)
for _ in 1:rounds
simian_shenanigans(monkeys)
end
return prod(sort([m.inspected for m in monkeys])[end-1:end])
end
function test()
@testset "monkey business" verbose=true begin
@test monkey_business(read_monkeys("example.txt")) == 10605
@test monkey_business(read_monkeys("input.txt")) == 64032
end
end
function main()
if size(ARGS, 1) == 0
test()
else
infile = ARGS[1]
println("infile = ", infile)
monkeys = read_monkeys(infile)
display(monkeys)
println()
println("monkey business ", monkey_business(monkeys))
end
end
main()