--- /dev/null
+use std::io::Read;
+use std::error::Error;
+use std::fs::File;
+
+use std::collections::VecDeque;
+
+const END_STEP: u32 = 64;
+
+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, END_STEP)?;
+ println!("{res}");
+
+ let res = run_part2(&input)?;
+ println!("{res}");
+
+ Ok(())
+}
+
+#[derive(Debug)]
+struct Puzzle {
+ map: Vec<Vec<char>>,
+ seen_at_step: Vec<Vec<u32>>,
+ start: (usize, usize),
+}
+
+impl Puzzle {
+ pub fn new(input: &str) -> Self {
+ let mut map: Vec<Vec<char>> = Vec::new();
+ let mut start: (usize, usize) = (0, 0);
+
+ input.lines()
+ .filter(|l| !l.is_empty())
+ .enumerate()
+ .for_each(|(i, l)| {
+ let mut c: Vec<char> = Vec::new();
+
+ c.push(' ');
+ c.append(&mut l.chars().collect::<Vec<char>>());
+ c.push(' ');
+
+ match c.iter().position(|&a| a == 'S') {
+ Some(p) => start = (i + 1, p),
+ None => {},
+ }
+
+
+ if i == 0 {
+ map.push(vec![' '; c.len()]);
+ }
+ map.push(c);
+
+ });
+
+ map.push(vec![' '; map[0].len()]);
+
+ let seen_at_step: Vec<Vec<u32>> = vec![
+ vec![0 ; map[0].len()]
+ ;
+ map.len()
+ ];
+
+ Self {
+ map,
+ seen_at_step,
+ start,
+ }
+ }
+
+ // une fois visitées les cases clignotes
+ // '.' -> 'O' -> '.' -> 'O'
+ pub fn travel(&mut self, end_step: u32) -> u32 {
+ let mut queue: VecDeque<(usize, usize)> = VecDeque::new();
+ queue.push_back(self.start);
+
+ let mut step: u32 = 1;
+
+ while step <= end_step {
+ let mut queue_next: VecDeque<(usize, usize)> = VecDeque::new();
+ while let Some(q) = queue.pop_front() {
+ let neighbours = [
+ (q.0, q.1 - 1),
+ (q.0, q.1 + 1),
+ (q.0 - 1, q.1),
+ (q.0 + 1, q.1),
+ ];
+ for n in neighbours {
+ if self.can_travel_to(n) {
+ self.seen_at_step[n.0][n.1] = step;
+ queue_next.push_back(n);
+ }
+ }
+ }
+
+ step += 1;
+ queue = queue_next.clone();
+ }
+
+ self.seen_at_step.iter()
+ .map(|r| {
+ r.iter().filter(|&&s| {
+ s > 0 && s % 2 == end_step % 2
+ })
+ .count()
+ })
+ .sum::<usize>() as u32
+ }
+
+ fn can_travel_to(&self, n: (usize, usize)) -> bool {
+ self.seen_at_step[n.0][n.1] == 0 && ['.', 'S'].contains(&self.map[n.0][n.1])
+ }
+}
+
+fn run_part1(input: &str, end_step: u32) -> Result<u32, Box<dyn Error>> {
+ println!("Running day21 - part 1");
+
+ let mut puzzle = Puzzle::new(input);
+ //println!("{:?}", puzzle);
+ let res = puzzle.travel(end_step);
+ Ok(res)
+}
+
+fn run_part2(input: &str) -> Result<u32, Box<dyn Error>> {
+ println!("Running day21 - part 2");
+ let res = 0;
+ Ok(res)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ static TEXT_INPUT: &str = "\
+...........
+.....###.#.
+.###.##..#.
+..#.#...#..
+....#.#....
+.##..S####.
+.##..#...#.
+.......##..
+.##.#.####.
+.##..##.##.
+...........";
+
+ #[test]
+ fn day21_part1() {
+ // N = 6
+ let res = run_part1(TEXT_INPUT, 6);
+ assert_eq!(16, res.unwrap());
+ }
+
+ #[test]
+ fn day21_part2() {
+ let res = run_part2(TEXT_INPUT);
+ assert_eq!(0, res.unwrap());
+ }
+}