From 6a9783b7c65231f9d95d133c237296de2d263e90 Mon Sep 17 00:00:00 2001 From: Chris Alge Date: Sat, 9 Nov 2024 13:56:47 +0100 Subject: [PATCH] Add 2024 Quest 3 --- 2024/day03_mining_maestro/Cargo.toml | 6 + 2024/day03_mining_maestro/src/lib.rs | 143 +++++++++++++++++++++ 2024/day03_mining_maestro/tests/challenge1 | 14 ++ 2024/day03_mining_maestro/tests/challenge2 | 35 +++++ 2024/day03_mining_maestro/tests/challenge3 | 52 ++++++++ 2024/day03_mining_maestro/tests/sample1 | 7 + 2024/day03_mining_maestro/tests/sample2 | 7 + 2024/day03_mining_maestro/tests/sample3 | 7 + 8 files changed, 271 insertions(+) create mode 100644 2024/day03_mining_maestro/Cargo.toml create mode 100644 2024/day03_mining_maestro/src/lib.rs create mode 100644 2024/day03_mining_maestro/tests/challenge1 create mode 100644 2024/day03_mining_maestro/tests/challenge2 create mode 100644 2024/day03_mining_maestro/tests/challenge3 create mode 100644 2024/day03_mining_maestro/tests/sample1 create mode 100644 2024/day03_mining_maestro/tests/sample2 create mode 100644 2024/day03_mining_maestro/tests/sample3 diff --git a/2024/day03_mining_maestro/Cargo.toml b/2024/day03_mining_maestro/Cargo.toml new file mode 100644 index 0000000..54ad570 --- /dev/null +++ b/2024/day03_mining_maestro/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "day03_mining_maestro" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/2024/day03_mining_maestro/src/lib.rs b/2024/day03_mining_maestro/src/lib.rs new file mode 100644 index 0000000..61c4f1e --- /dev/null +++ b/2024/day03_mining_maestro/src/lib.rs @@ -0,0 +1,143 @@ +use core::fmt::Display; + +#[derive(Debug, PartialEq, Eq)] +pub enum ParseError { + GridMalformed(usize, usize, usize), + InvalidTile(char), +} + +impl Display for ParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::GridMalformed(first, idx, len) => write!(f, "Input Grid is not rectangular. First line has {first} characters, but line {idx} has {len}."), + Self::InvalidTile(e) => write!(f, "Unable to parse into a tile: {e}"), + } + } +} + +struct Map { + map: Vec>, + height: usize, + width: usize, +} + +impl TryFrom<&str> for Map { + type Error = ParseError; + + fn try_from(value: &str) -> Result { + let lines: Vec<_> = value.lines().collect(); + if lines.is_empty() { + return Ok(Self { map: vec![vec![]], height: 0, width: 0, }); + } + let width = lines[0].len(); + let mut map = vec![vec![0; width]; lines.len()]; + for (y, l) in lines.iter().enumerate() { + if l.len() != width { + return Err(Self::Error::GridMalformed(width, y, l.len())); + } + for (x, c) in l.chars().enumerate() { + match c { + '.' => (), + '#' => map[y][x] = 1, + e => return Err(Self::Error::InvalidTile(e)), + } + } + } + Ok(Self { map, height: lines.len(), width }) + } +} + +impl Map{ + fn at_or_zero(&self, (x, y): (usize, usize)) -> usize { + if x >= self.width || y >= self.height { 0 } else { self.map[y][x] } + } + + fn neighbours(&self, (x, y): (usize, usize), royal: bool) -> Vec { + let mut res = if royal { + vec![ + self.at_or_zero((x.wrapping_sub(1), y)), + self.at_or_zero((x+1, y)), + self.at_or_zero((x, y.wrapping_sub(1))), + self.at_or_zero((x, y+1)), + self.at_or_zero((x.wrapping_sub(1), y.wrapping_sub(1))), + self.at_or_zero((x+1, y.wrapping_sub(1))), + self.at_or_zero((x.wrapping_sub(1), y+1)), + self.at_or_zero((x+1, y+1)), + ] + } else { + vec![ + self.at_or_zero((x.wrapping_sub(1), y)), + self.at_or_zero((x+1, y)), + self.at_or_zero((x, y.wrapping_sub(1))), + self.at_or_zero((x, y+1)), + ] + }; + res.sort(); + res + } + + fn maximize(&mut self, royal: bool) { + let (x_min, y_min, x_max, y_max) = if royal { + (0, 0, self.width, self.height) + } else { + (1, 1, self.width-1, self.height-1) + }; + loop { + let mut changed = false; + (x_min..x_max).for_each(|x| + (y_min..y_max).for_each(|y| { + let curr = self.map[y][x]; + let lowest = *self.neighbours((x, y), royal).first().unwrap_or(&0); + if curr > 0 && lowest >= curr { + self.map[y][x] = lowest + 1; + changed = true; + } + })); + if !changed { + return; + } + } + } + + fn total_sum(&self) -> usize { + self.map.iter().map(|line| line.iter().sum::()).sum() + } +} + +pub fn run(input: &str, part: usize) -> Result { + let mut map = Map::try_from(input)?; + match part { + 1 | 2 => map.maximize(false), + 3 => map.maximize(true), + _ => panic!("Illegal part number"), + }; + Ok(map.total_sum()) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs::read_to_string; + + fn read_file(name: &str) -> String { + read_to_string(name).expect(&format!("Unable to read file: {name}")[..]).trim().to_string() + } + + #[test] + fn test_sample() { + let expected = [35, 35, 29]; + for part in 1..=3 { + let sample_input = read_file(&format!("tests/sample{part}")); + assert_eq!(run(&sample_input, part), Ok(expected[part-1])); + } + } + + #[test] + fn test_challenge() { + let expected = [127, 2674, 10571]; + for part in 1..=3 { + let challenge_input = read_file(&format!("tests/challenge{part}")); + assert_eq!(run(&challenge_input, part), Ok(expected[part-1])); + } + } +} diff --git a/2024/day03_mining_maestro/tests/challenge1 b/2024/day03_mining_maestro/tests/challenge1 new file mode 100644 index 0000000..ee4c317 --- /dev/null +++ b/2024/day03_mining_maestro/tests/challenge1 @@ -0,0 +1,14 @@ +.............................. +.............................. +.............................. +..................#........... +.........#######..##.......... +........##############........ +.......###############........ +........##############........ +...........###########........ +..........###.###..##......... +...............#.............. +...............#.............. +.............................. +.............................. diff --git a/2024/day03_mining_maestro/tests/challenge2 b/2024/day03_mining_maestro/tests/challenge2 new file mode 100644 index 0000000..a6c2f7d --- /dev/null +++ b/2024/day03_mining_maestro/tests/challenge2 @@ -0,0 +1,35 @@ +...................................................................... +...................................#.................................. +..................................##.................................. +..............................#..####..#.............................. +............................#########.####............................ +.............................#################........................ +.......................#.....##################....................... +.......................#.....####################..................... +.....................#.#..#######################..................... +.....................####.######################..###................. +.....................############################.###................. +......................##############################.................. +......................#############################................... +......................##############################.................. +.......................##############################................. +......................################################................ +.......................#################################.............. +...................################..################................. +....................#################################................. +.......................##############################................. +......................###############################................. +.......................#############################.................. +.......................##############################................. +......................############################.###................ +........................##########################.................... +........................######################..#..................... +........................###################........................... +..........................############..##............................ +.........................###########.....#............................ +.........................######..###.................................. +.........................####....##................................... +..........................###.....#................................... +............................#......................................... +...................................................................... +...................................................................... diff --git a/2024/day03_mining_maestro/tests/challenge3 b/2024/day03_mining_maestro/tests/challenge3 new file mode 100644 index 0000000..153d780 --- /dev/null +++ b/2024/day03_mining_maestro/tests/challenge3 @@ -0,0 +1,52 @@ +######################....................................................................................................#################### +#.####################...................................................................................................###################.# +#######################..............................................##..................................................##################### +########################.......................................#.....#.................................................####################### +######################.....................................#.#.###...#.................................................####################### +######################...................................###.##########..#.##............................................##################### +#######################.................................#####################............................................##################### +#####################..................................#######################...........................................#.################### +##################.....................................#########################.........................................#...################# +###################..................................###########################..#............................................############### +################....................................###########################.####..........................................################ +################..................................##################################............................................############## +###############.................................######################################............................................############ +##########.###...................................######################################........................................##.############ +##########........................................######################################......................................################ +##########.........................................#####################################.........................................############# +##########..........................................####################################........................................############## +###########.........................................####################################.#.#...#.................................###..######## +#########..........................................###############################################....................................######## +....###.#........................................###############################################......................................######.# +....#.#..........................................##############################################.......................................####.... +......#............................................#############################################.............................................. +.................................................##############################################............................................... +................................................#####################......####################............................................... +................................................#..#################.######.####################.............................................. +................................................###################.###..###.##################............................................... +...................................................################.###..###.###################.............................................# +...................................................#################.######.####################.............................................# +...................................................##################......#######################....................................#....### +...................................................###############################################....................................####.### +..............#.....................................#############################################.....................................######.# +#............##......................................############################################...................................#.######## +####..#.#...###.#.....................................###########################################.###..............................##.######## +#################.....................................###############################################..............................########### +###############.........................................###########################################................................########### +#################.......................................###########################################..............................############# +#################....................................##############################################...........................################ +####################...................................############################################.........................################## +####################..................................#########################################.###..........................################# +#####################..............................#########################################.....##.........................################## +#######################............................#..######################################...............................################### +#######################................................#####################################...............................################### +#####################.#................................#####################################...............................################### +#######################.................................############################.#######...............................################### +#######################...................................##########################.....#.................................################### +#######################....................................########################......#................................#################### +#######################....................................###...##...#############.......................................#################### +######################................................................#########.###.......................................#################### +####################..................................................##########.##.......................................#################### +####################........................................................####.##....................................####################### +#.#################........................................................................................................#################.# +###################.......................................................................................................#################### diff --git a/2024/day03_mining_maestro/tests/sample1 b/2024/day03_mining_maestro/tests/sample1 new file mode 100644 index 0000000..77f4d09 --- /dev/null +++ b/2024/day03_mining_maestro/tests/sample1 @@ -0,0 +1,7 @@ +.......... +..###.##.. +...####... +..######.. +..######.. +...####... +.......... diff --git a/2024/day03_mining_maestro/tests/sample2 b/2024/day03_mining_maestro/tests/sample2 new file mode 100644 index 0000000..77f4d09 --- /dev/null +++ b/2024/day03_mining_maestro/tests/sample2 @@ -0,0 +1,7 @@ +.......... +..###.##.. +...####... +..######.. +..######.. +...####... +.......... diff --git a/2024/day03_mining_maestro/tests/sample3 b/2024/day03_mining_maestro/tests/sample3 new file mode 100644 index 0000000..77f4d09 --- /dev/null +++ b/2024/day03_mining_maestro/tests/sample3 @@ -0,0 +1,7 @@ +.......... +..###.##.. +...####... +..######.. +..######.. +...####... +..........