diff --git a/2024/Cargo.lock b/2024/Cargo.lock index 7b396aa..9f7d6cd 100644 --- a/2024/Cargo.lock +++ b/2024/Cargo.lock @@ -15,6 +15,7 @@ dependencies = [ name = "aoc-2024" version = "0.1.0" dependencies = [ + "nom", "regex", ] @@ -24,6 +25,22 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "regex" version = "1.11.1" diff --git a/2024/Cargo.toml b/2024/Cargo.toml index 3f40e65..f393e12 100644 --- a/2024/Cargo.toml +++ b/2024/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] +nom = "7.1.3" regex = "1.11.1" diff --git a/2024/src/day3.rs b/2024/src/day3.rs index 5f37be5..497a3d5 100644 --- a/2024/src/day3.rs +++ b/2024/src/day3.rs @@ -1,3 +1,6 @@ +use nom::{ + branch::alt, bytes::complete::{tag, take_while}, character::{complete::anychar, is_digit}, combinator::eof, multi::{many1, many_till}, Err, Finish, IResult +}; use regex::Regex; const INPUT: &'static str = include_str!("../data/day3.txt"); @@ -17,7 +20,10 @@ struct State { impl Default for State { fn default() -> Self { - Self{ mult_enabled: true, value: 0 } + Self { + mult_enabled: true, + value: 0, + } } } @@ -25,7 +31,7 @@ impl Default for State { enum Operation { Do, Dont, - Mult(Multiplication) + Mult(Multiplication), } impl Operation { @@ -39,7 +45,7 @@ impl Operation { state.mult_enabled = false; state } - Operation::Mult(mul) => mul.run(state) + Operation::Mult(mul) => mul.run(state), } } } @@ -61,28 +67,13 @@ impl Multiplication { fn parse_input_a(input: &str) -> Vec { let re = Regex::new(r"mul\(([0-9]{1,3}),([0-9]{1,3})\)").unwrap(); - re.captures_iter(input).map(|capture| { - let x = capture.get(1).unwrap().as_str().parse::().unwrap(); - let y = capture.get(2).unwrap().as_str().parse::().unwrap(); - Operation::Mult(Multiplication{ x, y }) - }).collect::>() -} - -fn parse_input_b(input: &str) -> Vec { - let operation_re = Regex::new(r"do\(\)|don't\(\)|mul\(([0-9]{1,3}),([0-9]{1,3})\)").unwrap(); - - operation_re.captures_iter(input).map(|capture| { - match capture.get(0).unwrap().as_str()[0..4].as_ref() { - "do()" => Operation::Do, - "don'" => Operation::Dont, - "mul(" => { - let x = capture.get(1).unwrap().as_str().parse::().unwrap(); - let y = capture.get(2).unwrap().as_str().parse::().unwrap(); - Operation::Mult(Multiplication{ x, y }) - } - _ => unimplemented!() - } - }).collect::>() + re.captures_iter(input) + .map(|capture| { + let x = capture.get(1).unwrap().as_str().parse::().unwrap(); + let y = capture.get(2).unwrap().as_str().parse::().unwrap(); + Operation::Mult(Multiplication { x, y }) + }) + .collect::>() } fn calculate_part(lst: Vec) -> i32 { @@ -95,12 +86,53 @@ fn calculate_part(lst: Vec) -> i32 { state.value } +fn parse_input_b(input: &str) -> Vec { + match many1(next_operation)(input).finish() { + Ok((_, operations)) => operations, + v => panic!("something went wrong: {:?}", v), + } +} + +fn next_operation(input: &str) -> IResult<&str, Operation> { + let (rest, (_discard, operation)) = many_till(anychar, match_operation)(input)?; + Ok((rest, operation)) +} + +fn match_operation(input: &str) -> IResult<&str, Operation> { + alt((match_do, match_dont, match_mult))(input) +} + +fn match_do(input: &str) -> IResult<&str, Operation> { + let (rest, _) = tag("do()")(input)?; + Ok((rest, Operation::Do)) +} + +fn match_dont(input: &str) -> IResult<&str, Operation> { + let (rest, _) = tag("don't()")(input)?; + Ok((rest, Operation::Dont)) +} + +fn match_mult(input: &str) -> IResult<&str, Operation> { + let (rest, _) = tag("mul(")(input)?; + let (rest, x) = take_while(|c| is_digit(c as u8))(rest)?; + let (rest, _) = tag(",")(rest)?; + let (rest, y) = take_while(|c| is_digit(c as u8))(rest)?; + let (rest, _) = tag(")")(rest)?; + + Ok((rest, Operation::Mult(Multiplication { + x: x.parse::().unwrap(), + y: y.parse::().unwrap(), + }))) +} + #[cfg(test)] mod test { use super::*; - const TEST_INPUT_A: &'static str = "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))"; - const TEST_INPUT_B: &'static str = "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))"; + const TEST_INPUT_A: &'static str = + "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))"; + const TEST_INPUT_B: &'static str = + "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))"; #[test] fn it_solves_parta() { @@ -119,9 +151,9 @@ mod test { let muls = parse_input_a(TEST_INPUT_A); assert_eq!(muls.len(), 4); - assert_eq!(muls[0], Operation::Mult(Multiplication{ x: 2, y: 4 })); - assert_eq!(muls[1], Operation::Mult(Multiplication{ x: 5, y: 5 })); - assert_eq!(muls[2], Operation::Mult(Multiplication{ x: 11, y: 8 })); - assert_eq!(muls[3], Operation::Mult(Multiplication{ x: 8, y: 5 })); + assert_eq!(muls[0], Operation::Mult(Multiplication { x: 2, y: 4 })); + assert_eq!(muls[1], Operation::Mult(Multiplication { x: 5, y: 5 })); + assert_eq!(muls[2], Operation::Mult(Multiplication { x: 11, y: 8 })); + assert_eq!(muls[3], Operation::Mult(Multiplication { x: 8, y: 5 })); } }