A fun one! Day 18 done.

This commit is contained in:
2020-12-17 22:23:55 -08:00
parent 037560a567
commit 1e94d686ff
8 changed files with 556 additions and 0 deletions

106
src/bin/homework.rs Normal file
View File

@@ -0,0 +1,106 @@
use advent2020::errors::TopLevelError;
use advent2020::math::Math;
use std::env;
use std::fs;
#[test]
fn neutral_examples() {
assert_eq!(
71,
Math::new_neutral("1 + 2 * 3 + 4 * 5 + 6")
.unwrap()
.compute()
);
assert_eq!(
51,
Math::new_neutral("1 + (2 * 3) + (4 * (5 + 6))")
.unwrap()
.compute()
);
assert_eq!(26, Math::new_neutral("2 * 3 + (4 * 5)").unwrap().compute());
assert_eq!(
437,
Math::new_neutral("5 + (8 * 3 + 9 + 3 * 4 * 3)")
.unwrap()
.compute()
);
assert_eq!(
12240,
Math::new_neutral("5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))")
.unwrap()
.compute()
);
assert_eq!(
13632,
Math::new_neutral("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2")
.unwrap()
.compute()
);
}
#[test]
fn add_first_examples() {
assert_eq!(
231,
Math::new_add_first("1 + 2 * 3 + 4 * 5 + 6")
.unwrap()
.compute()
);
assert_eq!(
51,
Math::new_add_first("1 + (2 * 3) + (4 * (5 + 6))")
.unwrap()
.compute()
);
assert_eq!(
46,
Math::new_add_first("2 * 3 + (4 * 5)").unwrap().compute()
);
assert_eq!(
1445,
Math::new_add_first("5 + (8 * 3 + 9 + 3 * 4 * 3)")
.unwrap()
.compute()
);
assert_eq!(
669060,
Math::new_add_first("5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))")
.unwrap()
.compute()
);
assert_eq!(
23340,
Math::new_add_first("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2")
.unwrap()
.compute()
);
}
fn main() -> Result<(), TopLevelError> {
let filename = env::args().nth(1).expect("No file argument given.");
let contents = fs::read_to_string(filename)?;
let mut sum_neutral = 0;
let mut sum_add_first = 0;
for line in contents.lines() {
match Math::new_neutral(line) {
Ok(expr) => {
println!("{} ==> {}", line, expr.compute());
sum_neutral += expr.compute();
}
Err(e) => println!("PARSE ERROR: {}", e),
}
match Math::new_add_first(line) {
Ok(expr) => {
println!("{} ==> {}", line, expr.compute());
sum_add_first += expr.compute();
}
Err(e) => println!("PARSE ERROR: {}", e),
}
}
println!("Total (neutral ordering): {}", sum_neutral);
println!("Total (add-first ordering): {}", sum_add_first);
Ok(())
}

View File

@@ -1,2 +1,5 @@
extern crate lalrpop_util;
pub mod errors;
pub mod map;
pub mod math;

16
src/math.rs Normal file
View File

@@ -0,0 +1,16 @@
mod ast;
lalrpop_util::lalrpop_mod!(parse, "/math/parse.rs");
pub use crate::math::ast::Math;
use crate::math::parse::{ExprMulParser, ExprParser};
impl Math {
pub fn new_neutral(s: &str) -> Result<Math, String> {
ExprParser::new().parse(s).map_err(|x| format!("{}", x))
}
pub fn new_add_first(s: &str) -> Result<Math, String> {
ExprMulParser::new().parse(s).map_err(|x| format!("{}", x))
}
}

15
src/math/ast.rs Normal file
View File

@@ -0,0 +1,15 @@
pub enum Math {
Constant(usize),
Multiply(Box<Math>, Box<Math>),
Add(Box<Math>, Box<Math>),
}
impl Math {
pub fn compute(&self) -> usize {
match self {
Math::Constant(x) => *x,
Math::Multiply(a, b) => a.compute() * b.compute(),
Math::Add(a, b) => a.compute() + b.compute(),
}
}
}

32
src/math/parse.lalrpop Normal file
View File

@@ -0,0 +1,32 @@
use crate::math::ast::Math;
use std::str::FromStr;
grammar;
pub Expr: Math = {
<e1: Expr> "+" <e2: Term> => Math::Add(Box::new(e1), Box::new(e2)),
<e1: Expr> "*" <e2: Term> => Math::Multiply(Box::new(e1), Box::new(e2)),
<e: Term> => e,
}
Term: Math = {
<n:Num> => Math::Constant(n),
"(" <t:Expr> ")" => t,
};
pub ExprMul: Math = {
<e1: ExprMul> "*" <e2: ExprAdd> => Math::Multiply(Box::new(e1), Box::new(e2)),
<e: ExprAdd> => e,
}
ExprAdd: Math = {
<e1: ExprAdd> "+" <e2: ExprConst> => Math::Add(Box::new(e1), Box::new(e2)),
<e: ExprConst> => e,
}
ExprConst: Math = {
<n:Num> => Math::Constant(n),
"(" <t:ExprMul> ")" => t,
}
Num: usize = <s:r"[0-9]+"> => usize::from_str(s).unwrap();