diff --git a/day20/Cargo.lock b/day20/Cargo.lock new file mode 100644 index 0000000..3124e93 --- /dev/null +++ b/day20/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "day20" +version = "0.1.0" +dependencies = [ + "glam", +] + +[[package]] +name = "glam" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" diff --git a/day20/Cargo.toml b/day20/Cargo.toml new file mode 100644 index 0000000..e908723 --- /dev/null +++ b/day20/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "day20" +version = "0.1.0" +edition = "2021" + +[dependencies] +glam = "0.29.2" diff --git a/day20/src/main.rs b/day20/src/main.rs new file mode 100644 index 0000000..9462c77 --- /dev/null +++ b/day20/src/main.rs @@ -0,0 +1,159 @@ +use std::fmt::Display; + +use glam::IVec2; + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +enum Direction { + Up, + Left, + Down, + Right, +} +use Direction::*; + +impl Direction { + fn to_vec(self) -> IVec2 { + match self { + Up => IVec2::new(-1, 0), + Left => IVec2::new(0, -1), + Down => IVec2::new(1, 0), + Right => IVec2::new(0, 1), + } + } + + fn all() -> Vec { + vec![Up, Left, Down, Right] + } + + fn orthogonal(&self) -> Vec { + match self { + Up | Down => vec![Left, Right], + Left | Right => vec![Up, Down], + } + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +enum TileType { + Free, + Wall, + Start, + End, +} +use TileType::*; + +impl Display for TileType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Free => write!(f, "."), + Wall => write!(f, "#"), + Start => write!(f, "S"), + End => write!(f, "E"), + } + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +struct Tile { + tiletype: TileType, + distance: usize, +} + +impl Display for Tile { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.distance < usize::MAX { + write!(f, ",") + } else { + write!(f, "{}", self.tiletype) + } + } +} + +fn parse(input: &str) -> (Vec>, IVec2) { + let mut start_pos = IVec2::new(0, 0); + ( + input + .lines() + .enumerate() + .map(|(l_idx, l)| { + l.chars() + .enumerate() + .map(|(c_idx, c)| Tile { + tiletype: match c { + '#' => Wall, + 'S' => { + start_pos.x = l_idx as i32; + start_pos.y = c_idx as i32; + Start + } + 'E' => End, + _ => Free, + }, + distance: usize::MAX, + }) + .collect() + }) + .collect(), + start_pos, + ) +} + +fn get_distances(map: &mut [Vec], pos: &IVec2, distance: &usize, path: &mut Vec) { + let curr_tile = &mut map[pos.x as usize][pos.y as usize]; + curr_tile.distance = *distance; + if curr_tile.tiletype == End { + return; + } + for direction in Direction::all() { + let new_tile_pos = pos + direction.to_vec(); + let new_tile = map[new_tile_pos.x as usize][new_tile_pos.y as usize]; + if new_tile.tiletype != Wall && new_tile.distance > distance + 1 { + path.push(new_tile_pos); + get_distances(map, &new_tile_pos, &(distance + 1), path); + } + } +} + +fn part12(map: &[Vec], path: &[IVec2], max_distance: i32) -> usize { + let mut res = 0; + for tile in path { + let mut cheated_targets = vec![]; + for direction in Direction::all() { + for i in 2..=max_distance { + for j in 0..=(max_distance - i) { + for other_direction in direction.orthogonal() { + let new_tile_pos = + tile + i * direction.to_vec() + j * other_direction.to_vec(); + let Some(Some(t)) = map + .get(new_tile_pos.x as usize) + .map(|l| l.get(new_tile_pos.y as usize)) + else { + continue; + }; + if t.tiletype == Wall || cheated_targets.contains(&new_tile_pos) { + continue; + } + if t.distance + >= map[tile.x as usize][tile.y as usize].distance + + 100 + + i as usize + + j as usize + { + cheated_targets.push(new_tile_pos); + res += 1; + } + } + } + } + } + } + res +} + +fn main() { + let (mut map, start_pos) = parse(include_str!("../input.txt")); + let mut path = vec![start_pos]; + get_distances(&mut map, &start_pos, &0, &mut path); + println!("{}", part12(&map, &path, 2)); + println!("{}", part12(&map, &path, 20)); +}