Day18
This commit is contained in:
parent
a22fbfbaee
commit
054ca54991
2 changed files with 170 additions and 0 deletions
168
src/day18.rs
Normal file
168
src/day18.rs
Normal file
|
@ -0,0 +1,168 @@
|
|||
use aoc_runner_derive::{aoc, aoc_generator};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||
pub enum Token {
|
||||
Num(i64),
|
||||
Add,
|
||||
Mul,
|
||||
LParen,
|
||||
RParen,
|
||||
}
|
||||
|
||||
impl Token {
|
||||
fn precedence(&self, part_2: bool) -> i64 {
|
||||
match self {
|
||||
Token::Add => {
|
||||
if part_2 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
Token::Mul => 0,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
struct RPN(VecDeque<Token>);
|
||||
|
||||
impl RPN {
|
||||
fn from_tokens(tokens: &[Token], part_2: bool) -> Self {
|
||||
let mut operators: Vec<Token> = Vec::new();
|
||||
let mut output: VecDeque<Token> = VecDeque::new();
|
||||
for token in tokens.iter().cloned() {
|
||||
match &token {
|
||||
Token::Num(_) => output.push_back(token),
|
||||
Token::Add | Token::Mul => {
|
||||
if let Some(top) = operators.last() {
|
||||
if (*top != Token::LParen)
|
||||
&& top.precedence(part_2) >= token.precedence(part_2)
|
||||
{
|
||||
output.push_back(operators.pop().unwrap())
|
||||
}
|
||||
}
|
||||
operators.push(token);
|
||||
}
|
||||
Token::LParen => operators.push(token),
|
||||
Token::RParen => {
|
||||
while Some(&Token::LParen) != operators.last() {
|
||||
output.push_back(operators.pop().expect("Unmatched parenthesis!"));
|
||||
}
|
||||
if let Some(Token::LParen) = operators.last() {
|
||||
operators.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while !operators.is_empty() {
|
||||
output.push_back(operators.pop().unwrap());
|
||||
}
|
||||
RPN(output)
|
||||
}
|
||||
|
||||
fn eval(&self) -> i64 {
|
||||
println!("{:?}", self.0);
|
||||
let mut stack = vec![];
|
||||
for token in &self.0 {
|
||||
match token {
|
||||
Token::Num(n) => {
|
||||
stack.push(*n);
|
||||
}
|
||||
Token::Add => {
|
||||
let a = stack.pop().unwrap();
|
||||
let b = stack.pop().unwrap();
|
||||
stack.push(a + b);
|
||||
}
|
||||
Token::Mul => {
|
||||
let a = stack.pop().unwrap();
|
||||
let b = stack.pop().unwrap();
|
||||
stack.push(a * b);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
if stack.len() != 1 {
|
||||
panic!("Error evaluating, leftover stack: {:?}", stack);
|
||||
}
|
||||
return stack.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl Token {
|
||||
fn lex(s: &str) -> Token {
|
||||
match s {
|
||||
"+" => Token::Add,
|
||||
"*" => Token::Mul,
|
||||
"(" => Token::LParen,
|
||||
")" => Token::RParen,
|
||||
n if n.chars().all(|c| c.is_numeric()) => Token::Num(n.parse().unwrap()),
|
||||
other => panic!("Failed to parse: {:?}", other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[aoc_generator(day18)]
|
||||
pub fn input_generator(input: &str) -> Vec<Vec<Token>> {
|
||||
let exprs: Vec<Vec<Token>> = input
|
||||
.lines()
|
||||
.map(|l| {
|
||||
println!("parsing: {:?}", l);
|
||||
l.replace("(", "( ")
|
||||
.replace(")", " )")
|
||||
.split_ascii_whitespace()
|
||||
.map(|s| Token::lex(s))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
exprs
|
||||
}
|
||||
|
||||
#[aoc(day18, part1)]
|
||||
pub fn solve_part1(input: &[Vec<Token>]) -> usize {
|
||||
input
|
||||
.iter()
|
||||
.map(|e| RPN::from_tokens(e, false).eval())
|
||||
.sum::<i64>() as usize
|
||||
}
|
||||
|
||||
#[aoc(day18, part2)]
|
||||
pub fn solve_part2(input: &[Vec<Token>]) -> usize {
|
||||
input
|
||||
.iter()
|
||||
.map(|e| RPN::from_tokens(e, true).eval())
|
||||
.sum::<i64>() as usize
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
#[test]
|
||||
fn part1() {
|
||||
use super::{input_generator, solve_part1};
|
||||
for (input, res) in &[
|
||||
("2 * 3 + (4 * 5)", 26),
|
||||
("1 + (2 * 3) + (4 * (5 + 6))", 51),
|
||||
("5 + (8 * 3 + 9 + 3 * 4 * 3)", 437),
|
||||
("5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))", 12240),
|
||||
("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2", 13632),
|
||||
] {
|
||||
assert_eq!(solve_part1(&input_generator(input)), *res, "{}", input);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2() {
|
||||
use super::{input_generator, solve_part2};
|
||||
for (input, res) in &[
|
||||
("2 * 3 + (4 * 5)", 46),
|
||||
("1 + (2 * 3) + (4 * (5 + 6))", 51),
|
||||
("5 + (8 * 3 + 9 + 3 * 4 * 3)", 1445),
|
||||
("5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))", 669060),
|
||||
("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2", 23340),
|
||||
] {
|
||||
assert_eq!(solve_part2(&input_generator(input)), *res, "{}", input);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,4 +18,6 @@ pub mod day15;
|
|||
pub mod day16;
|
||||
pub mod day17p1;
|
||||
pub mod day17p2;
|
||||
pub mod day18;
|
||||
// pub mod day18p2;
|
||||
aoc_lib! { year = 2020 }
|
||||
|
|
Loading…
Reference in a new issue