2022 Day 21 Part 2
This commit is contained in:
parent
20ca255627
commit
1a43f814d3
1 changed files with 148 additions and 0 deletions
|
|
@ -5,6 +5,7 @@ const INPUT: &str = include_str!("../../input/day21.txt");
|
||||||
fn main() {
|
fn main() {
|
||||||
let monkeys = parse(INPUT);
|
let monkeys = parse(INPUT);
|
||||||
println!("{:?}", part1(monkeys.clone()));
|
println!("{:?}", part1(monkeys.clone()));
|
||||||
|
println!("{:?}", part2(monkeys));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(input: &str) -> HashMap<Name, Expr> {
|
fn parse(input: &str) -> HashMap<Name, Expr> {
|
||||||
|
|
@ -135,3 +136,150 @@ impl Evaluator {
|
||||||
self.memo[&name]
|
self.memo[&name]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn part2(mut monkeys: HashMap<Name, Expr>) -> u64 {
|
||||||
|
let human: Name = "humn".into();
|
||||||
|
|
||||||
|
monkeys.remove(&human);
|
||||||
|
|
||||||
|
let dependents: usize = monkeys
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(_name, expr)| expr.bindings().iter().position(|b| b == "humn"))
|
||||||
|
.count();
|
||||||
|
assert_eq!(dependents, 1);
|
||||||
|
|
||||||
|
let names = monkeys["root"].bindings();
|
||||||
|
assert_eq!(names.len(), 2);
|
||||||
|
|
||||||
|
let mut a = Tree::build(Expr::Monkey(names[0].clone()), &monkeys);
|
||||||
|
let mut b = Tree::build(Expr::Monkey(names[1].clone()), &monkeys);
|
||||||
|
|
||||||
|
let leaf = Tree::Monkey(human.clone());
|
||||||
|
while a != leaf {
|
||||||
|
(a, b) = Tree::reroot(a, b, &human);
|
||||||
|
}
|
||||||
|
|
||||||
|
b.value()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
enum Tree {
|
||||||
|
Const(u64),
|
||||||
|
Monkey(Name),
|
||||||
|
BinOp(Op, Box<Tree>, Box<Tree>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
enum Op {
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tree {
|
||||||
|
fn build(expr: Expr, monkeys: &HashMap<Name, Expr>) -> Self {
|
||||||
|
match expr {
|
||||||
|
Expr::Const(v) => Tree::Const(v),
|
||||||
|
Expr::Monkey(m) => {
|
||||||
|
if let Some(e) = monkeys.get(&m) {
|
||||||
|
Tree::build(e.clone(), monkeys)
|
||||||
|
} else {
|
||||||
|
Tree::Monkey(m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Add(l, r) => Tree::BinOp(
|
||||||
|
Op::Add,
|
||||||
|
Tree::build(*l, monkeys).into(),
|
||||||
|
Tree::build(*r, monkeys).into(),
|
||||||
|
),
|
||||||
|
Expr::Sub(l, r) => Tree::BinOp(
|
||||||
|
Op::Sub,
|
||||||
|
Tree::build(*l, monkeys).into(),
|
||||||
|
Tree::build(*r, monkeys).into(),
|
||||||
|
),
|
||||||
|
Expr::Mul(l, r) => Tree::BinOp(
|
||||||
|
Op::Mul,
|
||||||
|
Tree::build(*l, monkeys).into(),
|
||||||
|
Tree::build(*r, monkeys).into(),
|
||||||
|
),
|
||||||
|
Expr::Div(l, r) => Tree::BinOp(
|
||||||
|
Op::Div,
|
||||||
|
Tree::build(*l, monkeys).into(),
|
||||||
|
Tree::build(*r, monkeys).into(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contains(&self, name: &Name) -> bool {
|
||||||
|
match self {
|
||||||
|
Tree::Const(_) => false,
|
||||||
|
Tree::Monkey(m) => m == name,
|
||||||
|
Tree::BinOp(_, l, r) => l.contains(name) || r.contains(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn binary(op: Op, l: Self, r: Self) -> Self {
|
||||||
|
Tree::BinOp(op, Box::new(l), Box::new(r))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reroot(a: Self, b: Self, name: &Name) -> (Self, Self) {
|
||||||
|
assert!(a.contains(name));
|
||||||
|
|
||||||
|
match a {
|
||||||
|
Tree::Const(_) => todo!(),
|
||||||
|
Tree::Monkey(_) => todo!(),
|
||||||
|
Tree::BinOp(op, l, r) => {
|
||||||
|
let (aa, bb) = if l.contains(name) {
|
||||||
|
// L op r == b
|
||||||
|
match op {
|
||||||
|
// L + r == b
|
||||||
|
// L == b - r
|
||||||
|
Op::Add => (l, Tree::binary(Op::Sub, b, *r)),
|
||||||
|
// L - r == b
|
||||||
|
// L == b + r
|
||||||
|
Op::Sub => (l, Tree::binary(Op::Add, b, *r)),
|
||||||
|
// L * r == b
|
||||||
|
// L == b / r
|
||||||
|
Op::Mul => (l, Tree::binary(Op::Div, b, *r)),
|
||||||
|
// L / r == b
|
||||||
|
// L == b * r
|
||||||
|
Op::Div => (l, Tree::binary(Op::Mul, b, *r)),
|
||||||
|
}
|
||||||
|
} else if r.contains(name) {
|
||||||
|
// l op R == b
|
||||||
|
match op {
|
||||||
|
// l + R == b
|
||||||
|
// R == b - l
|
||||||
|
Op::Add => (r, Tree::binary(Op::Sub, b, *l)),
|
||||||
|
// l - R == b
|
||||||
|
// R == l - b
|
||||||
|
Op::Sub => (r, Tree::binary(Op::Sub, *l, b)),
|
||||||
|
// l * R == b
|
||||||
|
// R == b / l
|
||||||
|
Op::Mul => (r, Tree::binary(Op::Div, b, *l)),
|
||||||
|
// l / R == b
|
||||||
|
// R == l / b
|
||||||
|
Op::Div => (r, Tree::binary(Op::Div, *l, b)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
todo!()
|
||||||
|
};
|
||||||
|
(*aa, bb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value(&self) -> u64 {
|
||||||
|
match self {
|
||||||
|
Tree::Const(v) => *v,
|
||||||
|
Tree::Monkey(_) => todo!(),
|
||||||
|
Tree::BinOp(op, l, r) => match op {
|
||||||
|
Op::Add => l.value() + r.value(),
|
||||||
|
Op::Sub => l.value() - r.value(),
|
||||||
|
Op::Mul => l.value() * r.value(),
|
||||||
|
Op::Div => l.value() / r.value(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue