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) => match operation {
117 Operation::Add => compute(input, left) + compute(input, right),
118 Operation::Sub => compute(input, left) - compute(input, right),
119 Operation::Mul => compute(input, left) * compute(input, right),
120 Operation::Div => compute(input, left) / compute(input, right),
121 },
122 };
123 input.yell[index] = result;
125 result
126}
127
128fn find(input: &mut Input, humn: usize, index: usize) -> bool {
131 let result = match input.monkeys[index] {
132 Monkey::Number(_) => humn == index,
133 Monkey::Result(left, _, right) => find(input, humn, left) || find(input, humn, right),
134 };
135 input.unknown[index] = result;
136 result
137}
138
139fn inverse(input: &Input, index: usize, value: i64) -> i64 {
142 let Input { root, yell, unknown, monkeys } = input;
143
144 match monkeys[index] {
145 Monkey::Number(_) => value,
148 Monkey::Result(left, _, right) if index == *root => {
150 if unknown[left] {
151 inverse(input, left, yell[right])
152 } else {
153 inverse(input, right, yell[left])
154 }
155 }
156 Monkey::Result(left, operation, right) => {
159 if unknown[left] {
160 match operation {
161 Operation::Add => inverse(input, left, value - yell[right]),
162 Operation::Sub => inverse(input, left, value + yell[right]),
163 Operation::Mul => inverse(input, left, value / yell[right]),
164 Operation::Div => inverse(input, left, value * yell[right]),
165 }
166 } else {
167 match operation {
168 Operation::Add => inverse(input, right, value - yell[left]),
169 Operation::Sub => inverse(input, right, yell[left] - value),
170 Operation::Mul => inverse(input, right, value / yell[left]),
171 Operation::Div => inverse(input, right, yell[left] / value),
172 }
173 }
174 }
175 }
176}