Added day 21
This commit is contained in:
parent
6a0dde01df
commit
495cf135e1
|
@ -1,7 +1,7 @@
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
use std::collections::{BinaryHeap, HashSet};
|
use std::collections::HashSet;
|
||||||
|
|
||||||
const INPUTS: [&[u8]; 2] = [
|
const INPUTS: [&[u8]; 2] = [
|
||||||
include_bytes!("./sample.txt"),
|
include_bytes!("./sample.txt"),
|
||||||
|
@ -224,7 +224,7 @@ const fn find_cost(costs: &[u16], i: u16) -> [u16; 3] {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
for input in INPUTS.iter().take(1) {
|
for input in INPUTS.iter() {
|
||||||
let output = parse(input);
|
let output = parse(input);
|
||||||
let score = solution(output);
|
let score = solution(output);
|
||||||
println!("{}", score);
|
println!("{}", score);
|
||||||
|
|
117
src/day21/1.rs
117
src/day21/1.rs
|
@ -0,0 +1,117 @@
|
||||||
|
#![feature(test)]
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
extern crate test;
|
||||||
|
|
||||||
|
const INPUTS: [&str; 2] = [include_str!("./sample.txt"), include_str!("./input.txt")];
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum Operation {
|
||||||
|
Divide,
|
||||||
|
Multiply,
|
||||||
|
Add,
|
||||||
|
Subtract,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Monkey {
|
||||||
|
operand1: Operand,
|
||||||
|
op: Option<Operation>,
|
||||||
|
operand2: Option<Operand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum Operand {
|
||||||
|
Number(i64),
|
||||||
|
Reference(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(input: &'static str) -> HashMap<String, Monkey> {
|
||||||
|
input
|
||||||
|
.lines()
|
||||||
|
.filter(|c| !c.is_empty())
|
||||||
|
.flat_map(|line| {
|
||||||
|
line.split_once(':').map(|(name, values)| {
|
||||||
|
let mut tokens = values.trim().splitn(3, ' ');
|
||||||
|
|
||||||
|
let operand1 = tokens.next();
|
||||||
|
|
||||||
|
let op = tokens
|
||||||
|
.next()
|
||||||
|
.map(|token| {
|
||||||
|
Some(match token {
|
||||||
|
"*" => Operation::Multiply,
|
||||||
|
"/" => Operation::Divide,
|
||||||
|
"-" => Operation::Subtract,
|
||||||
|
"+" => Operation::Add,
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.unwrap_or(None);
|
||||||
|
|
||||||
|
let operand2 = tokens
|
||||||
|
.next()
|
||||||
|
.map(|token| Some(Operand::Reference(token.to_string())))
|
||||||
|
.unwrap_or(None);
|
||||||
|
|
||||||
|
let operand1 = if operand2.is_some() {
|
||||||
|
Operand::Reference(operand1.unwrap().to_string())
|
||||||
|
} else {
|
||||||
|
Operand::Number(
|
||||||
|
operand1
|
||||||
|
.unwrap()
|
||||||
|
.bytes()
|
||||||
|
.fold(0, |a, x| (a * 10) + (x - b'0') as i64),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
name.to_string(),
|
||||||
|
Monkey {
|
||||||
|
operand1,
|
||||||
|
op,
|
||||||
|
operand2,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solution(input: HashMap<String, Monkey>) -> i64 {
|
||||||
|
resolve(&input, "root")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve(input: &HashMap<String, Monkey>, key: &str) -> i64 {
|
||||||
|
if let Some(v) = input.get(key) {
|
||||||
|
match (&v.operand1, &v.op, &v.operand2) {
|
||||||
|
(Operand::Number(v), None, _) => *v,
|
||||||
|
(Operand::Reference(op1), Some(op), Some(Operand::Reference(op2))) => match op {
|
||||||
|
Operation::Divide => resolve(input, op1) / resolve(input, op2),
|
||||||
|
Operation::Multiply => resolve(input, op1) * resolve(input, op2),
|
||||||
|
Operation::Add => resolve(input, op1) + resolve(input, op2),
|
||||||
|
Operation::Subtract => resolve(input, op1) - resolve(input, op2),
|
||||||
|
},
|
||||||
|
|
||||||
|
(_, _, _) => unreachable!(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
for input in INPUTS.iter() {
|
||||||
|
let output = parse(input);
|
||||||
|
let score = solution(output);
|
||||||
|
println!("{}", score);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[bench]
|
||||||
|
fn solution_bench(b: &mut test::Bencher) {
|
||||||
|
b.iter(|| {
|
||||||
|
let input = parse(INPUTS[1]);
|
||||||
|
let result = solution(input);
|
||||||
|
test::black_box(result);
|
||||||
|
})
|
||||||
|
}
|
237
src/day21/2.rs
237
src/day21/2.rs
|
@ -0,0 +1,237 @@
|
||||||
|
#![feature(box_patterns)]
|
||||||
|
#![feature(test)]
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
extern crate test;
|
||||||
|
|
||||||
|
const INPUTS: [&str; 2] = [include_str!("./sample.txt"), include_str!("./input.txt")];
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum Operation {
|
||||||
|
Divide,
|
||||||
|
Multiply,
|
||||||
|
Add,
|
||||||
|
Subtract,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Monkey {
|
||||||
|
operand1: Operand,
|
||||||
|
op: Option<Operation>,
|
||||||
|
operand2: Option<Operand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Operand {
|
||||||
|
Number(i64),
|
||||||
|
Reference(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(input: &'static str) -> HashMap<String, Monkey> {
|
||||||
|
input
|
||||||
|
.lines()
|
||||||
|
.filter(|c| !c.is_empty())
|
||||||
|
.flat_map(|line| {
|
||||||
|
line.split_once(':').map(|(name, values)| {
|
||||||
|
let mut tokens = values.trim().splitn(3, ' ');
|
||||||
|
|
||||||
|
let operand1 = tokens.next();
|
||||||
|
|
||||||
|
let op = tokens
|
||||||
|
.next()
|
||||||
|
.map(|token| {
|
||||||
|
Some(match token {
|
||||||
|
"*" => Operation::Multiply,
|
||||||
|
"/" => Operation::Divide,
|
||||||
|
"-" => Operation::Subtract,
|
||||||
|
"+" => Operation::Add,
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.unwrap_or(None);
|
||||||
|
|
||||||
|
let operand2 = tokens
|
||||||
|
.next()
|
||||||
|
.map(|token| Some(Operand::Reference(token.to_string())))
|
||||||
|
.unwrap_or(None);
|
||||||
|
|
||||||
|
let operand1 = if operand2.is_some() {
|
||||||
|
Operand::Reference(operand1.unwrap().to_string())
|
||||||
|
} else {
|
||||||
|
Operand::Number(
|
||||||
|
operand1
|
||||||
|
.unwrap()
|
||||||
|
.bytes()
|
||||||
|
.fold(0, |a, x| (a * 10) + (x - b'0') as i64),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
name.to_string(),
|
||||||
|
Monkey {
|
||||||
|
operand1,
|
||||||
|
op,
|
||||||
|
operand2,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solution(input: HashMap<String, Monkey>) -> i64 {
|
||||||
|
let root = input.get("root").unwrap();
|
||||||
|
|
||||||
|
let (op1, op2) = match (&root.operand1, &root.operand2) {
|
||||||
|
(Operand::Reference(v), Some(Operand::Reference(c))) => (v.clone(), c.clone()),
|
||||||
|
(_, _) => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let answer = 0;
|
||||||
|
|
||||||
|
match (resolve(&input, &op1), resolve(&input, &op2)) {
|
||||||
|
(a, Computation::Known(b)) => {
|
||||||
|
let r = std::i64::MAX;
|
||||||
|
|
||||||
|
let mut pmid = 0;
|
||||||
|
for step in (0..=13).rev() {
|
||||||
|
let mut prev = None;
|
||||||
|
let l = pmid;
|
||||||
|
let s = 10usize.pow(step);
|
||||||
|
|
||||||
|
for mid in (l..=r).step_by(s) {
|
||||||
|
let value = rev_resolve(a.clone(), mid);
|
||||||
|
|
||||||
|
if let Some(p) = prev {
|
||||||
|
if p < b && value > b || p > b && value < b {
|
||||||
|
pmid = mid - s as i64;
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else if p == b {
|
||||||
|
return mid - s as i64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = Some(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Computation::Known(b), a) => {
|
||||||
|
let r = std::i64::MAX;
|
||||||
|
|
||||||
|
let mut pmid = 0;
|
||||||
|
for step in (0..=13).rev() {
|
||||||
|
let mut prev = None;
|
||||||
|
let l = pmid;
|
||||||
|
let s = 10usize.pow(step);
|
||||||
|
|
||||||
|
for mid in (l..=r).step_by(s) {
|
||||||
|
let value = rev_resolve(a.clone(), mid);
|
||||||
|
|
||||||
|
if let Some(p) = prev {
|
||||||
|
if p < b && value > b || p > b && value < b {
|
||||||
|
pmid = mid - s as i64;
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else if p == b {
|
||||||
|
return mid - s as i64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = Some(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(_, _) => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
answer
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rev_resolve(computation: Computation, num: i64) -> i64 {
|
||||||
|
match computation {
|
||||||
|
Computation::Known(v) => v,
|
||||||
|
Computation::Unknown => num,
|
||||||
|
Computation::Lazy(op1, op, op2) => match (op1, op, op2) {
|
||||||
|
(box Computation::Known(a), Operation::Divide, box Computation::Known(b)) => a / b,
|
||||||
|
(box Computation::Known(a), Operation::Divide, box b) => a / rev_resolve(b, num),
|
||||||
|
(a, Operation::Divide, box Computation::Known(b)) => rev_resolve(*a, num) / b,
|
||||||
|
|
||||||
|
(box Computation::Known(a), Operation::Multiply, box Computation::Known(b)) => a * b,
|
||||||
|
(box Computation::Known(a), Operation::Multiply, box b) => a * rev_resolve(b, num),
|
||||||
|
(a, Operation::Multiply, box Computation::Known(b)) => rev_resolve(*a, num) * b,
|
||||||
|
|
||||||
|
(box Computation::Known(a), Operation::Add, box Computation::Known(b)) => a + b,
|
||||||
|
(box Computation::Known(a), Operation::Add, box b) => a + rev_resolve(b, num),
|
||||||
|
(a, Operation::Add, box Computation::Known(b)) => rev_resolve(*a, num) + b,
|
||||||
|
|
||||||
|
(box Computation::Known(a), Operation::Subtract, box Computation::Known(b)) => a - b,
|
||||||
|
(box Computation::Known(a), Operation::Subtract, box b) => a - rev_resolve(b, num),
|
||||||
|
(a, Operation::Subtract, box Computation::Known(b)) => rev_resolve(*a, num) - b,
|
||||||
|
|
||||||
|
(_, _, _) => unreachable!(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum Computation {
|
||||||
|
Known(i64),
|
||||||
|
Unknown,
|
||||||
|
Lazy(Box<Computation>, Operation, Box<Computation>),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve(input: &HashMap<String, Monkey>, key: &str) -> Computation {
|
||||||
|
if let Some(v) = input.get(key) {
|
||||||
|
match (&v.operand1, &v.op, &v.operand2) {
|
||||||
|
(Operand::Number(v), None, _) => Computation::Known(*v),
|
||||||
|
(Operand::Reference(op1), Some(op), Some(Operand::Reference(op2))) => {
|
||||||
|
if op1 == "humn" {
|
||||||
|
Computation::Lazy(
|
||||||
|
Box::new(Computation::Unknown),
|
||||||
|
*op,
|
||||||
|
Box::new(resolve(input, op2)),
|
||||||
|
)
|
||||||
|
} else if op2 == "humn" {
|
||||||
|
Computation::Lazy(
|
||||||
|
Box::new(resolve(input, op1)),
|
||||||
|
*op,
|
||||||
|
Box::new(Computation::Unknown),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
match (resolve(input, op1), resolve(input, op2)) {
|
||||||
|
(Computation::Known(a), Computation::Known(b)) => {
|
||||||
|
Computation::Known(match op {
|
||||||
|
Operation::Divide => a / b,
|
||||||
|
Operation::Multiply => a * b,
|
||||||
|
Operation::Add => a + b,
|
||||||
|
Operation::Subtract => a - b,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
(a, b) => Computation::Lazy(Box::new(a), *op, Box::new(b)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(_, _, _) => unreachable!(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
for input in INPUTS.iter() {
|
||||||
|
let output = parse(input);
|
||||||
|
let score = solution(output);
|
||||||
|
println!("{}", score);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[bench]
|
||||||
|
fn solution_bench(b: &mut test::Bencher) {
|
||||||
|
b.iter(|| {
|
||||||
|
let input = parse(INPUTS[1]);
|
||||||
|
let result = solution(input);
|
||||||
|
test::black_box(result);
|
||||||
|
})
|
||||||
|
}
|
1677
src/day21/input.txt
Normal file
1677
src/day21/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
15
src/day21/sample.txt
Normal file
15
src/day21/sample.txt
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
root: pppw + sjmn
|
||||||
|
dbpl: 5
|
||||||
|
cczh: sllz + lgvd
|
||||||
|
zczc: 2
|
||||||
|
ptdq: humn - dvpt
|
||||||
|
dvpt: 3
|
||||||
|
lfqf: 4
|
||||||
|
humn: 5
|
||||||
|
ljgn: 2
|
||||||
|
sjmn: drzm * dbpl
|
||||||
|
sllz: 4
|
||||||
|
pppw: cczh / lfqf
|
||||||
|
lgvd: ljgn * ptdq
|
||||||
|
drzm: hmdt - zczc
|
||||||
|
hmdt: 32
|
Loading…
Reference in New Issue
Block a user