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.
		
		
		
		
		
			
		
			
				
					
					
						
							116 lines
						
					
					
						
							3.2 KiB
						
					
					
				
			
		
		
	
	
							116 lines
						
					
					
						
							3.2 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}; part=1)
 | 
						|
  modulus = prod(m.test_divisor for m in monkeys)
 | 
						|
  for m in monkeys
 | 
						|
    for item in m.items
 | 
						|
      new_value = m.op(item, m.op_value)
 | 
						|
      if part == 1
 | 
						|
        new_value = Int(floor(new_value / 3))
 | 
						|
      else
 | 
						|
        new_value = mod(new_value, modulus)
 | 
						|
      end
 | 
						|
      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, part=1)
 | 
						|
  for _ in 1:rounds
 | 
						|
    simian_shenanigans(monkeys, part=part)
 | 
						|
  end
 | 
						|
  return prod(sort([m.inspected for m in monkeys])[end-1:end])
 | 
						|
end
 | 
						|
 | 
						|
function test()
 | 
						|
  @testset "monkey business 1" verbose=true begin
 | 
						|
    @test monkey_business(read_monkeys("example.txt")) == 10605
 | 
						|
    @test monkey_business(read_monkeys("input.txt")) == 64032
 | 
						|
  end
 | 
						|
  @testset "monkey business 2" verbose=true begin
 | 
						|
    @test monkey_business(
 | 
						|
            read_monkeys("example.txt"), rounds=10000, part=2) == 2713310158
 | 
						|
    @test monkey_business(
 | 
						|
            read_monkeys("input.txt"), rounds=10000, part=2) == 12729522272
 | 
						|
  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 1 ",
 | 
						|
            monkey_business(monkeys, rounds=20, part=1))
 | 
						|
 | 
						|
    monkeys = read_monkeys(infile)
 | 
						|
    println("monkey business 2 ",
 | 
						|
            monkey_business(monkeys, rounds=10000, part=2))
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
main()
 |