y2024d16p1
This commit is contained in:
parent
b20aa6fbdc
commit
6e3d6625ee
@ -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)]
|
||||
|
Loading…
Reference in New Issue
Block a user