]> aoc.elinar.fr Git - aoc_2023/commitdiff
Day10 - part 1
authoralex <null>
Sun, 10 Dec 2023 10:08:35 +0000 (11:08 +0100)
committeralex <null>
Sun, 10 Dec 2023 10:13:50 +0000 (11:13 +0100)
src/day10.rs [new file with mode: 0644]
src/main.rs

diff --git a/src/day10.rs b/src/day10.rs
new file mode 100644 (file)
index 0000000..9b30225
--- /dev/null
@@ -0,0 +1,276 @@
+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());
+    }
+}
index 5dc80cc7fb9bd4871c7f009fcc0f671f1a1c5cdf..fe39a4c509283ac1fd28259bd8e1f15c5fd03c50 100644 (file)
@@ -12,6 +12,7 @@ pub mod day06;
 pub mod day07;
 pub mod day08;
 pub mod day09;
+pub mod day10;
 
 fn main() {
     let args: Vec<String> = env::args().collect();
@@ -39,6 +40,7 @@ fn run(day: &str, input_file: &str) -> Result<(), Box<dyn Error>> {
         "day07" => day07::run(input_file)?,
         "day08" => day08::run(input_file)?,
         "day09" => day09::run(input_file)?,
+        "day10" => day10::run(input_file)?,
         _ => return Err(format!("unknown day \"{day}\"").into()),
     }
     Ok(())