--- /dev/null
+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());
+ }
+}