Day 21, part 2

This commit is contained in:
jazzpi 2022-12-21 18:45:28 +01:00
parent ec5b46d793
commit 47cb2fefa5
3 changed files with 92 additions and 17 deletions

View File

@ -3,5 +3,5 @@ use aoc22::{day21, util};
pub fn main() { pub fn main() {
let monkeys = day21::parse_monkeys(&util::parse_input()); let monkeys = day21::parse_monkeys(&util::parse_input());
println!("root yells: {}", day21::yell(monkeys.root())); println!("root yells: {}", day21::yell(monkeys.root(), false));
} }

9
src/bin/d21p2.rs Normal file
View File

@ -0,0 +1,9 @@
use aoc22::{day21, util};
pub fn main() {
let monkeys = day21::parse_monkeys(&util::parse_input());
let human = day21::find(&monkeys, "humn").unwrap();
println!("Human should yell: {}", day21::find_solution(human));
}

View File

@ -3,7 +3,7 @@ use std::collections::HashMap;
use regex::Regex; use regex::Regex;
use trees::{tr, Node, Tree}; use trees::{tr, Node, Tree};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum Operation { pub enum Operation {
Add, Add,
Sub, Sub,
@ -23,12 +23,18 @@ impl Operation {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, PartialEq)]
pub enum Monkey { pub enum MonkeyKind {
Number(isize), Number(isize),
Calculate(String, String, Operation), Calculate(String, String, Operation),
} }
#[derive(Debug, Clone, PartialEq)]
pub struct Monkey {
pub name: String,
pub kind: MonkeyKind,
}
pub fn parse_monkeys(input: &String) -> Tree<Monkey> { pub fn parse_monkeys(input: &String) -> Tree<Monkey> {
let mut monkeys = HashMap::new(); let mut monkeys = HashMap::new();
@ -36,16 +42,22 @@ pub fn parse_monkeys(input: &String) -> Tree<Monkey> {
for line in input.lines() { for line in input.lines() {
let captures = re.captures(line).unwrap(); let captures = re.captures(line).unwrap();
let name = captures.get(1).unwrap().as_str(); let name = captures.get(1).unwrap().as_str();
let monkey = if let Some(num) = captures.get(2) { let kind = if let Some(num) = captures.get(2) {
Monkey::Number(num.as_str().parse().unwrap()) MonkeyKind::Number(num.as_str().parse().unwrap())
} else { } else {
Monkey::Calculate( MonkeyKind::Calculate(
captures.get(3).unwrap().as_str().to_owned(), captures.get(3).unwrap().as_str().to_owned(),
captures.get(5).unwrap().as_str().to_owned(), captures.get(5).unwrap().as_str().to_owned(),
Operation::from(captures.get(4).unwrap().as_str()), Operation::from(captures.get(4).unwrap().as_str()),
) )
}; };
monkeys.insert(name.to_owned(), monkey); monkeys.insert(
name.to_owned(),
Monkey {
name: name.to_owned(),
kind,
},
);
} }
let tree = to_tree(&monkeys, "root"); let tree = to_tree(&monkeys, "root");
@ -57,7 +69,7 @@ fn to_tree(monkeys: &HashMap<String, Monkey>, monkey: &str) -> Tree<Monkey> {
let monkey = &monkeys[monkey]; let monkey = &monkeys[monkey];
let mut tree = tr(monkey.clone()); let mut tree = tr(monkey.clone());
if let Monkey::Calculate(a, b, _) = monkey { if let MonkeyKind::Calculate(a, b, _) = &monkey.kind {
let forest = -to_tree(monkeys, a) - to_tree(monkeys, b); let forest = -to_tree(monkeys, a) - to_tree(monkeys, b);
tree.append(forest); tree.append(forest);
} }
@ -65,19 +77,73 @@ fn to_tree(monkeys: &HashMap<String, Monkey>, monkey: &str) -> Tree<Monkey> {
tree tree
} }
pub fn yell(monkey: &Node<Monkey>) -> isize { pub fn yell(monkey: &Node<Monkey>, no_human: bool) -> isize {
match monkey.data() { if no_human {
Monkey::Number(n) => *n, assert!(monkey.data().name != "humn");
Monkey::Calculate(_, _, op) => { }
match &monkey.data().kind {
MonkeyKind::Number(n) => *n,
MonkeyKind::Calculate(_, _, op) => {
let mut children = monkey.iter(); let mut children = monkey.iter();
let a = children.next().unwrap(); let a = children.next().unwrap();
let b = children.next().unwrap(); let b = children.next().unwrap();
match op { match op {
Operation::Add => yell(a) + yell(b), Operation::Add => yell(a, no_human) + yell(b, no_human),
Operation::Sub => yell(a) - yell(b), Operation::Sub => yell(a, no_human) - yell(b, no_human),
Operation::Mul => yell(a) * yell(b), Operation::Mul => yell(a, no_human) * yell(b, no_human),
Operation::Div => yell(a) / yell(b), Operation::Div => yell(a, no_human) / yell(b, no_human),
} }
} }
} }
} }
pub fn find_solution(target: &Node<Monkey>) -> isize {
let parent = target.parent().unwrap();
let other_pos = parent.iter().position(|n| n != target).unwrap();
assert!(other_pos < 2);
let sibling = parent.iter().nth(other_pos).unwrap();
let other = yell(sibling, true);
if parent.parent().is_none() {
other
} else {
let parent_target = find_solution(parent);
if let MonkeyKind::Calculate(_, _, op) = parent.data().kind {
match op {
Operation::Add => parent_target - other,
Operation::Sub => {
if other_pos == 0 {
other - parent_target
} else {
other + parent_target
}
}
Operation::Mul => parent_target / other,
Operation::Div => {
if other_pos == 0 {
other / parent_target
} else {
parent_target * other
}
}
}
} else {
panic!("Parent does not calculate!?");
}
}
}
pub fn find<'a>(monkeys: &'a Tree<Monkey>, name: &str) -> Option<&'a Node<Monkey>> {
let mut next = vec![monkeys.root()];
while let Some(n) = next.pop() {
let data = n.data();
if data.name == name {
return Some(n);
}
next.extend(n.iter());
}
None
}