forked from akramer/advent
Implemented 18 part 1
=
This commit is contained in:
141
src/bin/18.rs
Normal file
141
src/bin/18.rs
Normal file
@@ -0,0 +1,141 @@
|
||||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader};
|
||||
|
||||
// call with a starting parenthesis.
|
||||
// returns the offset of the closing parenthesis
|
||||
fn find_matching_paren(input: &str) -> usize {
|
||||
let mut parens_count = 0;
|
||||
for (i, item) in input.chars().enumerate() {
|
||||
match item {
|
||||
'(' => parens_count += 1,
|
||||
')' => parens_count -= 1,
|
||||
_ => (),
|
||||
}
|
||||
if parens_count == 0 {
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// call with a first number, returns the length of the number
|
||||
fn find_number(input: &str) -> usize {
|
||||
let mut i= 0;
|
||||
for item in input.chars() {
|
||||
match item {
|
||||
'0'..='9' => (),
|
||||
_ => return i,
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Token<'a> {
|
||||
Number(i64),
|
||||
Operator(Binop),
|
||||
Parens(&'a str),
|
||||
End,
|
||||
}
|
||||
|
||||
type Binop = fn(i64, i64) -> i64;
|
||||
|
||||
fn add(a: i64, b: i64) -> i64 {
|
||||
a + b
|
||||
}
|
||||
|
||||
fn mul(a: i64, b: i64) -> i64 {
|
||||
a * b
|
||||
}
|
||||
|
||||
// returns the number of chars consumed, as well as a token.
|
||||
fn get_token(input: &str) -> (usize, Token) {
|
||||
let mut i : usize = 0;
|
||||
for item in input.chars() {
|
||||
match item {
|
||||
'(' => {
|
||||
let len = find_matching_paren(&input[i..]);
|
||||
return (i + len, Token::Parens(&input[i..i + len]));
|
||||
}
|
||||
'+' => {
|
||||
return (i + 1, Token::Operator(add));
|
||||
}
|
||||
'*' => {
|
||||
return (i + 1, Token::Operator(mul));
|
||||
}
|
||||
'0'..='9' => {
|
||||
let len = find_number(&input[i..]);
|
||||
let val = input[i..i+len].parse::<i64>().unwrap();
|
||||
return (i + len, Token::Number(val));
|
||||
}
|
||||
' ' => (),
|
||||
_ => panic!("Unexpected input!"),
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
(i, Token::End)
|
||||
}
|
||||
|
||||
// finds a left argument, right argument, and operator.
|
||||
// calls the operator on the args and returns the result.
|
||||
fn evaluate(input: &str) -> i64 {
|
||||
let mut left_val;
|
||||
let (offset, tok) = get_token(&input);
|
||||
match tok {
|
||||
Token::Number(n) => {
|
||||
left_val = n;
|
||||
},
|
||||
Token::Parens(p) => {
|
||||
left_val = evaluate(&p[1..p.len()-1]);
|
||||
},
|
||||
_ => panic!("expected a number or a parenthetical"),
|
||||
}
|
||||
|
||||
let mut input = &input[offset..];
|
||||
loop {
|
||||
let operator;
|
||||
let (offset, op) = get_token(&input);
|
||||
match op {
|
||||
Token::Operator(o) => {
|
||||
operator = o;
|
||||
},
|
||||
Token::End => {
|
||||
return left_val;
|
||||
}
|
||||
_ => panic!("expected an operator"),
|
||||
}
|
||||
|
||||
let right_val;
|
||||
input = &input[offset..];
|
||||
let (offset, right) = get_token(&input);
|
||||
match right {
|
||||
Token::Number(n) => {
|
||||
right_val = n;
|
||||
},
|
||||
Token::Parens(p) => {
|
||||
right_val = evaluate(&p[1..p.len()-1]);
|
||||
},
|
||||
_ => panic!("expected a number or a parenthetical"),
|
||||
}
|
||||
input = &input[offset..];
|
||||
left_val = operator(left_val, right_val)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let file = File::open("18.input")?;
|
||||
let reader = BufReader::new(file);
|
||||
let mut answer = 0;
|
||||
|
||||
for line in reader.lines() {
|
||||
answer += evaluate(&line?);
|
||||
}
|
||||
//println!("eval: {}", evaluate("6 * 2 * 6 + (8 + 8 * (5 + 4 * 7 + 6 + 6 + 3)) * 8"));
|
||||
println!("answer is: {}", answer);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user