module Solutions.Day11 type Monkey = { Items: int64 list Operation: int64 -> int64 Test: int64 TrueMonkey: int FalseMonkey: int Inspections: int64 } let monkeys = [ { Items = [89; 95; 92; 64; 87; 68] Operation = (*) 11L Test = 2 TrueMonkey = 7 FalseMonkey = 4 Inspections = 0 } { Items = [87; 67] Operation = (+) 1L; Test = 13; TrueMonkey = 3 FalseMonkey = 6 Inspections = 0 } { Items = [95; 79; 92; 82; 60] Operation = (+) 6L Test = 3 TrueMonkey = 1 FalseMonkey = 6 Inspections = 0 } { Items = [67; 97; 56] Operation = fun x -> x * x Test = 17 TrueMonkey = 7 FalseMonkey = 0 Inspections = 0 } { Items = [80; 68; 87; 94; 61; 59; 50; 68] Operation = (*) 7L Test = 19 TrueMonkey = 5 FalseMonkey = 2 Inspections = 0 } { Items = [73; 51; 76; 59] Operation = (+) 8L Test = 7 TrueMonkey = 2 FalseMonkey = 1 Inspections = 0 } { Items = [92] Operation = (+) 5L Test = 11 TrueMonkey = 3 FalseMonkey = 0 Inspections = 0 } { Items = [99; 76; 78; 76; 79; 90; 89] Operation = (+) 7L Test = 5 TrueMonkey = 4 FalseMonkey = 5 Inspections = 0 } ] let throw item target monkeys = let monkey = List.item target monkeys List.updateAt target {monkey with Items = (List.append monkey.Items [item])} monkeys let doItem operation monkey monkeys item = let worryLevel = monkey.Operation item let boredLevel = operation worryLevel let target = if boredLevel % monkey.Test = 0L then monkey.TrueMonkey else monkey.FalseMonkey throw boredLevel target monkeys let playTurn operation monkeys id = let monkey = List.item id monkeys let cleared = monkeys |> List.updateAt id {monkey with Items = [] Inspections = monkey.Inspections + (int64 monkey.Items.Length)} monkey.Items |> List.fold (doItem operation monkey) cleared let playRound operation monkeys = let players = [ 0 .. (List.length monkeys - 1)] List.fold (playTurn operation) monkeys players let rec playRounds operation nb monkeys = if nb = 0 then monkeys else let next = playRound operation monkeys playRounds operation (nb - 1) next let solve operation count = monkeys |> playRounds operation count |> List.map (fun m -> m.Inspections) |> List.sortDescending |> List.take 2 |> List.reduce (*) let part1 () = solve (fun x -> x / 3L) 20 let part2 () = let safeMod = monkeys |> Seq.map (fun m -> m.Test) |> Seq.reduce (*) solve (fun x -> x % safeMod) 10_000