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>) -> Monkey {
58 if str.len() < 11 {
59 Monkey::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 Monkey::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: FastMap<_, _> =
87 lines.iter().enumerate().map(|(index, line)| (&line[0..4], index)).collect();
88
89 let monkeys: Vec<_> = lines.iter().map(|line| Monkey::parse(&line[6..], &indices)).collect();
90
91 let root = indices["root"];
93 let humn = indices["humn"];
94 let mut input =
95 Input { root, monkeys, yell: vec![0; lines.len()], unknown: vec![false; lines.len()] };
96
97 compute(&mut input, root);
98 find(&mut input, humn, root);
99 input
100}
101
102pub fn part1(input: &Input) -> i64 {
103 let Input { yell, root, .. } = input;
104 yell[*root]
105}
106
107pub fn part2(input: &Input) -> i64 {
108 let Input { root, .. } = input;
109 inverse(input, *root, -1)
110}
111
112fn compute(input: &mut Input, index: usize) -> i64 {
114 let result = match input.monkeys[index] {
115 Monkey::Number(n) => n,
116 Monkey::Result(left, operation, right) => {
117 let l = compute(input, left);
118 let r = compute(input, right);
119 match operation {
120 Operation::Add => l + r,
121 Operation::Sub => l - r,
122 Operation::Mul => l * r,
123 Operation::Div => l / r,
124 }
125 }
126 };
127 input.yell[index] = result;
129 result
130}
131
132fn find(input: &mut Input, humn: usize, index: usize) -> bool {
135 let result = match input.monkeys[index] {
136 Monkey::Number(_) => humn == index,
137 Monkey::Result(left, _, right) => find(input, humn, left) || find(input, humn, right),
138 };
139 input.unknown[index] = result;
140 result
141}
142
143fn inverse(input: &Input, index: usize, value: i64) -> i64 {
146 let Input { root, yell, unknown, monkeys } = input;
147
148 match monkeys[index] {
149 Monkey::Number(_) => value,
152 Monkey::Result(left, _, right) if index == *root => {
154 if unknown[left] {
155 inverse(input, left, yell[right])
156 } else {
157 inverse(input, right, yell[left])
158 }
159 }
160 Monkey::Result(left, operation, right) => {
163 if unknown[left] {
164 match operation {
165 Operation::Add => inverse(input, left, value - yell[right]),
166 Operation::Sub => inverse(input, left, value + yell[right]),
167 Operation::Mul => inverse(input, left, value / yell[right]),
168 Operation::Div => inverse(input, left, value * yell[right]),
169 }
170 } else {
171 match operation {
172 Operation::Add => inverse(input, right, value - yell[left]),
173 Operation::Sub => inverse(input, right, yell[left] - value),
174 Operation::Mul => inverse(input, right, value / yell[left]),
175 Operation::Div => inverse(input, right, yell[left] / value),
176 }
177 }
178 }
179 }
180}