--- /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)]
+struct Puzzle {
+ start: (usize, usize),
+ map: Vec<Vec<char>>,
+}
+
+impl Puzzle {
+ pub fn new(input: &str) -> Self {
+ // astuce : on ajoute une ligne de symbole neutre en haut et en bas
+ // et à gauche et à droite de la carte
+ // cela permet de s'affranchir des tests de limites de tableau
+ //
+ // .......
+ // -L|F7 .-L|F7.
+ // 7S-7| .7S-7|.
+ // L|7|| -> .L|7||.
+ // -L-J| .-L-J|.
+ // L|-JF .L|-JF.
+ // .......
+
+ let mut map: Vec<Vec<char>> = Vec::new();
+
+ // coordonnées du S de départ
+ let mut start = (0, 0);
+
+ input.lines()
+ .filter(|l| !l.is_empty())
+ .enumerate()
+ .for_each(|(i,l)| {
+ let mut row: Vec<char> = Vec::new();
+
+ row.push('.');
+ l.chars().for_each(|c| { row.push(c); });
+ row.push('.');
+
+ // ajout d'une première ligne de '.'
+ if i == 0 {
+ map.push( (0..row.len()).map(|_| '.').collect::<Vec<char>>() );
+ }
+ map.push(row);
+
+ // recherche du S de départ
+ if start == (0, 0) {
+ start = match l.chars().position(|c| c == 'S') {
+ Some(p) => (i + 1, p + 1),
+ None => (0, 0),
+ };
+ }
+ });
+
+ // ajout d'une dernière ligne
+ map.push( (0..map[0].len()).map(|_| '.').collect::<Vec<char>>() );
+
+ Self {
+ start,
+ map
+ }
+ }
+
+ pub fn get_char(self: &Self, pos: (usize, usize)) -> char {
+ self.map[pos.0][pos.1]
+ }
+}
+
+// a -> b
+// (row, col)
+fn is_connected(c: char, a: (usize, usize), b: (usize, usize)) -> bool {
+ match c {
+ '|' => a.1 == b.1 && (a.0 as i32 - b.0 as i32).abs() == 1,
+ '-' => a.0 == b.0 && (a.1 as i32 - b.1 as i32).abs() == 1,
+ 'L' => (a.1 == b.1 && (a.0 + 1) == b.0) || (a.0 == b.0 && a.1 == (b.1 + 1)),
+ 'J' => (a.1 == b.1 && (a.0 + 1) == b.0) || (a.0 == b.0 && (a.1 + 1) == b.1),
+ '7' => (a.1 == b.1 && a.0 == (b.0 + 1)) || (a.0 == b.0 && (a.1 + 1) == b.1),
+ 'F' => (a.1 == b.1 && a.0 == (b.0 + 1)) || (a.0 == b.0 && a.1 == (b.1 + 1)),
+ '.' => false,
+ _ => unreachable!(),
+ }
+}
+
+// besoin de connaitre le sens
+// c le char du tuyau de connexion
+// current: la position actuelle
+// pipe: le tuyau de connexion
+// retourne: (row, col) de la sortie après le tuyau de connexion
+fn get_next_next(c: char, current: (usize, usize), pipe: (usize, usize) ) -> (usize, usize) {
+ let (row, col) = current;
+ //println!("get_next: c: {}, current: {:?}, pipe: {:?}", c, current, pipe);
+ // vérifier que le "pipe" est connecté au "current"
+ match c {
+ // | x
+ // x |
+ '|' => {
+ if pipe.0 < row {
+ (row - 2, col)
+ } else {
+ (row + 2, col)
+ }
+ },
+
+ // x-
+ // -x
+ '-' => {
+ if pipe.1 < col {
+ (row, col - 2)
+ } else {
+ (row, col + 2)
+ }
+ },
+
+ // x Lx
+ // L
+ 'L' => {
+ if pipe.1 < col {
+ (row - 1, col - 1)
+ } else {
+ (row + 1, col + 1)
+ }
+ },
+
+ // x xJ
+ // J
+ 'J' => {
+ if pipe.1 > col {
+ (row - 1, col + 1)
+ } else {
+ (row + 1, col - 1)
+ }
+ },
+
+ // 7 x7
+ // x
+ '7' => {
+ if pipe.1 > col {
+ (row + 1, col + 1)
+ } else {
+ (row - 1, col - 1)
+ }
+ },
+
+ // F Fx
+ // x
+ 'F' => {
+ if pipe.1 < col {
+ (row + 1, col - 1)
+ } else {
+ (row - 1, col + 1)
+ }
+ },
+
+ '.' | 'S' => (0, 0),
+ _ => unreachable!(),
+ }
+}
+
+fn run_part1(input: &str) -> Result<u32, Box<dyn Error>> {
+ println!("Running day10 - part 1");
+
+ let puzzle = Puzzle::new(input);
+
+ let mut current = puzzle.start;
+ let (row, col) = current;
+ // on recherche dans les 4 directions
+ let start = [
+ (row - 1, col),
+ (row + 1, col),
+ (row, col - 1),
+ (row, col + 1),
+ ];
+ let mut count: u32 = 0;
+ for mut next in start {
+ count = 1;
+ while puzzle.get_char(next) != 'S' && is_connected(puzzle.get_char(next), current, next) {
+ count += 1;
+ let next_next = get_next_next(puzzle.get_char(next), current, next);
+ current = next;
+ next = next_next;
+ }
+ if puzzle.get_char(next) == 'S' {
+ break;
+ }
+ }
+
+ let res = count.div_ceil(2);
+ Ok(res)
+}
+
+fn run_part2(input: &str) -> Result<u32, Box<dyn Error>> {
+ println!("Running day10 - part 2");
+ let res = 0;
+ Ok(res)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn day10_part1_example1() {
+ let input = "\
+-L|F7
+7S-7|
+L|7||
+-L-J|
+L|-JF";
+ let res = run_part1(&input);
+ assert_eq!(4, res.unwrap());
+ }
+
+ #[test]
+ fn day10_part1_example2() {
+ let input = "\
+7-F7-
+.FJ|7
+SJLL7
+|F--J
+LJ.LJ";
+ let res = run_part1(&input);
+ assert_eq!(8, res.unwrap());
+ }
+
+ #[test]
+ fn test_is_connected() {
+ // (row, col)
+ assert_eq!( is_connected('|', (0,0), (1,0)), true);
+ assert_eq!( is_connected('|', (1,0), (0,0)), true);
+ assert_eq!( is_connected('|', (0,0), (0,1)), false);
+ assert_eq!( is_connected('|', (0,0), (2,0)), false);
+
+ assert_eq!( is_connected('-', (0,0), (0,1)), true);
+ assert_eq!( is_connected('-', (0,1), (0,0)), true);
+ assert_eq!( is_connected('-', (0,0), (1,0)), false);
+
+ assert_eq!( is_connected('L', (0,0), (1,0)), true);
+ assert_eq!( is_connected('L', (0,1), (0,0)), true);
+ assert_eq!( is_connected('L', (0,0), (0,1)), false);
+
+ assert_eq!( is_connected('J', (0,0), (1,0)), true);
+ assert_eq!( is_connected('J', (0,0), (0,1)), true);
+ assert_eq!( is_connected('J', (0,1), (0,0)), false);
+
+ assert_eq!( is_connected('7', (0,0), (0,1)), true);
+ assert_eq!( is_connected('7', (1,0), (0,0)), true);
+ assert_eq!( is_connected('7', (0,0), (1,0)), false);
+
+ assert_eq!( is_connected('F', (0,1), (0,0)), true);
+ assert_eq!( is_connected('F', (1,0), (0,0)), true);
+ assert_eq!( is_connected('F', (0,0), (0,1)), false);
+
+ assert_eq!( is_connected('.', (0,0), (0,1)), false);
+ }
+
+ #[test]
+ fn day10_part2() {
+ let input = "";
+ let res = run_part2(&input);
+ assert_eq!(0, res.unwrap());
+ }
+}