Improve code reuse

This commit is contained in:
2020-12-18 19:45:22 +01:00
parent 2d076ff5b9
commit 8ca3018837

View File

@@ -2,35 +2,41 @@ use std::io::Read;
use crate::common::Lines; use crate::common::Lines;
use crate::Solution; use crate::Solution;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
enum Op { enum Op {
Addition, Addition,
Multiplication, Multiplication,
} }
fn extract_brackets(with_brackets: &str) -> (&str, &str) { fn extract_part(expression: &str) -> (&str, &str) {
let mut brackets = 1; if expression.starts_with('(') {
let mut brackets = 1;
let mut end = None; for (end, c) in expression.chars().enumerate().skip(1) {
match c {
'(' => brackets += 1,
')' => brackets -= 1,
_ => {}
}
for (i, c) in with_brackets.chars().enumerate().skip(1) { if brackets == 0 {
match c { return (
'(' => brackets += 1, // Include the opening bracket for easier detection
')' => brackets -= 1, &expression[..end],
_ => {} expression.get((end + 2)..).unwrap_or(""),
);
}
} }
if brackets == 0 { panic!("Unmatched brackets: {}", expression);
end = Some(i); } else if let Some(pos) = expression.find(' ') {
break; (
} &expression[..pos],
expression.get((pos + 1)..).unwrap_or(""),
)
} else {
(expression, "")
} }
let end = end.expect("Unmatched brackets");
let next_start = with_brackets.len().min(end + 2);
(&with_brackets[1..end], &with_brackets[next_start..])
} }
fn compute_value(expression: &str) -> u64 { fn compute_value(expression: &str) -> u64 {
@@ -38,42 +44,28 @@ fn compute_value(expression: &str) -> u64 {
let mut value = 0; let mut value = 0;
let mut op = None; let mut op = None;
let mut apply_value = |n, op| match op {
Some(Op::Addition) => value += n,
Some(Op::Multiplication) => value *= n,
None => value = n,
};
while !remainder.is_empty() { while !remainder.is_empty() {
let pos = remainder.find(' '); let (part, rest) = extract_part(remainder);
remainder = rest;
let part = if let Some(pos) = pos { let n = match part.chars().next().unwrap() {
&remainder[..pos] '+' => {
} else { op = Some(Op::Addition);
remainder
};
match part.chars().next().unwrap() {
'+' => op = Some(Op::Addition),
'*' => op = Some(Op::Multiplication),
'(' => {
let (in_brackets, rest) = extract_brackets(remainder);
remainder = rest;
let n = compute_value(in_brackets);
apply_value(n, op);
// Skip the remainder update
continue; continue;
} }
c if c.is_ascii_digit() => { '*' => {
let n = part.parse().unwrap(); op = Some(Op::Multiplication);
apply_value(n, op); continue;
} }
_ => panic!("Not a valid expression part {}", part), '(' => compute_value(&part[1..]),
} _ => part.parse().unwrap(),
};
let pos = pos.map(|n| n + 1).unwrap_or_else(|| remainder.len()); match op {
remainder = &remainder[pos..]; Some(Op::Addition) => value += n,
Some(Op::Multiplication) => value *= n,
None => value = n,
}
} }
value value
@@ -85,46 +77,31 @@ fn compute_value2(expression: &str) -> u64 {
let mut result = 1; let mut result = 1;
let mut op = None; let mut op = None;
let mut apply_value = |n, op| match op {
Some(Op::Addition) => value += n,
Some(Op::Multiplication) => {
result *= value;
value = n;
}
None => value = n,
};
while !remainder.is_empty() { while !remainder.is_empty() {
let pos = remainder.find(' '); let (part, rest) = extract_part(remainder);
remainder = rest;
let part = if let Some(pos) = pos { let n = match part.chars().next().unwrap() {
&remainder[..pos] '+' => {
} else { op = Some(Op::Addition);
remainder
};
match part.chars().next().unwrap() {
'+' => op = Some(Op::Addition),
'*' => op = Some(Op::Multiplication),
'(' => {
let (in_brackets, rest) = extract_brackets(remainder);
remainder = rest;
let n = compute_value2(in_brackets);
apply_value(n, op);
// Skip the remainder update
continue; continue;
} }
c if c.is_ascii_digit() => { '*' => {
let n = part.parse().unwrap(); op = Some(Op::Multiplication);
continue;
apply_value(n, op);
} }
_ => panic!("Not a valid expression part {}", part), '(' => compute_value2(&part[1..]),
} _ => part.parse().unwrap(),
};
let pos = pos.map(|n| n + 1).unwrap_or_else(|| remainder.len()); match op {
remainder = &remainder[pos..]; Some(Op::Addition) => value += n,
Some(Op::Multiplication) => {
result *= value;
value = n;
}
None => value = n,
}
} }
result * value result * value