diff --git a/Cargo.lock b/Cargo.lock index b489721..d1ea35c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,7 @@ name = "advent" version = "0.1.0" dependencies = [ "anyhow", + "nom", ] [[package]] @@ -12,3 +13,106 @@ name = "anyhow" version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "bitvec" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7ba35e9565969edb811639dbebfe34edc0368e472c5018474c8eb2543397f81" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "funty" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ba62103ce691c2fd80fbae2213dfdda9ce60804973ac6b6e97de818ea7f52c8" + +[[package]] +name = "lexical-core" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if", + "ryu", + "static_assertions", +] + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "nom" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88034cfd6b4a0d54dd14f4a507eceee36c0b70e5a02236c4e4df571102be17f0" +dependencies = [ + "bitvec", + "lexical-core", + "memchr", + "version_check", +] + +[[package]] +name = "radium" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "tap" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36474e732d1affd3a6ed582781b3683df3d0563714c59c39591e8ff707cf078e" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/Cargo.toml b/Cargo.toml index c879d58..5766742 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,5 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0" \ No newline at end of file +anyhow = "1.0" +nom = "6.0" \ No newline at end of file diff --git a/src/bin/18.rs b/src/bin/18.rs new file mode 100644 index 0000000..e748eb8 --- /dev/null +++ b/src/bin/18.rs @@ -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::().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(()) +}