blob: f9a608dec0cf2f21ca3f15e2a29b921667d2cb42 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
module Day21
open System.IO
open System.Numerics
open FSharpPlus
open FParsec
open Common
type MonkeyName = string
module MonkeyName =
let root = "root"
let human = "humn"
type Operator = Complex -> Complex -> Complex
module Operator =
let fromChar =
function
| '+' -> (+)
| '-' -> (-)
| '*' -> (*)
| '/' -> (/)
| c -> failwithf "Invalid operator: %c" c
let unknownExtractor l r =
let eq: Complex = l - r
Complex(round <| -eq.Real / eq.Imaginary, 0)
type MonkeyJob =
| Number of Complex
| Operation of MonkeyName * Operator * MonkeyName
static member unknownVariable = Number(Complex(0, 1))
static member eval(cache: Map<MonkeyName, Complex>) =
function
| Number num -> num
| Operation (left, operator, right) -> operator cache[left] cache[right]
static member withOperator op =
function
| Operation (l, _, r) -> Operation(l, op, r)
| other -> other
static member dependencies =
function
| Operation (l, _, r) -> [ l; r ]
| _ -> []
type Monkey = MonkeyName * MonkeyJob
module Monkey =
let parse =
let pws = pchar ' '
let pname = anyString 4 |>> MonkeyName
let pop = pws >>. anyChar .>> pws |>> Operator.fromChar
let pnumber = pfloat |>> (fun n -> Number(Complex(n, 0)))
let poperation = tuple3 pname pop pname |>> Operation
let pjob = pnumber <|> poperation
let pmonkey = pname .>> pstring ": " .>>. pjob |>> Monkey
Util.parse pmonkey
let solution modification input =
let monkeys =
input
|> Seq.map Monkey.parse
|> Map.ofSeq
|> modification
let nodeValues =
monkeys
|> Map.mapValues MonkeyJob.dependencies
|> Util.tsort
|> List.fold (fun cache name -> Map.add name (MonkeyJob.eval cache monkeys[name]) cache) Map.empty
int64 nodeValues[MonkeyName.root].Real
let part1 = id
let part2 =
Map.add MonkeyName.human MonkeyJob.unknownVariable
>> Map.change MonkeyName.root (Option.map (MonkeyJob.withOperator Operator.unknownExtractor))
let test = File.ReadLines("test.txt")
assert (solution part1 test = 152)
assert (solution part2 test = 301)
let input = File.ReadLines("input.txt")
printfn "%d" <| solution part1 input
printfn "%d" <| solution part2 input
|