From f1812b5ee061f2e6bd2c33d781504a4ffd427f0f Mon Sep 17 00:00:00 2001 From: LongHairedHacker Date: Fri, 18 Dec 2020 17:11:35 +0100 Subject: [PATCH] Added day 18 part2 --- src/bin/day18.rs | 243 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 194 insertions(+), 49 deletions(-) diff --git a/src/bin/day18.rs b/src/bin/day18.rs index c229950..4264da0 100644 --- a/src/bin/day18.rs +++ b/src/bin/day18.rs @@ -3,23 +3,21 @@ use std::fs::File; use std::io::{self, BufRead}; use std::vec::Vec; -fn extract_paren_expression(input: &str) -> String { - let mut res: String = "".to_string(); - let mut open_count = 1; +fn read_paren_expression(input: &str) -> (&str, &str) { + let mut open_count = 0; let mut close_count = 0; - for c in input[1..].chars() { - match c { + for i in 0..input.len() { + match input.chars().nth(i).unwrap() { '(' => open_count += 1, ')' => { close_count += 1; if open_count == close_count { - return res; + return (&input[1..i], &input[i + 1..]); } } _ => {} } - res += &c.to_string(); } panic!( @@ -28,40 +26,114 @@ fn extract_paren_expression(input: &str) -> String { ); } -fn extract_number(input: &str) -> String { - input.chars().take_while(|c| c.is_ascii_digit()).collect() +fn read_number(input: &str) -> (&str, &str) { + for i in 0..input.len() { + if !input.chars().nth(i).unwrap().is_ascii_digit() { + return (&input[0..i], &input[i..]); + } + } + return (input, ""); } -fn eval_expression(input: &str) -> u64 { - let mut clean: String = input.chars().filter(|c| *c != ' ').collect(); - let mut res = 0; - let mut op = '^'; +#[derive(PartialEq, Clone, Debug)] +enum Expression { + Num(u64), + OpAdd, + OpMul, + SubExpr(Vec), +} - while clean != "" { - let c = clean.chars().nth(0).unwrap(); +fn parse_expression(input: &str) -> Vec { + let mut expr = Vec::new(); + let mut rest = input; + + while rest != "" { + let c = rest.chars().nth(0).unwrap(); if c.is_ascii_digit() { - let substr = extract_number(&clean); - clean = clean[substr.len()..].to_string(); - let num: u64 = substr.parse().unwrap(); - match op { - '^' => res = num, - '+' => res += num, - '*' => res *= num, - _ => panic!("Unsupported Op: {}", op), - } - } else if c == '+' || c == '*' { - op = c; - clean = clean[1..].to_string(); + let (substr, tail) = read_number(rest); + expr.push(Expression::Num(substr.parse().unwrap())); + rest = tail; } else if c == '(' { - let substr = extract_paren_expression(&clean); - clean = clean[substr.len() + 2..].to_string(); - let num = eval_expression(&substr); - match op { - '^' => res = num, - '+' => res += num, - '*' => res *= num, - _ => panic!("Unsupported Op: {}", op), + let (substr, tail) = read_paren_expression(rest); + expr.push(Expression::SubExpr(parse_expression(substr))); + rest = tail; + } else if c == '+' { + expr.push(Expression::OpAdd); + rest = &rest[1..]; + } else if c == '*' { + expr.push(Expression::OpMul); + rest = &rest[1..]; + } else { + rest = &rest[1..]; + } + } + + expr +} + +fn eval_part1(expr: &Vec) -> u64 { + let subexpr_eval = expr.iter().map(|e| match e { + Expression::SubExpr(subexpr) => Expression::Num(eval_part1(subexpr)), + _ => e.clone(), + }); + + let mut res = 0; + let mut op = Expression::OpAdd; + for e in subexpr_eval { + match e { + Expression::Num(n) => match op { + Expression::OpAdd => res += n, + Expression::OpMul => res *= n, + _ => panic!("Malformed expression. Not an op."), + }, + Expression::OpAdd => op = Expression::OpAdd, + Expression::OpMul => op = Expression::OpMul, + _ => panic!("Malformed expression."), + } + } + + res +} + +fn eval_part2(expr: &Vec) -> u64 { + let subexpr_eval: Vec = expr + .iter() + .map(|e| match e { + Expression::SubExpr(subexpr) => Expression::Num(eval_part2(subexpr)), + _ => e.clone(), + }) + .collect(); + + let mut mul_eval: Vec = Vec::new(); + let mut i = 0; + while i < subexpr_eval.len() { + match subexpr_eval[i] { + Expression::OpAdd => { + if let Expression::Num(n1) = mul_eval.pop().unwrap() { + if let Expression::Num(n2) = subexpr_eval[i + 1] { + mul_eval.push(Expression::Num(n1 + n2)); + i += 2; + } else { + panic!("Malformed expression: Expected Number") + } + } else { + panic!("Malformed expression: Expected Number") + } } + _ => { + mul_eval.push(subexpr_eval[i].clone()); + i += 1; + } + } + } + + let mut res = 1; + + for e in mul_eval { + match e { + Expression::Num(n) => res *= n, + Expression::OpMul => {} + _ => panic!("Malformed expression."), } } @@ -72,8 +144,15 @@ fn main() -> Result<(), Box> { let file = File::open("inputs/day18.txt")?; let lines = io::BufReader::new(file).lines().map(|l| l.unwrap()); - let res = lines.map(|l| eval_expression(&l)).fold(0, |x, y| x + y); - println!("Answer: {}", res); + let exprs: Vec> = lines.map(|l| parse_expression(&l)).collect(); + + let result1 = exprs.iter().map(|e| eval_part1(e)).fold(0, |x, y| x + y); + + println!("Answer Part 1: {}", result1); + + let result2 = exprs.iter().map(|e| eval_part2(e)).fold(0, |x, y| x + y); + + println!("Answer Part 2: {}", result2); Ok(()) } @@ -83,31 +162,97 @@ mod tests { use crate::*; #[test] - fn test_extractor() { + fn test_paren_expression() { assert_eq!( - extract_paren_expression("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2"), - "(2 + 4 * 9) * (6 + 9 * 8 + 6) + 6" + read_paren_expression("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2"), + ("(2 + 4 * 9) * (6 + 9 * 8 + 6) + 6", " + 2 + 4 * 2") ); } #[test] - fn test_basics() { - assert_eq!(eval_expression("23"), 23); - assert_eq!(eval_expression("2 + 3 * 4"), 20); - assert_eq!(eval_expression("2 + (3 * 4)"), 14); + fn test_number() { + assert_eq!(read_number("243 + 3"), ("243", " + 3"),); } #[test] - fn test_problems() { - assert_eq!(eval_expression("2 * 3 + (4 * 5)"), 26); - assert_eq!(eval_expression("5 + (8 * 3 + 9 + 3 * 4 * 3)"), 437); + fn test_parse() { + assert_eq!(parse_expression("23"), vec![Expression::Num(23)]); assert_eq!( - eval_expression("5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))"), + parse_expression("2 + 3 * 4"), + vec![ + Expression::Num(2), + Expression::OpAdd, + Expression::Num(3), + Expression::OpMul, + Expression::Num(4) + ] + ); + assert_eq!( + parse_expression("2 + (3 * 4)"), + vec![ + Expression::Num(2), + Expression::OpAdd, + Expression::SubExpr(vec![ + Expression::Num(3), + Expression::OpMul, + Expression::Num(4) + ]) + ] + ); + } + + #[test] + fn test_basics1() { + assert_eq!(eval_part1(&parse_expression("23")), 23); + assert_eq!(eval_part1(&parse_expression("2 + 3 * 4")), 20); + assert_eq!(eval_part1(&parse_expression("2 + (3 * 4)")), 14); + } + + fn test_basics2() { + assert_eq!(eval_part2(&parse_expression("23")), 23); + assert_eq!(eval_part2(&parse_expression("2 + 3 * 2 * 3 + 2")), 50); + assert_eq!(eval_part2(&parse_expression("2 + (3 * 4)")), 14); + } + + #[test] + fn test_problems1() { + assert_eq!(eval_part1(&parse_expression("2 * 3 + (4 * 5)")), 26); + assert_eq!( + eval_part1(&parse_expression("5 + (8 * 3 + 9 + 3 * 4 * 3)")), + 437 + ); + assert_eq!( + eval_part1(&parse_expression( + "5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))" + )), 12240 ); assert_eq!( - eval_expression("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2"), + eval_part1(&parse_expression( + "((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2" + )), 13632 ); } + + #[test] + fn test_problems2() { + assert_eq!(eval_part2(&parse_expression("2 * 3 + (4 * 5)")), 46); + assert_eq!( + eval_part2(&parse_expression("5 + (8 * 3 + 9 + 3 * 4 * 3)")), + 1445 + ); + assert_eq!( + eval_part2(&parse_expression( + "5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))" + )), + 669060 + ); + assert_eq!( + eval_part2(&parse_expression( + "((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2" + )), + 23340 + ); + } }