From 1541b82c114ace9177f26d93e588d5714f972949 Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Fri, 1 Dec 2023 11:21:05 +0100 Subject: [PATCH] Implement 2023 day 1 part 2 --- 2023/Cargo.toml | 9 +++++++ 2023/benches/days.rs | 2 +- 2023/src/day01.rs | 52 ++++++++++++++++++++++++++++++++++++--- 2023/src/samples/01.1.txt | 4 +++ 2023/src/samples/01.2.txt | 7 ++++++ 5 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 2023/src/samples/01.1.txt create mode 100644 2023/src/samples/01.2.txt diff --git a/2023/Cargo.toml b/2023/Cargo.toml index a5d649c..d855299 100644 --- a/2023/Cargo.toml +++ b/2023/Cargo.toml @@ -9,6 +9,15 @@ edition = "2021" anyhow = "1.0.75" clap = { version = "4.4.8", features = ["derive"] } nom = "7.1.3" +regex = "1.10.2" [dev-dependencies] criterion = "0.5.1" + +[profile.release] +# Keep debug information in release for better flamegraphs +debug = true + +[[bench]] +name = "days" +harness = false diff --git a/2023/benches/days.rs b/2023/benches/days.rs index ed0120e..95533c3 100644 --- a/2023/benches/days.rs +++ b/2023/benches/days.rs @@ -9,7 +9,7 @@ use criterion::Criterion; use aoc_2023::get_implementation; /// Number of days we have an implementation to benchmark -const DAYS_IMPLEMENTED: u8 = 0; +const DAYS_IMPLEMENTED: u8 = 1; fn read_input(day: u8) -> std::io::Result> { let input_path = format!("inputs/{day:02}.txt"); diff --git a/2023/src/day01.rs b/2023/src/day01.rs index b1f7ef2..07cb0e1 100644 --- a/2023/src/day01.rs +++ b/2023/src/day01.rs @@ -1,4 +1,5 @@ use anyhow::Result; +use regex::bytes::Regex; pub fn part1(input: &[u8]) -> Result { let mut it = input.iter(); @@ -30,18 +31,63 @@ pub fn part1(input: &[u8]) -> Result { Ok(sum.to_string()) } -pub fn part2(_input: &[u8]) -> Result { - anyhow::bail!("Not implemented") +fn parse_string_digit(digit: &[u8]) -> Result { + Ok(match digit { + b"one" => 1, + b"two" => 2, + b"three" => 3, + b"four" => 4, + b"five" => 5, + b"six" => 6, + b"seven" => 7, + b"eight" => 8, + b"nine" => 9, + &[d] => u32::from(d - b'0'), + other => anyhow::bail!("invalid digit: {}", String::from_utf8_lossy(other)), + }) +} + +// 53255: too low +pub fn part2(input: &[u8]) -> Result { + let parser = Regex::new(r"[1-9]|one|two|three|four|five|six|seven|eight|nine")?; + let mut sum = 0; + + for line in input.split(|&c| c == b'\n') { + let mut first = None; + let mut last = &b""[..]; + + let mut start = 0; + + // Cannot use find_iter because it doesn't find overlapping matches. + while let Some(needle) = parser.find_at(line, start) { + start = needle.start() + 1; + let digit = needle.as_bytes(); + first.get_or_insert(digit); + last = digit; + } + + if let Some(first) = first { + sum += 10 * parse_string_digit(first)? + parse_string_digit(last)?; + } + } + + Ok(sum.to_string()) } #[cfg(test)] mod tests { use super::*; - const SAMPLE: &[u8] = include_bytes!("samples/01.txt"); + const SAMPLE: &[u8] = include_bytes!("samples/01.1.txt"); + const SAMPLE2: &[u8] = include_bytes!("samples/01.2.txt"); #[test] fn sample_part1() { assert_eq!("142", part1(SAMPLE).unwrap()); } + + #[test] + fn sample_part2() { + assert_eq!("281", part2(SAMPLE2).unwrap()); + } } diff --git a/2023/src/samples/01.1.txt b/2023/src/samples/01.1.txt new file mode 100644 index 0000000..7bbc69a --- /dev/null +++ b/2023/src/samples/01.1.txt @@ -0,0 +1,4 @@ +1abc2 +pqr3stu8vwx +a1b2c3d4e5f +treb7uchet diff --git a/2023/src/samples/01.2.txt b/2023/src/samples/01.2.txt new file mode 100644 index 0000000..41aa89c --- /dev/null +++ b/2023/src/samples/01.2.txt @@ -0,0 +1,7 @@ +two1nine +eightwothree +abcone2threexyz +xtwone3four +4nineeightseven2 +zoneight234 +7pqrstsixteen