From: alex <> Date: Thu, 12 Dec 2024 11:52:30 +0000 (+0100) Subject: Day12 - part 1 X-Git-Url: https://aoc.elinar.fr/?a=commitdiff_plain;h=b6730d888567d8ad2802b3b4a127af42f7f268b8;p=aoc_2024 Day12 - part 1 --- diff --git a/src/day12.rs b/src/day12.rs new file mode 100644 index 0000000..e819537 --- /dev/null +++ b/src/day12.rs @@ -0,0 +1,137 @@ +use std::error::Error; +use std::path::Path; + +struct Puzzle { + map: Vec>, + visited: Vec>, +} + +impl Puzzle { + pub fn new(input: &str) -> Self { + let mut map: Vec> = Vec::new(); + input.lines() + .for_each(|l| { + let mut row: Vec = l.as_bytes().iter().map(|v| *v).collect(); + row.insert(0, b' '); + row.push(b' '); + map.push(row); + }); + map.insert(0, vec![b' '; map[0].len()]); + map.push(vec![b' '; map[0].len()]); + + let visited: Vec> = vec![vec![false; map[0].len()]; map.len()]; + + Self { map, visited } + } + + fn count_perimeter(&self, pos: (isize, isize), plant: u8) -> u32 { + let (row, col) = pos; + [(-1, 0), (0, 1), (1, 0), (0, -1)].iter() + .filter(|(dr, dc)| self.map[(row + dr) as usize][(col + dc) as usize] != plant) + .count() as u32 + } + + fn area_perimeter(&mut self, pos: (usize, usize), plant: u8) -> (u32, u32) { + let (mut area, mut perimeter) = (0, 0); + + let mut region: Vec<(isize, isize)> = Vec::new(); + region.push((pos.0 as isize, pos.1 as isize)); + + while let Some((row, col)) = region.pop() { + area += 1; + perimeter += self.count_perimeter((row, col), plant); + [(-1, 0), (0, 1), (1, 0), (0, -1)].iter() + .for_each(|(dr, dc)| { + let (r, c) = ((row + dr) as usize, (col + dc) as usize); + if !self.visited[r][c] && self.map[r][c] == plant { + self.visited[r][c] = true; + region.push((r as isize, c as isize)); + } + }); + } + + (area, perimeter) + } +} + +fn run_part1(input: &str) -> Result> { + println!("Running {} - part 1", get_day()); + + let mut puzzle = Puzzle::new(input); + + let mut res = 0; + for r in 1..(puzzle.map.len()-1) { + for c in 1..(puzzle.map[0].len()-1) { + if !puzzle.visited[r][c] { + puzzle.visited[r][c] = true; + let plant = puzzle.map[r][c]; + let pos = (r, c); + let (area, perimeter) = puzzle.area_perimeter(pos, plant); + res += area * perimeter; + } + } + } + + Ok(res) +} + +fn run_part2(input: &str) -> Result> { + println!("Running {} - part 2", get_day()); + + Ok(0) +} + +pub fn run(input: &str) -> Result<(), Box> { + let res = run_part1(input)?; + println!("{res}"); + + let res = run_part2(input)?; + println!("{res}"); + + Ok(()) +} + +fn get_day() -> String { + let filename = file!(); + Path::new(filename).file_stem().unwrap().to_str().unwrap().to_string() +} + +#[cfg(test)] +mod tests { + use super::*; + + static TEXT_INPUT_0: &str = "\ +AAAA +BBCD +BBCC +EEEC"; + static TEXT_INPUT_1: &str = "\ +OOOOO +OXOXO +OOOOO +OXOXO +OOOOO"; + static TEXT_INPUT_2: &str = "\ +RRRRIICCFF +RRRRIICCCF +VVRRRCCFFF +VVRCCCJFFF +VVVVCJJCFE +VVIVCCJJEE +VVIIICJJEE +MIIIIIJJEE +MIIISIJEEE +MMMISSJEEE"; + + #[test] + fn test_part1() { + assert_eq!(140, run_part1(TEXT_INPUT_0).unwrap()); + assert_eq!(772, run_part1(TEXT_INPUT_1).unwrap()); + assert_eq!(1930, run_part1(TEXT_INPUT_2).unwrap()); + } + + #[test] + fn test_part2() { + assert_eq!(0, run_part2(TEXT_INPUT_2).unwrap()); + } +} diff --git a/src/main.rs b/src/main.rs index dd9eed2..0e0f455 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ pub mod day08; pub mod day09; pub mod day10; pub mod day11; +pub mod day12; fn main() { let args: Vec = env::args().collect(); @@ -48,6 +49,7 @@ fn run(day: &str, input_file: &str) -> Result<(), Box> { "day09" => day09::run(&input)?, "day10" => day10::run(&input)?, "day11" => day11::run(&input)?, + "day12" => day12::run(&input)?, _ => return Err(format!("unknown or unimplemented day \"{day}\"").into()), } Ok(())