1use crate::util::hash::*;
41use crate::util::parse::*;
42
43#[derive(Clone, Copy)]
44enum Operation {
45 Add,
46 Sub,
47 Mul,
48 Div,
49}
50
51enum Monkey {
52 Number(i64),
53 Result(usize, Operation, usize),
54}
55
56impl Monkey {
57 fn parse(str: &str, indices: &FastMap<&str, usize>) -> Self {
58 if str.len() < 11 {
59 Self::Number(str.signed())
60 } else {
61 let left = indices[&str[0..4]];
62 let right = indices[&str[7..11]];
63 let operation = match str.as_bytes()[5] {
64 b'+' => Operation::Add,
65 b'-' => Operation::Sub,
66 b'*' => Operation::Mul,
67 b'/' => Operation::Div,
68 _ => unreachable!(),
69 };
70 Self::Result(left, operation, right)
71 }
72 }
73}
74
75pub struct Input {
76 root: usize,
77 monkeys: Vec<Monkey>,
78 yell: Vec<i64>,
79 unknown: Vec<bool>,
80}
81
82pub fn parse(input: &str) -> Input {
83 let lines: Vec<_> = input.lines().collect();
84
85 let indices = lines.iter().enumerate().map(|(index, line)| (&line[0..4], index)).collect();
87
88 let monkeys = lines.iter().map(|line| Monkey::parse(&line[6..], &indices)).collect();
89
90 let root = indices["root"];
92 let humn = indices["humn"];
93 let mut input =
94 Input { root, monkeys, yell: vec![0; lines.len()], unknown: vec![false; lines.len()] };
95
96 compute(&mut input, root);
97 find(&mut input, humn, root);
98 input
99}
100
101pub fn part1(input: &Input) -> i64 {
102 input.yell[input.root]
103}
104
105pub fn part2(input: &Input) -> i64 {
106 inverse(input, input.root, -1)
107}
108
109fn compute(input: &mut Input, index: usize) -> i64 {
111 let result = match input.monkeys[index] {
112 Monkey::Number(n) => n,
113 Monkey::Result(left, operation, right) => {
114 let l = compute(input, left);
115 let r = compute(input, right);
116 match operation {
117 Operation::Add => l + r,
118 Operation::Sub => l - r,
119 Operation::Mul => l * r,
120 Operation::Div => l / r,
121 }
122 }
123 };
124 input.yell[index] = result;
126 result
127}
128
129fn find(input: &mut Input, humn: usize, index: usize) -> bool {
132 let result = match input.monkeys[index] {
133 Monkey::Number(_) => humn == index,
134 Monkey::Result(left, _, right) => find(input, humn, left) || find(input, humn, right),
135 };
136 input.unknown[index] = result;
137 result
138}
139
140fn inverse(input: &Input, index: usize, value: i64) -> i64 {
143 let Input { root, yell, unknown, monkeys } = input;
144
145 match monkeys[index] {
146 Monkey::Number(_) => value,
149 Monkey::Result(left, _, right) if index == *root => {
151 if unknown[left] {
152 inverse(input, left, yell[right])
153 } else {
154 inverse(input, right, yell[left])
155 }
156 }
157 Monkey::Result(left, operation, right) => {
160 if unknown[left] {
161 let value = match operation {
162 Operation::Add => value - yell[right],
163 Operation::Sub => value + yell[right],
164 Operation::Mul => value / yell[right],
165 Operation::Div => value * yell[right],
166 };
167 inverse(input, left, value)
168 } else {
169 let value = match operation {
170 Operation::Add => value - yell[left],
171 Operation::Sub => yell[left] - value,
172 Operation::Mul => value / yell[left],
173 Operation::Div => yell[left] / value,
174 };
175 inverse(input, right, value)
176 }
177 }
178 }
179}