Switch day3b to a nom parser

This commit is contained in:
Savanni D'Gerinel 2024-12-04 21:16:40 -05:00
parent e121e53258
commit c170aee068
3 changed files with 81 additions and 31 deletions

17
2024/Cargo.lock generated
View File

@ -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"

View File

@ -4,4 +4,5 @@ version = "0.1.0"
edition = "2021"
[dependencies]
nom = "7.1.3"
regex = "1.11.1"

View File

@ -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<Operation> {
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::<i32>().unwrap();
let y = capture.get(2).unwrap().as_str().parse::<i32>().unwrap();
Operation::Mult(Multiplication{ x, y })
}).collect::<Vec<Operation>>()
}
fn parse_input_b(input: &str) -> Vec<Operation> {
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::<i32>().unwrap();
let y = capture.get(2).unwrap().as_str().parse::<i32>().unwrap();
Operation::Mult(Multiplication{ x, y })
}
_ => unimplemented!()
}
}).collect::<Vec<Operation>>()
re.captures_iter(input)
.map(|capture| {
let x = capture.get(1).unwrap().as_str().parse::<i32>().unwrap();
let y = capture.get(2).unwrap().as_str().parse::<i32>().unwrap();
Operation::Mult(Multiplication { x, y })
})
.collect::<Vec<Operation>>()
}
fn calculate_part(lst: Vec<Operation>) -> i32 {
@ -95,12 +86,53 @@ fn calculate_part(lst: Vec<Operation>) -> i32 {
state.value
}
fn parse_input_b(input: &str) -> Vec<Operation> {
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::<i32>().unwrap(),
y: y.parse::<i32>().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 }));
}
}