This commit is contained in:
Matthias@Dell 2023-12-17 20:35:51 +01:00
parent e029841b34
commit 48db0eb9d5

View File

@ -46,6 +46,8 @@ const DOWN: u8 = 1;
const RIGHT: u8 = 2; const RIGHT: u8 = 2;
const LEFT: u8 = 3; const LEFT: u8 = 3;
const OPPOSITE: [u8; 4] = [DOWN, UP, RIGHT, LEFT];
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct Node { struct Node {
heat_loss: u8, heat_loss: u8,
@ -60,9 +62,10 @@ impl Node {
} }
impl std::fmt::Display for Node { impl std::fmt::Display for Node {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[l={}, ml={:04}{}]", self.heat_loss, self.min_heat_loss, match self.direction_from { write!(f, "[l={}, ml={:04}|{}{}{}{}]", self.heat_loss, self.min_heat_loss, self.steps_from[UP as usize], self.steps_from[DOWN as usize], self.steps_from[LEFT as usize], self.steps_from[RIGHT as usize])
// UP => '^', DOWN => 'v', LEFT => '<', RIGHT => '>', _ => 'X'}) // match self.direction_from {
UP => 'v', DOWN => '^', LEFT => '>', RIGHT => '<', _ => 'X'}) // // UP => '^', DOWN => 'v', LEFT => '<', RIGHT => '>', _ => 'X'})
// UP => 'v', DOWN => '^', LEFT => '>', RIGHT => '<', _ => 'X'})
} }
} }
@ -86,37 +89,35 @@ fn traverse_grapgh(graph: &mut Vec2D::<Node>) -> u32 {
while !queue.is_empty() { while !queue.is_empty() {
let (x, y) = queue.pop_front().unwrap(); let (x, y) = queue.pop_front().unwrap();
let opposite: u8;
let node = *graph.at(x ,y).unwrap(); // copy required because we borrow from graph later :( let node = *graph.at(x ,y).unwrap(); // copy required because we borrow from graph later :(
if !node.updated { continue; } if !node.updated { continue; }
// update surrounding reachable nodes if they can be reached at a lower cost // update surrounding reachable nodes if they can be reached at a lower cost
// dont check the one from where we came from // dont check the direction where we came from
// if updated, queue them // if updated, queue them
if node.direction_from & (UP | DOWN) != 0 { opposite = node.direction_from ^ (UP | DOWN) }
else { opposite = node.direction_from ^ (LEFT | RIGHT) }
let mut update_direction = |direction: u8| { let mut update_direction = |direction: u8| {
if direction == opposite { return } // dont update the direction from which this node was reached if node.steps_from[OPPOSITE[direction as usize] as usize] != 0 { return } // dont update directions from which this node was reached
let mut steps: u8 = 1; // check if multiple ways work
if node.direction_from == direction { if node.steps_from.iter().filter(|c| c != 0).count() == 1 && node.steps_from[direction as usize] >= 3 { return }
if node.steps_from >= 3 { return } // unreachable, because we cant walk more than 3 blocks in one direction if // unreachable, because we cant walk more than 3 blocks in one direction
steps += node.steps_from;
}
if let Some((other_x, other_y)) = go_direction(x, y, xlen, ylen, direction) { if let Some((other_x, other_y)) = go_direction(x, y, xlen, ylen, direction) {
let other_node = graph.at_mut(other_x, other_y).unwrap(); let other_node = graph.at_mut(other_x, other_y).unwrap();
let heat_loss = node.min_heat_loss + other_node.heat_loss as u32; let heat_loss = node.min_heat_loss + other_node.heat_loss as u32;
// TODO use array // TODO use array
let steps = node.steps_from[direction as usize]; .iter().filter(|c| **c > 0).min().unwrap_or() + 1;
if other_node.min_heat_loss > heat_loss { // update all if other_node.min_heat_loss > heat_loss { // update all
other_node.min_heat_loss = node.min_heat_loss + other_node.heat_loss as u32; other_node.min_heat_loss = node.min_heat_loss + other_node.heat_loss as u32;
other_node.direction_from = direction; other_node.steps_from = [0; 4];
other_node.steps_from = steps; // if this node can be reached multiple ways,
// choose the way that minimizes the other node's steps from this direction
other_node.steps_from[direction as usize] = steps;
other_node.updated = true; other_node.updated = true;
queue.push_back((other_x, other_y)); queue.push_back((other_x, other_y));
} }
else if other_node.min_heat_loss == heat_loss { // mark additional possible direction else if other_node.min_heat_loss == heat_loss { // mark additional possible direction
other_node.min_heat_loss = node.min_heat_loss + other_node.heat_loss as u32; // other_node.steps_from[direction as usize] = node.steps_from[direction as usize] + 1;
other_node.direction_from = direction; other_node.steps_from[direction as usize] = steps;
other_node.steps_from = steps;
other_node.updated = true; other_node.updated = true;
queue.push_back((other_x, other_y)); queue.push_back((other_x, other_y));
} }
@ -140,8 +141,8 @@ fn traverse_grapgh(graph: &mut Vec2D::<Node>) -> u32 {
fn main() { fn main() {
// let input = "input.txt"; // let input = "input.txt";
let input = "example.txt"; // let input = "example.txt";
// let input = "example2.txt"; let input = "example2.txt";
let mut lines = read_lines(&input); let mut lines = read_lines(&input);
let line_length = lines.next().expect("No line").unwrap().len(); let line_length = lines.next().expect("No line").unwrap().len();
let n_lines = lines.count() + 1; // already consumed one let n_lines = lines.count() + 1; // already consumed one