Skip to content

Commit 9808f35

Browse files
committed
Document Year 2022 Day 21
1 parent 0614b3b commit 9808f35

File tree

1 file changed

+52
-0
lines changed

1 file changed

+52
-0
lines changed

src/year2022/day21.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,42 @@
1+
//! # Monkey Math
2+
//!
3+
//! The Monkeys form a [binary tree](https://en.wikipedia.org/wiki/Binary_tree). We first
4+
//! compute the result by recursively following the strucuture all the ways to the leaves.
5+
//! We also find the `humn` node and all its parents the same way, marking them as "unknown".
6+
//!
7+
//! For part two we know that the value on the left and the right of the root must be equal.
8+
//! Following the tree down the path previously marked "unknown" we recursively solve
9+
//! equations until we reached the `humn` node.
10+
//!
11+
//! For example say the root's children are `a` and `b`
12+
//!
13+
//! ```none
14+
//! yell[a] = 6
15+
//! unknown[a] = false
16+
//! yell[b] = 5
17+
//! unknown[b] = true
18+
//! ```
19+
//!
20+
//! So this implies `b` is a parent of `humn` and must equal `6` to pass (the current value is
21+
//! irrelevant). We then recursively look at the children of `b`:
22+
//!
23+
//! ```none
24+
//! yell[c] = 4
25+
//! unknown[a] = true
26+
//! operation = "+"
27+
//! yell[d] = 4
28+
//! unknown[b] = false
29+
//! ```
30+
//!
31+
//! We know that `c + d` must equal 6 so this implies `c = 2`. We then recursively look at the
32+
//! children of `c`
33+
//!
34+
//! ```none
35+
//! yell[humn] = 123
36+
//! unknown[a] = true
37+
//! ```
38+
//!
39+
//! Once we finally reach the `humn` node the value that we currently have `2` is the answer.
140
use crate::util::hash::*;
241
use crate::util::parse::*;
342

@@ -43,11 +82,13 @@ pub struct Input {
4382
pub fn parse(input: &str) -> Input {
4483
let lines: Vec<_> = input.lines().collect();
4584

85+
// Assign each monkey an index on a first come first served basis.
4686
let indices: FastMap<_, _> =
4787
lines.iter().enumerate().map(|(index, line)| (&line[0..4], index)).collect();
4888

4989
let monkeys: Vec<_> = lines.iter().map(|line| Monkey::parse(&line[6..], &indices)).collect();
5090

91+
// We only need the specific indices of the root and human.
5192
let root = indices["root"];
5293
let humn = indices["humn"];
5394
let mut input =
@@ -68,6 +109,7 @@ pub fn part2(input: &Input) -> i64 {
68109
inverse(input, *root, -1)
69110
}
70111

112+
/// Recursively compute the total following the tree structure all the way to the leaves.
71113
fn compute(input: &mut Input, index: usize) -> i64 {
72114
let result = match input.monkeys[index] {
73115
Monkey::Number(n) => n,
@@ -78,10 +120,13 @@ fn compute(input: &mut Input, index: usize) -> i64 {
78120
Operation::Div => compute(input, left) / compute(input, right),
79121
},
80122
};
123+
// Cache the computed value for use in part two.
81124
input.yell[index] = result;
82125
result
83126
}
84127

128+
/// Recursively find the humn node then mark it and all its parents all the way to the
129+
/// root as "unknown".
85130
fn find(input: &mut Input, humn: usize, index: usize) -> bool {
86131
let result = match input.monkeys[index] {
87132
Monkey::Number(_) => humn == index,
@@ -91,18 +136,25 @@ fn find(input: &mut Input, humn: usize, index: usize) -> bool {
91136
result
92137
}
93138

139+
/// Recursively finds the value of the expression on the "unknown" side so that it equals the
140+
/// known side.
94141
fn inverse(input: &Input, index: usize, value: i64) -> i64 {
95142
let Input { root, yell, unknown, monkeys } = input;
96143

97144
match monkeys[index] {
145+
// The only leaf node we'll actually ever reach is the "humn" node so the value at this
146+
// point is the answer.
98147
Monkey::Number(_) => value,
148+
// If we're the root then the left and right side must be equal.
99149
Monkey::Result(left, _, right) if index == *root => {
100150
if unknown[left] {
101151
inverse(input, left, yell[right])
102152
} else {
103153
inverse(input, right, yell[left])
104154
}
105155
}
156+
// Addition and multiplication are commutative, but subtraction and division are not,
157+
// so we have to handle unknowns on the right and left differently.
106158
Monkey::Result(left, operation, right) => {
107159
if unknown[left] {
108160
match operation {

0 commit comments

Comments
 (0)