y2024d16p1
This commit is contained in:
		| @@ -1,9 +1,258 @@ | ||||
| pub fn process_part1(input: &str) -> i32 { | ||||
| use std::{collections::HashMap, error::Error}; | ||||
|  | ||||
| use itertools::Itertools; | ||||
|  | ||||
| pub fn process_part1(input: &str) -> usize { | ||||
|     let mut start = (0, 0); | ||||
|     let mut end = (0, 0); | ||||
|     let grid = input | ||||
|         .lines() | ||||
|         .enumerate() | ||||
|         .map(|(yidx, row)| { | ||||
|             row.chars() | ||||
|                 .enumerate() | ||||
|                 .map(|(xidx, chara)| { | ||||
|                     let tile = GridTile::try_from(chara).unwrap(); | ||||
|                     match tile { | ||||
|                         GridTile::Wall | GridTile::Path => tile, | ||||
|                         GridTile::Start => { | ||||
|                             start = (xidx, yidx); | ||||
|                             tile | ||||
|                         } | ||||
|                         GridTile::End => { | ||||
|                             end = (xidx, yidx); | ||||
|                             tile | ||||
|                         } | ||||
|                     } | ||||
|                 }) | ||||
|                 .collect_vec() | ||||
|         }) | ||||
|         .collect_vec(); | ||||
|     let mut next_paths = vec![Reindeer { | ||||
|         coords: start, | ||||
|         ..Default::default() | ||||
|     }]; | ||||
|     let mut arrived: Vec<Reindeer> = Vec::new(); | ||||
|     let mut visited = HashMap::new(); | ||||
|     while !next_paths.is_empty() { | ||||
|         next_paths = next_paths | ||||
|             .iter() | ||||
|             .map(|reindeer| reindeer.get_all_next_paths(&grid)) | ||||
|             .collect_vec() | ||||
|             .concat(); | ||||
|         for (idx, reindeer) in next_paths.clone().iter().enumerate().rev() { | ||||
|             if let Some(score) = visited.get_mut(&reindeer.coords) { | ||||
|                 if *score <= reindeer.score { | ||||
|                     next_paths.remove(idx); | ||||
|                     continue; | ||||
|                 } else { | ||||
|                     *score = reindeer.score; | ||||
|                 } | ||||
|             } else { | ||||
|                 visited.insert(reindeer.coords, reindeer.score); | ||||
|             } | ||||
|             if reindeer.state == ReindeerState::Arrived { | ||||
|                 let arrived_reindeer = next_paths.remove(idx); | ||||
|                 arrived.push(arrived_reindeer); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     arrived.iter().map(|reindeer| reindeer.score).min().unwrap() | ||||
| } | ||||
|  | ||||
| pub fn process_part2(input: &str) -> usize { | ||||
|     0 | ||||
| } | ||||
|  | ||||
| pub fn process_part2(input: &str) -> i32 { | ||||
|     0 | ||||
| #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)] | ||||
| enum Orientation { | ||||
|     #[default] | ||||
|     East, | ||||
|     West, | ||||
|     North, | ||||
|     South, | ||||
| } | ||||
|  | ||||
| impl Orientation { | ||||
|     fn turn_clockwise(&self) -> Self { | ||||
|         match self { | ||||
|             Orientation::East => Self::South, | ||||
|             Orientation::West => Self::North, | ||||
|             Orientation::North => Self::East, | ||||
|             Orientation::South => Self::West, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn turn_counterclockwise(&self) -> Self { | ||||
|         match self { | ||||
|             Orientation::East => Self::North, | ||||
|             Orientation::West => Self::South, | ||||
|             Orientation::North => Self::West, | ||||
|             Orientation::South => Self::East, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)] | ||||
| enum ReindeerState { | ||||
|     #[default] | ||||
|     Going, | ||||
|     Arrived, | ||||
|     Stuck, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)] | ||||
| struct Reindeer { | ||||
|     orientation: Orientation, | ||||
|     coords: (usize, usize), | ||||
|     score: usize, | ||||
|     state: ReindeerState, | ||||
| } | ||||
|  | ||||
| impl Reindeer { | ||||
|     fn get_next(&self, grid: &[Vec<GridTile>]) -> Reindeer { | ||||
|         let tile = match self.orientation { | ||||
|             Orientation::East => grid[self.coords.1][self.coords.0 + 1], | ||||
|             Orientation::West => grid[self.coords.1][self.coords.0 - 1], | ||||
|             Orientation::North => grid[self.coords.1 - 1][self.coords.0], | ||||
|             Orientation::South => grid[self.coords.1 + 1][self.coords.0], | ||||
|         }; | ||||
|         let coords = match self.orientation { | ||||
|             Orientation::East => (self.coords.0 + 1, self.coords.1), | ||||
|             Orientation::West => (self.coords.0 - 1, self.coords.1), | ||||
|             Orientation::South => (self.coords.0, self.coords.1 + 1), | ||||
|             Orientation::North => (self.coords.0, self.coords.1 - 1), | ||||
|         }; | ||||
|         if tile == GridTile::Wall { | ||||
|             Reindeer { | ||||
|                 state: ReindeerState::Stuck, | ||||
|                 ..*self | ||||
|             } | ||||
|         } else if tile == GridTile::End { | ||||
|             Reindeer { | ||||
|                 score: self.score + 1, | ||||
|                 state: ReindeerState::Arrived, | ||||
|                 coords, | ||||
|                 ..*self | ||||
|             } | ||||
|         } else { | ||||
|             Reindeer { | ||||
|                 score: self.score + 1, | ||||
|                 coords, | ||||
|                 ..*self | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn get_right(&self, grid: &[Vec<GridTile>]) -> Reindeer { | ||||
|         let tile = match self.orientation { | ||||
|             Orientation::East => grid[self.coords.1 + 1][self.coords.0], | ||||
|             Orientation::West => grid[self.coords.1 - 1][self.coords.0], | ||||
|             Orientation::North => grid[self.coords.1][self.coords.0 + 1], | ||||
|             Orientation::South => grid[self.coords.1][self.coords.0 - 1], | ||||
|         }; | ||||
|         let coords = match self.orientation { | ||||
|             Orientation::East => (self.coords.0, self.coords.1 + 1), | ||||
|             Orientation::West => (self.coords.0, self.coords.1 - 1), | ||||
|             Orientation::South => (self.coords.0 - 1, self.coords.1), | ||||
|             Orientation::North => (self.coords.0 + 1, self.coords.1), | ||||
|         }; | ||||
|         if tile == GridTile::Wall { | ||||
|             Reindeer { | ||||
|                 state: ReindeerState::Stuck, | ||||
|                 ..*self | ||||
|             } | ||||
|         } else if tile == GridTile::End { | ||||
|             Reindeer { | ||||
|                 score: self.score + 1001, | ||||
|                 state: ReindeerState::Arrived, | ||||
|                 coords, | ||||
|                 orientation: self.orientation.turn_clockwise(), | ||||
|             } | ||||
|         } else { | ||||
|             Reindeer { | ||||
|                 score: self.score + 1001, | ||||
|                 orientation: self.orientation.turn_clockwise(), | ||||
|                 coords, | ||||
|                 ..*self | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn get_left(&self, grid: &[Vec<GridTile>]) -> Reindeer { | ||||
|         let tile = match self.orientation { | ||||
|             Orientation::East => grid[self.coords.1 - 1][self.coords.0], | ||||
|             Orientation::West => grid[self.coords.1 + 1][self.coords.0], | ||||
|             Orientation::North => grid[self.coords.1][self.coords.0 - 1], | ||||
|             Orientation::South => grid[self.coords.1][self.coords.0 + 1], | ||||
|         }; | ||||
|         let coords = match self.orientation { | ||||
|             Orientation::East => (self.coords.0, self.coords.1 - 1), | ||||
|             Orientation::West => (self.coords.0, self.coords.1 + 1), | ||||
|             Orientation::South => (self.coords.0 + 1, self.coords.1), | ||||
|             Orientation::North => (self.coords.0 - 1, self.coords.1), | ||||
|         }; | ||||
|         if tile == GridTile::Wall { | ||||
|             Reindeer { | ||||
|                 state: ReindeerState::Stuck, | ||||
|                 ..*self | ||||
|             } | ||||
|         } else if tile == GridTile::End { | ||||
|             Reindeer { | ||||
|                 score: self.score + 1001, | ||||
|                 state: ReindeerState::Arrived, | ||||
|                 coords, | ||||
|                 orientation: self.orientation.turn_counterclockwise(), | ||||
|             } | ||||
|         } else { | ||||
|             Reindeer { | ||||
|                 score: self.score + 1001, | ||||
|                 orientation: self.orientation.turn_counterclockwise(), | ||||
|                 coords, | ||||
|                 ..*self | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn get_all_next_paths(&self, grid: &[Vec<GridTile>]) -> Vec<Reindeer> { | ||||
|         let next = self.get_next(grid); | ||||
|         let right = self.get_right(grid); | ||||
|         let left = self.get_left(grid); | ||||
|         let mut paths = Vec::new(); | ||||
|         if next.state != ReindeerState::Stuck { | ||||
|             paths.push(next); | ||||
|         } | ||||
|         if right.state != ReindeerState::Stuck { | ||||
|             paths.push(right); | ||||
|         } | ||||
|         if left.state != ReindeerState::Stuck { | ||||
|             paths.push(left); | ||||
|         } | ||||
|         paths | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)] | ||||
| enum GridTile { | ||||
|     Wall, | ||||
|     #[default] | ||||
|     Path, | ||||
|     Start, | ||||
|     End, | ||||
| } | ||||
|  | ||||
| impl TryFrom<char> for GridTile { | ||||
|     type Error = Box<dyn Error>; | ||||
|  | ||||
|     fn try_from(value: char) -> std::result::Result<GridTile, Box<dyn Error>> { | ||||
|         match value { | ||||
|             '#' => Ok(Self::Wall), | ||||
|             '.' => Ok(Self::Path), | ||||
|             'S' => Ok(Self::Start), | ||||
|             'E' => Ok(Self::End), | ||||
|             _ => Err(Box::from(format!("{value} is not a valid tile"))), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
|   | ||||
		Reference in New Issue
	
	Block a user