--- /dev/null
+use std::io::Read;
+use std::error::Error;
+use std::fs::File;
+
+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, Copy, Clone)]
+enum Direction {
+ ToTheLeft,
+ ToTheRight,
+ ToTheTop,
+ ToTheBottom,
+}
+
+#[derive(Clone, Debug)]
+struct Seen {
+ top: bool,
+ right: bool,
+ bottom: bool,
+ left: bool,
+}
+
+struct Puzzle {
+ map: Vec<Vec<char>>,
+ height: usize,
+ width: usize,
+ seen: Vec<Vec<Seen>>,
+}
+
+impl Puzzle {
+ pub fn new(input: &str) -> Self {
+ let mut map: Vec<Vec<char>> = Vec::new();
+ let mut width = 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(' ');
+ if i == 0 {
+ width = c.len();
+ map.push(vec![' '; width]);
+ }
+ map.push(c);
+ });
+ map.push(vec![' '; width]);
+
+ let height = map.len();
+
+ let seen: Vec<Vec<Seen>> = vec![
+ vec![ Seen { top: false, right: false, bottom: false, left: false }; width]
+ ;
+ height
+ ];
+
+ Self {
+ map,
+ height,
+ width,
+ seen,
+ }
+ }
+
+ pub fn print(&self) {
+ self.map.iter()
+ .for_each(|r| {
+ println!("{:?}", r.iter().collect::<String>());
+ });
+ }
+
+ pub fn get_next_from_left(&self, pos: (usize, usize)) -> Vec<(Direction, (usize, usize))> {
+ //println!("gn_from_left: {:?} {}", pos, self.map[pos.0][pos.1 + 1]);
+ match self.map[pos.0][pos.1 + 1] {
+ '.' | '-' => vec![(Direction::ToTheRight, (pos.0, pos.1 + 1))],
+ '\\' => vec![(Direction::ToTheBottom, (pos.0, pos.1 + 1))],
+ '/' => vec![(Direction::ToTheTop, (pos.0, pos.1 + 1))],
+ '|' => vec![(Direction::ToTheBottom, (pos.0, pos.1 + 1)), (Direction::ToTheTop, (pos.0, pos.1 + 1))],
+ ' ' => vec![(Direction::ToTheRight, pos)],
+ _ => unreachable!(),
+ }
+ }
+
+ pub fn get_next_from_right(&self, pos: (usize, usize)) -> Vec<(Direction, (usize, usize))> {
+ //println!("gn_from_left: {:?} {}", pos, self.map[pos.0][pos.1 - 1]);
+ match self.map[pos.0][pos.1 - 1] {
+ '.' | '-' => vec![(Direction::ToTheLeft, (pos.0, pos.1 - 1))],
+ '\\' => vec![(Direction::ToTheTop, (pos.0, pos.1 - 1))],
+ '/' => vec![(Direction::ToTheBottom, (pos.0, pos.1 - 1))],
+ '|' => vec![(Direction::ToTheTop, (pos.0, pos.1 - 1)), (Direction::ToTheBottom, (pos.0, pos.1 - 1))],
+ ' ' => vec![(Direction::ToTheLeft, pos)],
+ _ => unreachable!(),
+ }
+ }
+
+ pub fn get_next_from_top(&self, pos: (usize, usize)) -> Vec<(Direction, (usize, usize))> {
+ //println!("gn_from_left: {:?} {}", pos, self.map[pos.0 + 1][pos.1]);
+ match self.map[pos.0 + 1][pos.1] {
+ '.' | '|' => vec![(Direction::ToTheBottom, (pos.0 + 1, pos.1))],
+ '\\' => vec![(Direction::ToTheRight, (pos.0 + 1, pos.1))],
+ '/' => vec![(Direction::ToTheLeft, (pos.0 + 1, pos.1))],
+ '-' => vec![(Direction::ToTheLeft, (pos.0 + 1, pos.1)), (Direction::ToTheRight, (pos.0 + 1, pos.1))],
+ ' ' => vec![(Direction::ToTheBottom, pos)],
+ _ => unreachable!(),
+ }
+ }
+
+ pub fn get_next_from_bottom(&self, pos: (usize, usize)) -> Vec<(Direction, (usize, usize))> {
+ //println!("gn_from_left: {:?} {}", pos, self.map[pos.0 - 1][pos.1]);
+ match self.map[pos.0 - 1][pos.1] {
+ '.' | '|' => vec![(Direction::ToTheTop, (pos.0 - 1, pos.1))],
+ '\\' => vec![(Direction::ToTheLeft, (pos.0 - 1, pos.1))],
+ '/' => vec![(Direction::ToTheRight, (pos.0 - 1, pos.1))],
+ '-' => vec![(Direction::ToTheLeft, (pos.0 - 1, pos.1)), (Direction::ToTheRight, (pos.0 - 1, pos.1))],
+ ' ' => vec![(Direction::ToTheTop, pos)],
+ _ => unreachable!(),
+ }
+ }
+
+ pub fn update_seen(&mut self, pos: (usize, usize), direction: Direction) {
+ match direction {
+ Direction::ToTheTop => self.seen[pos.0][pos.1].top = true,
+ Direction::ToTheRight => self.seen[pos.0][pos.1].right = true,
+ Direction::ToTheBottom => self.seen[pos.0][pos.1].bottom = true,
+ Direction::ToTheLeft => self.seen[pos.0][pos.1].left = true,
+ }
+ }
+
+ pub fn get_seen(& self, pos: (usize, usize), direction: Direction) -> bool {
+ match direction {
+ Direction::ToTheTop => self.seen[pos.0][pos.1].top,
+ Direction::ToTheRight => self.seen[pos.0][pos.1].right,
+ Direction::ToTheBottom => self.seen[pos.0][pos.1].bottom,
+ Direction::ToTheLeft => self.seen[pos.0][pos.1].left,
+ }
+ }
+
+ pub fn move_beam(&mut self, start: (usize, usize), start_direction: Direction) {
+ let mut pos: (usize, usize) = start;
+ let mut direction: Direction = start_direction;
+ //println!("start: {:?} {:?}", direction, pos);
+ loop {
+ if self.map[pos.0][pos.1] == ' ' {
+ break;
+ }
+ self.update_seen(pos, direction);
+ let new_pos: Vec<(Direction, (usize, usize))> = match direction {
+ Direction::ToTheRight => self.get_next_from_left(pos),
+ Direction::ToTheLeft => self.get_next_from_right(pos),
+ Direction::ToTheBottom => self.get_next_from_top(pos),
+ Direction::ToTheTop => self.get_next_from_bottom(pos),
+ };
+ (direction, pos) = new_pos[0];
+ //println!("next: {:?} {:?}", direction, pos);
+ if self.get_seen(pos, direction) {
+ break;
+ }
+ (1..new_pos.len()).for_each(|i| {
+ let (d, p) = new_pos[i];
+ if !self.get_seen(p, d) {
+ self.move_beam(p, d);
+ }
+ });
+ }
+ }
+
+ pub fn energized_tiles(&self) -> u64 {
+ let res: u64 = self.seen.iter()
+ .flatten()
+ .map(|b| {
+ if b.top || b.right || b.bottom || b.left {
+ 1
+ } else {
+ 0
+ }
+ })
+ .sum();
+
+ res
+ }
+}
+
+fn run_part1(input: &str) -> Result<u64, Box<dyn Error>> {
+ println!("Running day16 - part 1");
+
+ let mut puzzle = Puzzle::new(input);
+ //puzzle.print();
+
+ // le rayon vient de la gauche (va vers la droite)
+ let (direction, pos) = puzzle.get_next_from_left((1,0))[0];
+ puzzle.move_beam(pos, direction);
+
+ let res = puzzle.energized_tiles();
+ Ok(res)
+}
+
+fn run_part2(input: &str) -> Result<u64, Box<dyn Error>> {
+ println!("Running day16 - part 2");
+ let res = 0;
+ Ok(res)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ static TEXT_INPUT: &str = r".|...\....
+|.-.\.....
+.....|-...
+........|.
+..........
+.........\
+..../.\\..
+.-.-/..|..
+.|....-|.\
+..//.|....";
+
+ #[test]
+ fn day16_part1() {
+ let res = run_part1(TEXT_INPUT);
+ assert_eq!(46, res.unwrap());
+ }
+
+ #[test]
+ fn day16_part2() {
+ let res = run_part2(TEXT_INPUT);
+ assert_eq!(0, res.unwrap());
+ }
+}