diff --git a/2023/11/.gitignore b/2023/11/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/2023/11/.gitignore @@ -0,0 +1 @@ +/target diff --git a/2023/11/Cargo.toml b/2023/11/Cargo.toml new file mode 100644 index 0000000..4cec064 --- /dev/null +++ b/2023/11/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "y2023d11" +version = "0.1.0" +edition = "2024" + +[dependencies] +anyhow = "1.0.100" +itertools.workspace = true diff --git a/2023/11/data/example1 b/2023/11/data/example1 new file mode 100644 index 0000000..ca9fe3b --- /dev/null +++ b/2023/11/data/example1 @@ -0,0 +1 @@ +0 1 10 99 999 \ No newline at end of file diff --git a/2023/11/data/example2 b/2023/11/data/example2 new file mode 100644 index 0000000..528f9d5 --- /dev/null +++ b/2023/11/data/example2 @@ -0,0 +1 @@ +125 17 \ No newline at end of file diff --git a/2023/11/data/input b/2023/11/data/input new file mode 100644 index 0000000..d6ab1eb --- /dev/null +++ b/2023/11/data/input @@ -0,0 +1 @@ +3935565 31753 437818 7697 5 38 0 123 \ No newline at end of file diff --git a/2023/11/src/data.rs b/2023/11/src/data.rs new file mode 100644 index 0000000..0ef9295 --- /dev/null +++ b/2023/11/src/data.rs @@ -0,0 +1,8 @@ +#[cfg(test)] +pub const EXAMPLE1: &'static str = include_str!("../data/example1"); + +#[cfg(test)] +pub const EXAMPLE2: &'static str = include_str!("../data/example2"); + +#[allow(unused)] +pub const INPUT: &'static str = include_str!("../data/input"); diff --git a/2023/11/src/main.rs b/2023/11/src/main.rs new file mode 100644 index 0000000..f30aa50 --- /dev/null +++ b/2023/11/src/main.rs @@ -0,0 +1,11 @@ +mod data; +mod part1; +mod part2; +mod puzzle; +mod stone; + +fn main() { + use data::INPUT; + println!("Part 1: {}", part1::run(INPUT)); + println!("Part 2: {}", part2::run(INPUT)); +} diff --git a/2023/11/src/part1/mod.rs b/2023/11/src/part1/mod.rs new file mode 100644 index 0000000..f5a19c0 --- /dev/null +++ b/2023/11/src/part1/mod.rs @@ -0,0 +1,44 @@ +use crate::*; +use puzzle::Puzzle; +use stone::Stone; + +type Stones = Vec; + +pub fn blink(stones: &Stones) -> Stones { + stones.into_iter().flat_map(Stone::blink).collect() +} + +pub fn run(input: &str) -> usize { + let puzzle: Puzzle = input.parse().expect("parse failed"); + let mut stones = puzzle.0; + for _ in 0..25 { + stones = blink(&stones); + } + stones.len() +} + +#[cfg(test)] +mod test { + use super::*; + use anyhow::Result; + use data::EXAMPLE1; + use data::EXAMPLE2; + + #[test] + fn test_blink() -> Result<()> { + let puzzle: Puzzle = EXAMPLE1.parse()?; + assert_eq!( + blink(&puzzle.0), + [1, 2024, 1, 0, 9, 9, 2021976] + .into_iter() + .map(Stone) + .collect::() + ); + Ok(()) + } + + #[test] + fn test1() { + assert_eq!(run(EXAMPLE2), 55312); + } +} diff --git a/2023/11/src/part2/mod.rs b/2023/11/src/part2/mod.rs new file mode 100644 index 0000000..b151d8c --- /dev/null +++ b/2023/11/src/part2/mod.rs @@ -0,0 +1,48 @@ +use crate::*; +use itertools::Itertools; +use puzzle::Puzzle; +use std::collections::HashMap; +use stone::Stone; + +type Stones = HashMap; + +fn blink(stones: &Stones) -> Stones { + stones + .iter() + .flat_map(|(&stone, &count)| stone.blink().into_iter().map(move |stone| (stone, count))) + .into_grouping_map() + .sum() +} + +pub fn run(input: &str) -> usize { + let puzzle: Puzzle = input.parse().expect("parse failed"); + let mut stones: Stones = puzzle.0.iter().map(|&stone| (stone, 1usize)).collect(); + for _ in 0..75 { + stones = blink(&stones); + } + stones.into_iter().map(|(_, count)| count).sum() +} + +#[cfg(test)] +mod test { + use super::*; + use anyhow::Result; + use data::EXAMPLE1; + + #[test] + fn test_blink() -> Result<()> { + let puzzle: Puzzle = EXAMPLE1.parse()?; + let stones: Stones = puzzle.0.iter().copied().counts(); + assert_eq!( + blink(&stones), + Stones::from([ + (Stone(1), 2), + (Stone(2024), 1), + (Stone(0), 1), + (Stone(9), 2), + (Stone(2021976), 1) + ]) + ); + Ok(()) + } +} diff --git a/2023/11/src/puzzle.rs b/2023/11/src/puzzle.rs new file mode 100644 index 0000000..3179b5e --- /dev/null +++ b/2023/11/src/puzzle.rs @@ -0,0 +1,19 @@ +use crate::*; +use anyhow::Result; +use std::str::FromStr; +use stone::Stone; + +#[derive(Debug)] +pub struct Puzzle(pub Vec); + +impl FromStr for Puzzle { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + Ok(Puzzle( + s.split(' ') + .map(|s| Ok(Stone(s.parse()?))) + .collect::>()?, + )) + } +} diff --git a/2023/11/src/stone.rs b/2023/11/src/stone.rs new file mode 100644 index 0000000..4421a6a --- /dev/null +++ b/2023/11/src/stone.rs @@ -0,0 +1,25 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Stone(pub u64); + +impl Stone { + pub fn blink(&self) -> Vec { + match self.0 { + 0 => vec![Stone(1)], + n @ (10..100) => vec![Stone(n / 10), Stone(n % 10)], + n @ (1000..10000) => vec![Stone(n / 100), Stone(n % 100)], + n @ (100000..1000000) => vec![Stone(n / 1000), Stone(n % 1000)], + n @ (10000000..100000000) => vec![Stone(n / 10000), Stone(n % 10000)], + n @ (1000000000..10000000000) => vec![Stone(n / 100000), Stone(n % 100000)], + n @ (100000000000..1000000000000) => vec![Stone(n / 1000000), Stone(n % 1000000)], + n @ (10000000000000..100000000000000) => vec![Stone(n / 10000000), Stone(n % 10000000)], + n @ (1000000000000000..10000000000000000) => { + vec![Stone(n / 100000000), Stone(n % 100000000)] + } + n @ (100000000000000000..1000000000000000000) => { + vec![Stone(n / 1000000000), Stone(n % 1000000000)] + } + n @ (10000000000000000000..) => vec![Stone(n / 10000000000), Stone(n % 10000000000)], + n => vec![Stone(n * 2024)], + } + } +} diff --git a/Cargo.lock b/Cargo.lock index d6e0bbd..4817dbe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arrayvec" @@ -658,18 +658,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.15" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d76d3f064b981389ecb4b6b7f45a0bf9fdac1d5b9204c7bd6714fecc302850" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.15" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d29feb33e986b6ea906bd9c3559a856983f92371b3eaa5e83782a351623de0" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -797,6 +797,14 @@ dependencies = [ "thiserror", ] +[[package]] +name = "y2023d11" +version = "0.1.0" +dependencies = [ + "anyhow", + "itertools", +] + [[package]] name = "y2024d01" version = "0.1.0"