From: alex Date: Mon, 18 Dec 2023 22:24:25 +0000 (+0100) Subject: Day18 - part 1 X-Git-Url: https://aoc.elinar.fr/?a=commitdiff_plain;h=ea9be44a6d4ca4a42f5125e289bb618737ccc514;p=aoc_2023 Day18 - part 1 --- diff --git a/src/day18.rs b/src/day18.rs new file mode 100644 index 0000000..a8e3a6d --- /dev/null +++ b/src/day18.rs @@ -0,0 +1,244 @@ +use std::io::Read; +use std::error::Error; +use std::fs::File; + +use std::collections::BTreeSet; + +pub fn run(input_file: &str) -> Result<(), Box> { + let mut f = File::open(input_file)?; + let mut input = String::new(); + f.read_to_string(&mut input)?; + + let res = run_part1(&input)?; + println!("{res}"); + + let res = run_part2(&input)?; + println!("{res}"); + + Ok(()) +} + +#[derive(Debug, Clone, Copy)] +struct Boundary { + top: i32, + bottom: i32, + right: i32, + left: i32, +} + +struct Puzzle { + frontier: Vec<(i32, i32)>, + height: usize, + width: usize, +} + +impl Puzzle { + pub fn new(input: &str) -> Self { + let mut frontier: Vec<(i32, i32)> = Vec::new(); + let mut boundaries = Boundary { + top: 0, + bottom: 0, + right: 0, + left: 0, + }; + + let mut pos: (i32, i32) = (0, 0); + + input.lines() + .filter(|l| !l.is_empty()) + .for_each(|l| { + let values = l.split(' ').collect::>(); + let direction: char = values[0].chars().nth(0).unwrap(); + let distance: i32 = values[1].parse().unwrap(); + + match direction { + 'R' => { + (1..=distance).for_each(|i| { + frontier.push((pos.0, pos.1 + i)); + }); + pos.1 += distance; + if boundaries.right < pos.1 { + boundaries.right = pos.1; + } + }, + 'L' => { + (1..=distance).for_each(|i| { + frontier.push((pos.0, pos.1 - i)); + }); + pos.1 -= distance; + if boundaries.left > pos.1 { + boundaries.left = pos.1; + } + }, + 'U' => { + (1..=distance).for_each(|i| { + frontier.push((pos.0 - i, pos.1)); + }); + pos.0 -= distance; + if boundaries.top > pos.0 { + boundaries.top = pos.0; + } + }, + 'D' => { + (1..=distance).for_each(|i| { + frontier.push((pos.0 + i, pos.1)); + }); + pos.0 += distance; + if boundaries.bottom < pos.0 { + boundaries.bottom = pos.0; + } + }, + _ => unreachable!(), + } + }); + + //println!("{:?}", boundaries); + // changement de coordonnées + // et trie par ordre croissant + for (x, y) in frontier.iter_mut() { + *x += boundaries.top.abs() + 1; + *y += boundaries.left.abs() + 1; + } + + let height = (boundaries.bottom - boundaries.top + 3) as usize; + let width = (boundaries.right - boundaries.left + 3) as usize; + + Self { + frontier, + height, + width, + } + } + + pub fn is_frontier(&self, pos: (i32, i32)) -> bool { + self.frontier.contains(&pos) + } + + pub fn is_border(&self, x: (usize, usize)) -> bool { + x.0 == 0 || x.1 == 0 || x.0 == self.height - 1 || x.1 == self.width - 1 + } + + pub fn travel(&self, (x, y): (usize, usize)) -> u32 { + let mut count = 0; + let mut seen: BTreeSet<(usize, usize)> = BTreeSet::new(); + let mut queue: Vec<(usize, usize)> = Vec::new(); + queue.push((x, y)); + + while let Some((i, j)) = queue.pop() { + if seen.contains(&(i, j)) || self.is_frontier((i as i32, j as i32)) { + continue; + } + seen.insert((i, j)); + if !self.is_border((i, j)) { + //println!("found: ({},{})", i, j); + count += 1; + } + if i > 0 && !seen.contains(&(i - 1, j)) { + queue.push((i - 1, j)); + } + if i < self.height && !seen.contains(&(i + 1, j)) { + queue.push((i + 1, j)); + } + if j > 0 && !seen.contains(&(i, j - 1)) { + queue.push((i, j - 1)); + } + if j < self.width && !seen.contains(&(i, j + 1)) { + queue.push((i, j + 1)); + } + } + count + } +} + +fn run_part1(input: &str) -> Result> { + println!("Running day18 - part 1"); + let puzzle = Puzzle::new(input); + + let count_outside = puzzle.travel((0,0)); + let res = (puzzle.height as u32 - 1) * (puzzle.width as u32 - 1) - count_outside; + Ok(res) +} + +fn run_part2(input: &str) -> Result> { + println!("Running day18 - part 2"); + let res = 0; + Ok(res) +} + +#[cfg(test)] +mod tests { + use super::*; + + static TEXT_INPUT: &str = "\ +R 6 (#70c710) +D 5 (#0dc571) +L 2 (#5713f0) +D 2 (#d2c081) +R 2 (#59c680) +D 2 (#411b91) +L 5 (#8ceee2) +U 2 (#caa173) +L 1 (#1b58a2) +U 2 (#caa171) +R 2 (#7807d2) +U 3 (#a77fa3) +L 2 (#015232) +U 2 (#7a21e3)"; + +// ####### +// #.....# +// ###...# +// ..#...# +// ..#...# +// ###.### +// #...#.. +// ##..### +// .#....# +// .###### +// +// ####### +// ####### +// ####### +// ..##### +// ..##### +// ####### +// #####.. +// ####### +// .###### +// .###### + + + + #[test] + fn day18_part1() { + let res = run_part1(TEXT_INPUT); + assert_eq!(62, res.unwrap()); + } + + #[test] + fn day18_part1_rotation() { + let input = "\ +L 2 (#5713f0) +D 2 (#d2c081) +R 2 (#59c680) +D 2 (#411b91) +L 5 (#8ceee2) +U 2 (#caa173) +L 1 (#1b58a2) +U 2 (#caa171) +R 2 (#7807d2) +U 3 (#a77fa3) +L 2 (#015232) +U 2 (#7a21e3) +R 6 (#70c710) +D 5 (#0dc571)"; + let res = run_part1(&input); + assert_eq!(62, res.unwrap()); + } + + #[test] + fn day18_part2() { + let res = run_part2(TEXT_INPUT); + assert_eq!(0, res.unwrap()); + } +} diff --git a/src/main.rs b/src/main.rs index 5e567b5..819dbc6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,7 @@ pub mod day11; pub mod day14; pub mod day15; pub mod day16; +pub mod day18; fn main() { let args: Vec = env::args().collect(); @@ -49,6 +50,7 @@ fn run(day: &str, input_file: &str) -> Result<(), Box> { "day14" => day14::run(input_file)?, "day15" => day15::run(input_file)?, "day16" => day16::run(input_file)?, + "day18" => day18::run(input_file)?, _ => return Err(format!("unknown day \"{day}\"").into()), } Ok(())