]> aoc.elinar.fr Git - aoc_2023/commitdiff
Day18 - part 1
authoralex <null>
Mon, 18 Dec 2023 22:24:25 +0000 (23:24 +0100)
committeralex <null>
Mon, 18 Dec 2023 22:24:25 +0000 (23:24 +0100)
src/day18.rs [new file with mode: 0644]
src/main.rs

diff --git a/src/day18.rs b/src/day18.rs
new file mode 100644 (file)
index 0000000..a8e3a6d
--- /dev/null
@@ -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<dyn Error>> {
+    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::<Vec<&str>>();
+                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<u32, Box<dyn Error>> {
+    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<u32, Box<dyn Error>> {
+    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());
+    }
+}
index 5e567b50954f5bc7bb349a80cb42e352e10fc544..819dbc6bac97c937c84436b3b0d7369b2673b439 100644 (file)
@@ -17,6 +17,7 @@ pub mod day11;
 pub mod day14;
 pub mod day15;
 pub mod day16;
+pub mod day18;
 
 fn main() {
     let args: Vec<String> = env::args().collect();
@@ -49,6 +50,7 @@ fn run(day: &str, input_file: &str) -> Result<(), Box<dyn Error>> {
         "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(())