From d40c7cb27b6fb048be09ea63a3bf2a0c0e59e471 Mon Sep 17 00:00:00 2001 From: Dylan Thies Date: Thu, 14 Dec 2023 22:00:58 -0500 Subject: [PATCH] day 14 part 1 done clippy and format --- 2023/Cargo.lock | 11 +++++ 2023/day-14/Cargo.toml | 17 +++++++ 2023/day-14/src/lib.rs | 4 ++ 2023/day-14/src/main.rs | 12 +++++ 2023/day-14/src/part1.rs | 98 ++++++++++++++++++++++++++++++++++++++++ 2023/day-14/src/part2.rs | 19 ++++++++ 6 files changed, 161 insertions(+) create mode 100644 2023/day-14/Cargo.toml create mode 100644 2023/day-14/src/lib.rs create mode 100644 2023/day-14/src/main.rs create mode 100644 2023/day-14/src/part1.rs create mode 100644 2023/day-14/src/part2.rs diff --git a/2023/Cargo.lock b/2023/Cargo.lock index 30d1b7c..cf4ef12 100644 --- a/2023/Cargo.lock +++ b/2023/Cargo.lock @@ -132,6 +132,17 @@ dependencies = [ "rstest", ] +[[package]] +name = "day-14" +version = "2023.0.0" +dependencies = [ + "glam", + "itertools", + "nom", + "nom_locate", + "rstest", +] + [[package]] name = "day-2" version = "2023.0.0" diff --git a/2023/day-14/Cargo.toml b/2023/day-14/Cargo.toml new file mode 100644 index 0000000..cff1a89 --- /dev/null +++ b/2023/day-14/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "day-14" +version.workspace = true +edition.workspace = true +authors.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nom = { workspace = true } +itertools = {workspace = true } +nom_locate.workspace = true +glam.workspace = true + +[dev-dependencies] +rstest.workspace = true diff --git a/2023/day-14/src/lib.rs b/2023/day-14/src/lib.rs new file mode 100644 index 0000000..3fafe8d --- /dev/null +++ b/2023/day-14/src/lib.rs @@ -0,0 +1,4 @@ +pub mod part1; +pub use crate::part1::*; +pub mod part2; +pub use crate::part2::*; diff --git a/2023/day-14/src/main.rs b/2023/day-14/src/main.rs new file mode 100644 index 0000000..4054c48 --- /dev/null +++ b/2023/day-14/src/main.rs @@ -0,0 +1,12 @@ +#![warn(clippy::all, clippy::pedantic)] + +use day_14::part1; +use day_14::part2; + +fn main() { + let input = include_str!("./input.txt"); + let part1_result = part1(input); + println!("part 1: {part1_result}"); + let part2_result = part2(input); + println!("part 2: {part2_result}"); +} diff --git a/2023/day-14/src/part1.rs b/2023/day-14/src/part1.rs new file mode 100644 index 0000000..0797489 --- /dev/null +++ b/2023/day-14/src/part1.rs @@ -0,0 +1,98 @@ +#![warn(clippy::all, clippy::pedantic)] + +use std::collections::HashMap; + +use glam::IVec2; +use itertools::Itertools; +use nom::{bytes::complete::is_a, character::complete, multi::separated_list1, IResult}; + +#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] +enum Boulder { + Round, + Static, +} +impl From for Boulder { + fn from(value: char) -> Self { + match value { + 'O' => Self::Round, + '#' => Self::Static, + x => unimplemented!("there is no boulder type for this charachter {x}"), + } + } +} + +/// day 14 part 1 of aoc 2023 +/// +/// # Arguments +/// - input the input for today's puzzle +/// +/// # Panics +/// panics whne it cannot parse the input OR when ever the number of game numbers is greater than +#[must_use] +#[allow(clippy::cast_sign_loss)] +pub fn part1(input: &str) -> String { + let (_, (maxes, map)) = parse_input(input).expect("stuff"); + + (0..maxes.x) + .map(|col| { + map.iter() + .filter(|(key, _)| key.x == col) + .sorted_by(|(a, _), (b, _)| a.y.cmp(&b.y)) + .fold((0, 0), |(score, last), (pos, boulde)| match boulde { + Boulder::Static => (score, pos.y + 1), + Boulder::Round => (score + maxes.y - last, last + 1), + }) + .0 as usize + }) + .sum::() + .to_string() +} + +fn parse_input(input: &str) -> IResult<&str, (IVec2, HashMap)> { + let (input, rows) = separated_list1(complete::line_ending, is_a(".O#"))(input)?; + let max_rows = i32::try_from(rows.len()).expect("stuff and things"); + let max_cols = i32::try_from(rows[0].len()).expect("things and stuff?"); + let maxs = IVec2::from((max_cols, max_rows)); + let hash = rows + .iter() + .enumerate() + .flat_map(|(line_no, chars)| { + chars + .chars() + .enumerate() + .filter_map(move |(col_no, c)| { + (c != '.').then_some(( + IVec2::from(( + i32::try_from(col_no).expect("hopefully not to small"), + i32::try_from(line_no).expect("this shouldn't be too big"), + )), + c, + )) + }) + .map(|(pos, c)| (pos, Boulder::from(c))) + }) + .collect(); + Ok((input, (maxs, hash))) +} + +#[cfg(test)] +mod test { + use super::*; + + const INPUT: &str = "O....#.... +O.OO#....# +.....##... +OO.#O....O +.O.....O#. +O.#..O.#.# +..O..#O..O +.......O.. +#....###.. +#OO..#...."; + + #[test] + fn part1_works() { + let result = part1(INPUT); + assert_eq!(result, "136".to_string()); + } +} diff --git a/2023/day-14/src/part2.rs b/2023/day-14/src/part2.rs new file mode 100644 index 0000000..d8e6695 --- /dev/null +++ b/2023/day-14/src/part2.rs @@ -0,0 +1,19 @@ +#![warn(clippy::all, clippy::pedantic)] + +#[must_use] +pub fn part2(_input: &str) -> String { + "Not Finished".to_string() +} + +#[cfg(test)] +mod test { + use super::*; + + const INPUT: &str = ""; + + #[test] + fn part2_works() { + let result = part2(INPUT); + assert_eq!(result, "Not Finished".to_string()); + } +}