y2024d16p1

This commit is contained in:
Fabian Schmidt 2024-12-16 14:48:17 +01:00
parent b20aa6fbdc
commit 6e3d6625ee

View File

@ -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 0
} }
pub fn process_part2(input: &str) -> i32 { #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)]
0 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)] #[cfg(test)]