2022 Day 21 Part 1
This commit is contained in:
parent
e6521b17e5
commit
20ca255627
1 changed files with 137 additions and 0 deletions
137
2022/src/bin/day21.rs
Normal file
137
2022/src/bin/day21.rs
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
const INPUT: &str = include_str!("../../input/day21.txt");
|
||||
|
||||
fn main() {
|
||||
let monkeys = parse(INPUT);
|
||||
println!("{:?}", part1(monkeys.clone()));
|
||||
}
|
||||
|
||||
fn parse(input: &str) -> HashMap<Name, Expr> {
|
||||
input
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let words: Vec<&str> = line.split(": ").collect();
|
||||
let name = words[0].to_string();
|
||||
let expr = Expr::parse(words[1]);
|
||||
|
||||
(name, expr)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
type Name = String;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
enum Expr {
|
||||
Const(u64),
|
||||
Monkey(Name),
|
||||
Add(Box<Expr>, Box<Expr>),
|
||||
Sub(Box<Expr>, Box<Expr>),
|
||||
Mul(Box<Expr>, Box<Expr>),
|
||||
Div(Box<Expr>, Box<Expr>),
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
fn parse(s: &str) -> Self {
|
||||
let w: Vec<&str> = s.split(' ').collect();
|
||||
|
||||
if w.len() == 1 {
|
||||
Expr::parse_atom(w[0])
|
||||
} else {
|
||||
Expr::parse_binary(w)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_atom(s: &str) -> Self {
|
||||
match s.parse::<u64>() {
|
||||
Ok(u) => Expr::Const(u),
|
||||
Err(_) => Expr::Monkey(s.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_binary(w: Vec<&str>) -> Self {
|
||||
assert_eq!(w.len(), 3);
|
||||
|
||||
let l = Self::parse_atom(w[0]);
|
||||
let r = Self::parse_atom(w[2]);
|
||||
|
||||
match w[1] {
|
||||
"+" => Expr::Add(Box::new(l), Box::new(r)),
|
||||
"-" => Expr::Sub(Box::new(l), Box::new(r)),
|
||||
"*" => Expr::Mul(Box::new(l), Box::new(r)),
|
||||
"/" => Expr::Div(Box::new(l), Box::new(r)),
|
||||
other => panic!("{}", other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn part1(monkeys: HashMap<Name, Expr>) -> u64 {
|
||||
let mut ev = Evaluator::new(monkeys);
|
||||
ev.eval("root".to_string())
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
fn bindings(&self) -> Vec<Name> {
|
||||
match self {
|
||||
Expr::Const(_) => vec![],
|
||||
Expr::Monkey(name) => vec![name.clone()],
|
||||
Expr::Add(l, r) => [l.bindings(), r.bindings()].concat(),
|
||||
Expr::Sub(l, r) => [l.bindings(), r.bindings()].concat(),
|
||||
Expr::Mul(l, r) => [l.bindings(), r.bindings()].concat(),
|
||||
Expr::Div(l, r) => [l.bindings(), r.bindings()].concat(),
|
||||
}
|
||||
}
|
||||
|
||||
fn value(&self, memo: &HashMap<Name, u64>) -> u64 {
|
||||
match self {
|
||||
Expr::Const(v) => *v,
|
||||
Expr::Monkey(name) => memo[name],
|
||||
Expr::Add(l, r) => l.value(memo) + r.value(memo),
|
||||
Expr::Sub(l, r) => l.value(memo) - r.value(memo),
|
||||
Expr::Mul(l, r) => l.value(memo) * r.value(memo),
|
||||
Expr::Div(l, r) => l.value(memo) / r.value(memo),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Evaluator {
|
||||
memo: HashMap<Name, u64>,
|
||||
monkeys: HashMap<Name, Expr>,
|
||||
}
|
||||
|
||||
impl Evaluator {
|
||||
fn new(monkeys: HashMap<Name, Expr>) -> Self {
|
||||
Self {
|
||||
memo: Default::default(),
|
||||
monkeys,
|
||||
}
|
||||
}
|
||||
|
||||
fn eval(&mut self, name: Name) -> u64 {
|
||||
let mut queue: VecDeque<Name> = Default::default();
|
||||
queue.push_front(name.clone());
|
||||
|
||||
let mut needed: VecDeque<Name> = Default::default();
|
||||
|
||||
while let Some(want) = queue.pop_front() {
|
||||
if needed.contains(&want) {
|
||||
continue;
|
||||
}
|
||||
needed.push_front(want.clone());
|
||||
|
||||
for name in self.monkeys[&want].bindings() {
|
||||
queue.push_front(name.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
for name in needed {
|
||||
let expr = &self.monkeys[&name];
|
||||
let v = expr.value(&self.memo);
|
||||
self.memo.insert(name, v);
|
||||
}
|
||||
|
||||
self.memo[&name]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue