Monkey in the Middle
Description: https://adventofcode.com/2022/day/11
open System.IO
open System
let mapOperation (parts: string[]) =
let left = parts[0]
let sign = parts[1]
let right = parts[2]
let operation: (int64 -> int64 -> int64) =
match sign with
| "+" -> (+)
| "*" -> (*)
| x -> failwith $"Unknown sign {x}"
if (left = "old") then
if (right = "old") then
fun x -> operation x x
else
fun x -> operation x (int64 right)
else if (right = "old") then
fun x -> (operation (int64 left) x)
else
fun _ -> (operation (int64 left) (int64 right))
type Monkey
(
items: int64[],
operation: int64 -> int64,
divisor: int64,
tMonkey: int,
fMonkey: int,
part: int
) =
let mutable items = items
let operation = operation
let divisor = divisor
let trueTest = tMonkey
let falseTest = fMonkey
let mutable inspectedItems: int64 = 0
member _.HasItem() : bool = items.Length <> 0
member _.Inspect() =
inspectedItems <- inspectedItems + 1L
let mutable result = operation items[0]
items <- Array.skip 1 items
result <- result / (if part = 1 then 3L else 1L)
if result % divisor = int64 0 then
trueTest, result
else
falseTest, result
member _.Catch(item: int64) = items <- Array.append items [| item |]
member _.Inspected() = inspectedItems
type Input() =
member _.Compute(part: int) =
use stream = new StreamReader "./input.txt"
let mutable endOfFile = false
let mutable monkeys = Array.empty<Monkey>
let mutable multipliers = 1L
while (not endOfFile) do
let line = stream.ReadLine()
if (line = null) then
endOfFile <- true
else
let items =
stream.ReadLine().Substring(" Starting items: ".Length).Split(", ")
|> Array.map int64
let operation =
stream.ReadLine().Substring(" Operation: new = ".Length).Split(" ")
|> mapOperation
let divisor = stream.ReadLine().Split(" ") |> Array.last |> int64
multipliers <- multipliers * divisor
let trueMonkey = stream.ReadLine().Split(" ") |> Array.last |> int
let falseMonkey = stream.ReadLine().Split(" ") |> Array.last |> int
stream.ReadLine() |> ignore
let monkey = new Monkey(items, operation, divisor, trueMonkey, falseMonkey, part)
monkeys <- Array.append monkeys [| monkey |]
let rounds = if part = 1 then 20 else 10000
for r in 1..rounds do
for i in 0 .. (monkeys.Length - 1) do
let currentMonkey = monkeys[i]
while (currentMonkey.HasItem()) do
let (monkey, result) = currentMonkey.Inspect()
monkeys[ monkey ].Catch(result % multipliers)
let lastTwo =
monkeys
|> Array.map (fun x -> x.Inspected())
|> Array.sort
|> Array.skip (monkeys.Length - 2)
lastTwo[0] * lastTwo[1]
let input = Input()
let part = (Environment.GetCommandLineArgs()[1]) |> int
printfn "%d" (input.Compute(part))