Day 24, part 1
This commit is contained in:
parent
98fcdfeaef
commit
a7d32abb93
13
src/bin/d24p1.rs
Normal file
13
src/bin/d24p1.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
use aoc22::{
|
||||||
|
day24::{self},
|
||||||
|
util,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let (map, start, target) = day24::parse_map(&util::parse_input());
|
||||||
|
|
||||||
|
day24::print_map(&map, &start);
|
||||||
|
|
||||||
|
let rounds = day24::find_path(&map, &start, &target);
|
||||||
|
println!("Goal is reachable in {} min", rounds);
|
||||||
|
}
|
177
src/day24.rs
Normal file
177
src/day24.rs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use crate::util::{Coord, Dir};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Tile {
|
||||||
|
Empty,
|
||||||
|
Wall,
|
||||||
|
Blizzards(Vec<Dir>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns (map, start, end)
|
||||||
|
pub fn parse_map(input: &str) -> (Vec<Vec<Tile>>, Coord, Coord) {
|
||||||
|
let mut map = Vec::new();
|
||||||
|
|
||||||
|
for line in input.lines() {
|
||||||
|
let mut row = Vec::new();
|
||||||
|
|
||||||
|
for c in line.chars() {
|
||||||
|
row.push(match c {
|
||||||
|
'.' => Tile::Empty,
|
||||||
|
'#' => Tile::Wall,
|
||||||
|
_ => Tile::Blizzards(vec![Dir::from_char(c).unwrap()]),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
map.push(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(map.len() >= 2);
|
||||||
|
let last_row = map.len() - 1;
|
||||||
|
|
||||||
|
let start = map[0]
|
||||||
|
.iter()
|
||||||
|
.position(|t| matches!(t, Tile::Empty))
|
||||||
|
.unwrap();
|
||||||
|
let end = map[last_row]
|
||||||
|
.iter()
|
||||||
|
.position(|t| matches!(t, Tile::Empty))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
(map, (0, start), (last_row, end))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_map(map: &Vec<Vec<Tile>>, expedition: &Coord) {
|
||||||
|
for (y, row) in map.iter().enumerate() {
|
||||||
|
for (x, tile) in row.iter().enumerate() {
|
||||||
|
if *expedition == (y, x) {
|
||||||
|
print!("E");
|
||||||
|
} else {
|
||||||
|
match tile {
|
||||||
|
Tile::Empty => print!("."),
|
||||||
|
Tile::Wall => print!("#"),
|
||||||
|
Tile::Blizzards(blizzards) => {
|
||||||
|
if blizzards.len() > 1 {
|
||||||
|
print!("{}", blizzards.len());
|
||||||
|
} else {
|
||||||
|
print!("{}", blizzards[0].to_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print!("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_map(map: &Vec<Vec<Tile>>) -> Vec<Vec<Tile>> {
|
||||||
|
assert!(map.len() > 0);
|
||||||
|
// Outermost rows/columns are walls
|
||||||
|
let min_y = 1;
|
||||||
|
let max_y = map.len() - 2;
|
||||||
|
let min_x = 1;
|
||||||
|
let max_x = map[0].len() - 2;
|
||||||
|
|
||||||
|
// Start with a map without blizzards
|
||||||
|
let mut result: Vec<Vec<Tile>> = map
|
||||||
|
.iter()
|
||||||
|
.map(|r| {
|
||||||
|
r.iter()
|
||||||
|
.map(|t| {
|
||||||
|
if matches!(t, Tile::Blizzards(_)) {
|
||||||
|
Tile::Empty
|
||||||
|
} else {
|
||||||
|
t.clone()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for y in 0..map.len() {
|
||||||
|
for x in 0..map[0].len() {
|
||||||
|
if let Tile::Blizzards(blizzards) = &map[y][x] {
|
||||||
|
for blizzard_dir in blizzards {
|
||||||
|
let new_tile = match blizzard_dir {
|
||||||
|
Dir::Right => {
|
||||||
|
if x == max_x {
|
||||||
|
(y, min_x)
|
||||||
|
} else {
|
||||||
|
(y, x + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dir::Down => {
|
||||||
|
if y == max_y {
|
||||||
|
(min_y, x)
|
||||||
|
} else {
|
||||||
|
(y + 1, x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dir::Left => {
|
||||||
|
if x == min_x {
|
||||||
|
(y, max_x)
|
||||||
|
} else {
|
||||||
|
(y, x - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Dir::Up => {
|
||||||
|
if y == min_y {
|
||||||
|
(max_y, x)
|
||||||
|
} else {
|
||||||
|
(y - 1, x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let new_tile = &mut result[new_tile.0][new_tile.1];
|
||||||
|
if let Tile::Blizzards(blizzards) = new_tile {
|
||||||
|
blizzards.push(*blizzard_dir);
|
||||||
|
} else {
|
||||||
|
assert!(matches!(new_tile, Tile::Empty));
|
||||||
|
*new_tile = Tile::Blizzards(vec![*blizzard_dir]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns length of the shortest path
|
||||||
|
pub fn find_path(initial: &Vec<Vec<Tile>>, start: &Coord, target: &Coord) -> usize {
|
||||||
|
let mut map = initial.clone();
|
||||||
|
let mut to_check = HashSet::new();
|
||||||
|
to_check.insert(*start);
|
||||||
|
let mut rounds = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
map = next_map(&map);
|
||||||
|
rounds += 1;
|
||||||
|
let mut check_next = HashSet::new();
|
||||||
|
|
||||||
|
for pos in to_check {
|
||||||
|
let mut reachable = vec![
|
||||||
|
pos,
|
||||||
|
(pos.0 + 1, pos.1),
|
||||||
|
(pos.0, pos.1 + 1),
|
||||||
|
(pos.0, pos.1 - 1),
|
||||||
|
];
|
||||||
|
// This would underflow in the first round
|
||||||
|
if pos.0 != 0 {
|
||||||
|
reachable.push((pos.0 - 1, pos.1));
|
||||||
|
}
|
||||||
|
|
||||||
|
for p in reachable {
|
||||||
|
if p == *target {
|
||||||
|
return rounds;
|
||||||
|
}
|
||||||
|
if matches!(map[p.0][p.1], Tile::Empty) {
|
||||||
|
check_next.insert(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
to_check = check_next;
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ pub mod day20;
|
|||||||
pub mod day21;
|
pub mod day21;
|
||||||
pub mod day22;
|
pub mod day22;
|
||||||
pub mod day23;
|
pub mod day23;
|
||||||
|
pub mod day24;
|
||||||
pub mod day3;
|
pub mod day3;
|
||||||
pub mod day4;
|
pub mod day4;
|
||||||
pub mod day5;
|
pub mod day5;
|
||||||
|
19
src/util.rs
19
src/util.rs
@ -144,6 +144,25 @@ impl Dir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_char(c: char) -> Option<Dir> {
|
||||||
|
match c {
|
||||||
|
'^' => Some(Dir::Up),
|
||||||
|
'>' => Some(Dir::Right),
|
||||||
|
'v' => Some(Dir::Down),
|
||||||
|
'<' => Some(Dir::Left),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Dir::Right => ">",
|
||||||
|
Dir::Down => "v",
|
||||||
|
Dir::Left => "<",
|
||||||
|
Dir::Up => "^",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cw(&self) -> Dir {
|
pub fn cw(&self) -> Dir {
|
||||||
let d = *self as usize;
|
let d = *self as usize;
|
||||||
Self::from_usize((d + 1) % 4).unwrap()
|
Self::from_usize((d + 1) % 4).unwrap()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user