From 527b156882e8e53c3f11a2f94799fcb1f4fa70e7 Mon Sep 17 00:00:00 2001 From: Ishan Jain Date: Tue, 17 Dec 2024 00:54:55 +0530 Subject: [PATCH] added optimized versions of day16 --- src/day16/1.rs | 124 ++++++++++++++++++++++++++++++++++++ src/day16/2.rs | 166 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 src/day16/1.rs create mode 100644 src/day16/2.rs diff --git a/src/day16/1.rs b/src/day16/1.rs new file mode 100644 index 0000000..e67c800 --- /dev/null +++ b/src/day16/1.rs @@ -0,0 +1,124 @@ + +#![feature(test)] +extern crate test; + +use std::cmp::Reverse; +use std::collections::BinaryHeap; +use fxhash::FxHashMap; + +const INPUTS: [&str; 2] = [ + "############### +#.......#....E# +#.#.###.#.###.# +#.....#.#...#.# +#.###.#####.#.# +#.#.#.......#.# +#.#.#####.###.# +#...........#.# +###.#.#####.#.# +#...#.....#.#.# +#.#.#.###.#.#.# +#.....#...#.#.# +#.###.#.#.#.#.# +#S..#.....#...# +###############", + include_str!("./input.txt"), +]; + +pub fn run(input: &str) -> i64 { + let grid = input.lines().map(|x| x.chars().collect::>()).collect::>>(); + let m = grid.len(); + let n = grid[0].len(); + + let mut sx = 0; + let mut sy = 0; + + let mut ex = 0; + let mut ey = 0; + + for i in 0..m { + for j in 0..n { + if grid[i][j] == 'S' { + sx = i as i64; + sy = j as i64; + } else if grid[i][j] == 'E' { + ex = i as i64; + ey = j as i64; + } + } + } + + dijkstra(&grid, (sx,sy), (ex,ey)) +} + +fn dijkstra(grid: &Vec>, (sx, sy): (i64, i64), (ex, ey): (i64, i64)) -> i64 { + + let mut best = std::i64::MAX; + + let mut map = FxHashMap::default(); + map.insert((sx,sy, 1), 0); + + let mut heap = BinaryHeap::new(); + heap.push((Reverse(0), sx, sy, 1)); + + while let Some((Reverse(score), x, y, dir)) = heap.pop() { + if score >= best { + continue; + } + if x == ex && y == ey { + best = std::cmp::min(best, score); + continue; + } + if grid[x as usize][y as usize] == '#' { + continue; + } + + if *map.entry((x,y,dir)).or_insert(score) < score { + continue; + } + + match dir { + 0 => { + heap.push((Reverse(score+1), x-1, y, 0)); + + heap.push((Reverse(score+1001), x, y+1, 1)); + heap.push((Reverse(score+1001), x, y-1, 3)); + }, + 1 => { + heap.push((Reverse(score+1), x, y+1, 1)); + + heap.push((Reverse(score+1001), x+1,y, 2)); + heap.push((Reverse(score+1001), x-1,y, 0)); + } + 2 => { + heap.push((Reverse(score+1), x+1, y, 2)); + + heap.push((Reverse(score+1001), x, y+1, 1)); + heap.push((Reverse(score+1001), x, y-1, 3)); + } + 3 => { + heap.push((Reverse(score+1), x, y-1, 3)); + + heap.push((Reverse(score+1001), x-1, y, 0)); + heap.push((Reverse(score+1001), x+1, y, 2)); + } + _ => () + } + } + + best +} + +fn main() { + for input in INPUTS.iter() { + println!("answer = {}", run(input)); + } +} + +#[bench] +fn part1(b: &mut test::Bencher) { + b.iter(|| { + let v = run(INPUTS[1]); + test::black_box(v); + }); +} diff --git a/src/day16/2.rs b/src/day16/2.rs new file mode 100644 index 0000000..f44845e --- /dev/null +++ b/src/day16/2.rs @@ -0,0 +1,166 @@ +#![feature(test)] +extern crate test; + +use std::cmp::Reverse; +use std::collections::BinaryHeap; +use fxhash::FxHashMap; + +const INPUTS: [&str; 2] = [ + "############### +#.......#....E# +#.#.###.#.###.# +#.....#.#...#.# +#.###.#####.#.# +#.#.#.......#.# +#.#.#####.###.# +#...........#.# +###.#.#####.#.# +#...#.....#.#.# +#.#.#.###.#.#.# +#.....#...#.#.# +#.###.#.#.#.#.# +#S..#.....#...# +###############", + include_str!("./input.txt"), +]; + +pub fn run(input: &str) -> i64 { + let grid = input.lines().map(|x| x.chars().collect::>()).collect::>>(); + let m = grid.len(); + let n = grid[0].len(); + + let mut sx = 0; + let mut sy = 0; + + let mut ex = 0; + let mut ey = 0; + + for i in 0..m { + for j in 0..n { + if grid[i][j] == 'S' { + sx = i as i64; + sy = j as i64; + } else if grid[i][j] == 'E' { + ex = i as i64; + ey = j as i64; + } + } + } + + let visited_nodes = dijkstra(&grid, (sx,sy), (ex,ey)); + + visited_nodes.count() as i64 +} + +fn dijkstra(grid: &Vec>, (sx, sy): (i64, i64), (ex, ey): (i64, i64)) -> Bitmap { + let mut best = std::i64::MAX; + + let mut map = FxHashMap::default(); + let mut visited = Bitmap::new(grid.len() as i64, grid[0].len() as i64); + let mut heap = BinaryHeap::new(); + let path = Bitmap::new(grid.len() as i64, grid[0].len() as i64) + .set(sx,sy); + + heap.push((Reverse(0), sx, sy, 1, path)); + map.insert((sx,sy, 1), 0); + + while let Some((Reverse(score), x, y, dir, path)) = heap.pop() { + if score > best { + continue; + } + if x == ex && y == ey { + visited.merge(path); + best = std::cmp::min(best, score); + continue; + } + if grid[x as usize][y as usize] == '#' { + continue; + } + + if *map.entry((x,y,dir)).or_insert(score) < score { + continue; + } + + match dir { + 0 => { + heap.push((Reverse(score+1), x-1, y, 0, path.clone().set(x-1,y))); + + heap.push((Reverse(score+1001), x, y+1, 1, path.clone().set(x,y+1))); + heap.push((Reverse(score+1001), x, y-1, 3, path.clone().set(x,y-1))); + }, + 1 => { + heap.push((Reverse(score+1), x, y+1, 1, path.clone().set(x,y+1))); + + heap.push((Reverse(score+1001), x+1,y, 2, path.clone().set(x+1,y))); + heap.push((Reverse(score+1001), x-1,y, 0, path.clone().set(x-1,y))); + } + 2 => { + heap.push((Reverse(score+1), x+1, y, 2, path.clone().set(x+1,y))); + + heap.push((Reverse(score+1001), x, y+1, 1, path.clone().set(x,y+1))); + heap.push((Reverse(score+1001), x, y-1, 3, path.clone().set(x,y-1))); + } + 3 => { + heap.push((Reverse(score+1), x, y-1, 3, path.clone().set(x,y-1))); + + heap.push((Reverse(score+1001), x-1, y, 0, path.clone().set(x-1,y))); + heap.push((Reverse(score+1001), x+1, y, 2, path.clone().set(x+1,y))); + } + _ => () + } + } + + visited +} + + +const WORD_SIZE: usize = 64; + +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)] +struct Bitmap { + inner: Vec, + n: i64 +} + +impl Bitmap { + fn new(m: i64, n: i64) -> Self { + Self { + inner: vec![0; ((m * n) as usize / WORD_SIZE) + 1], + n + } + } + + fn merge(&mut self, p2: Bitmap) { + for (a,b) in self.inner.iter_mut().zip(p2.inner.into_iter()) { + *a |= b; + } + } + + fn set(mut self, x: i64, y: i64) -> Self { + let offset = (x * self.n + y) as usize; + let index = offset / WORD_SIZE; + let bit_offset = offset % WORD_SIZE; + + self.inner[index] |= 1 << bit_offset; + + self + } + + fn count(self) -> u32 { + self.inner.into_iter().fold(0, |a,x| a + x.count_ones()) + } +} + +fn main() { + for input in INPUTS.iter() { + println!("answer = {}", run(input)); + } +} + +#[bench] +fn part1(b: &mut test::Bencher) { + b.iter(|| { + let v = run(INPUTS[1]); + test::black_box(v); + }); +}