diff --git a/Cargo.lock b/Cargo.lock index d2835d6..b9143ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,12 +77,27 @@ dependencies = [ "rayon", ] +[[package]] +name = "day-06" +version = "0.0.0" +dependencies = [ + "indoc", + "nom", + "rayon", +] + [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "indoc" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" + [[package]] name = "itertools" version = "0.12.0" diff --git a/Cargo.toml b/Cargo.toml index 2ee7536..f963a3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,10 +4,12 @@ members = [ "day-01", "day-02", "day-03", - "day-05" + "day-05", + "day-06" ] [workspace.dependencies] +indoc = "2.0.4" itertools = "0.12.0" nom = "7.1.3" rayon = "1.8.0" diff --git a/day-06/Cargo.toml b/day-06/Cargo.toml new file mode 100644 index 0000000..2a25ec8 --- /dev/null +++ b/day-06/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "day-06" +version = "0.0.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +indoc.workspace = true +nom.workspace = true +rayon.workspace = true diff --git a/day-06/src/bin/input.txt b/day-06/src/bin/input.txt new file mode 100644 index 0000000..3d11c9c --- /dev/null +++ b/day-06/src/bin/input.txt @@ -0,0 +1,2 @@ +Time: 46 82 84 79 +Distance: 347 1522 1406 1471 \ No newline at end of file diff --git a/day-06/src/bin/part1.rs b/day-06/src/bin/part1.rs new file mode 100644 index 0000000..9b54068 --- /dev/null +++ b/day-06/src/bin/part1.rs @@ -0,0 +1,68 @@ +use nom::{ + bytes::complete::tag, + character::complete::{self, newline, space1}, + multi::separated_list1, + sequence::{pair, preceded, separated_pair}, + IResult, Parser, +}; + +fn main() { + println!("{}", part1(include_str!("./input.txt"))); +} + +fn part1(input: &str) -> u64 { + separated_pair(time_parser, newline, distance_parser) + .map(|(times, distances)| { + times + .into_iter() + .zip(distances) + .map(|(time, distance)| calc_game(time, distance) as u64) + .product::() + }) + .parse(input) + .unwrap() + .1 +} + +fn time_parser(i: &str) -> IResult<&str, Vec> { + preceded( + pair(tag("Time:"), space1), + separated_list1(space1, complete::u32), + )(i) +} + +fn distance_parser(i: &str) -> IResult<&str, Vec> { + preceded( + pair(tag("Distance:"), space1), + separated_list1(space1, complete::u32), + )(i) +} + +fn calc_game(time: u32, distance: u32) -> u32 { + (1..time) + .filter_map(|t| (calc_distance(t, time) > distance).then_some(())) + .count() as u32 +} + +fn calc_distance(hold_time: u32, total_time: u32) -> u32 { + hold_time * (total_time - hold_time) +} + +#[cfg(test)] +mod tests { + use super::*; + use indoc::indoc; + + #[test] + fn test_part1() { + assert_eq!( + part1(indoc!( + " + Time: 7 15 30 + Distance: 9 40 200 + " + )), + 288 + ); + } +} diff --git a/day-06/src/bin/part2.rs b/day-06/src/bin/part2.rs new file mode 100644 index 0000000..fea9b45 --- /dev/null +++ b/day-06/src/bin/part2.rs @@ -0,0 +1,65 @@ +use nom::{ + bytes::complete::tag, + character::complete::{digit1, newline, space1}, + multi::separated_list1, + sequence::{pair, preceded, separated_pair}, + IResult, Parser, +}; +use rayon::prelude::*; + +fn main() { + println!("{}", part2(include_str!("./input.txt"))); +} + +fn part2(input: &str) -> u64 { + separated_pair(time_parser, newline, distance_parser) + .map(|(time, distance)| calc_game(time, distance)) + .parse(input) + .unwrap() + .1 +} + +fn time_parser(i: &str) -> IResult<&str, u64> { + preceded(pair(tag("Time:"), space1), separated_list1(space1, digit1)) + .map(|strs| strs.join("").parse::().expect("Invalid digit")) + .parse(i) +} + +fn distance_parser(i: &str) -> IResult<&str, u64> { + preceded( + pair(tag("Distance:"), space1), + separated_list1(space1, digit1), + ) + .map(|strs| strs.join("").parse::().expect("Invalid digit")) + .parse(i) +} + +fn calc_game(time: u64, distance: u64) -> u64 { + (1..time) + .into_par_iter() + .filter_map(|t| (calc_distance(t, time) > distance).then_some(())) + .count() as u64 +} + +fn calc_distance(hold_time: u64, total_time: u64) -> u64 { + hold_time * (total_time - hold_time) +} + +#[cfg(test)] +mod tests { + use super::*; + use indoc::indoc; + + #[test] + fn test_part1() { + assert_eq!( + part2(indoc!( + " + Time: 7 15 30 + Distance: 9 40 200 + " + )), + 288 + ); + } +}