diff --git a/rust/main.rs b/rust/main.rs index f13bccc..82e857e 100644 --- a/rust/main.rs +++ b/rust/main.rs @@ -3,9 +3,10 @@ mod puzzles; use crate::puzzle::Puzzle; use puzzles::day1; use puzzles::day2; +use puzzles::day3; use std::fs; -const PUZZLES: [&dyn SomePuzzle; 2] = [&day1::PUZZLE, &day2::PUZZLE]; +const PUZZLES: [&dyn SomePuzzle; 3] = [&day1::PUZZLE, &day2::PUZZLE, &day3::PUZZLE]; fn main() { [false, true].iter().for_each(|is_real_data| { diff --git a/rust/puzzles/day3.rs b/rust/puzzles/day3.rs new file mode 100644 index 0000000..1e05ff0 --- /dev/null +++ b/rust/puzzles/day3.rs @@ -0,0 +1,70 @@ +use crate::puzzle::Puzzle; +use nom::{ + Parser, + character::complete::{newline, satisfy}, + combinator::eof, + error::Error, + multi::{many1, separated_list1}, + sequence::terminated, +}; + +pub const PUZZLE: Puzzle>, 2> = Puzzle { + number: 3, + parser: |input| { + terminated::<_, _, Error<&str>, _, _>( + terminated( + separated_list1( + newline, + many1(satisfy(|c| c.is_digit(10)).map(|c| c as u8 - '0' as u8)), + ), + newline, + ), + eof, + ) + .parse(input) + .unwrap() + .1 + }, + parts: [ + |input| { + input + .iter() + .map(|bank| { + digits_to_int(&max_batteries(2, &bank).expect("battery list too short")) + }) + .sum::() + .to_string() + }, + |input| { + input + .iter() + .map(|bank| { + digits_to_int(&max_batteries(12, &bank).expect("battery list too short")) + }) + .sum::() + .to_string() + }, + ], +}; + +fn max_batteries(n: usize, v: &[u8]) -> Option> { + let mut result = Vec::with_capacity(n); + let mut remaining = n; + let mut slice = v; + while remaining > 0 { + let (b, i) = find_max(&slice[..slice.len() - remaining + 1]); + result.push(b); + remaining -= 1; + slice = &slice[i + 1..]; + } + Some(result) +} + +fn find_max(v: &[A]) -> (A, usize) { + let (n, x) = v.iter().enumerate().rev().max_by_key(|x| x.1).unwrap(); + (*x, n) +} + +fn digits_to_int(digits: &[u8]) -> usize { + digits.iter().fold(0, |acc, &d| acc * 10 + (d as usize)) +} diff --git a/rust/puzzles/mod.rs b/rust/puzzles/mod.rs index 7daf67a..96606ab 100644 --- a/rust/puzzles/mod.rs +++ b/rust/puzzles/mod.rs @@ -1,2 +1,3 @@ pub(crate) mod day1; pub(crate) mod day2; +pub(crate) mod day3;