Skip to content

Commit

Permalink
Faster approach with incremental BFS
Browse files Browse the repository at this point in the history
  • Loading branch information
maneatingape committed Dec 18, 2024
1 parent 15739f5 commit 9b9bd69
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 36 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
| 15 | [Warehouse Woes](https://adventofcode.com/2024/day/15) | [Source](src/year2024/day15.rs) | 303 |
| 16 | [Reindeer Maze](https://adventofcode.com/2024/day/16) | [Source](src/year2024/day16.rs) | 390 |
| 17 | [Chronospatial Computer](https://adventofcode.com/2024/day/17) | [Source](src/year2024/day17.rs) | 2 |
| 18 | [RAM Run](https://adventofcode.com/2024/day/18) | [Source](src/year2024/day18.rs) | 61 |
| 18 | [RAM Run](https://adventofcode.com/2024/day/18) | [Source](src/year2024/day18.rs) | 42 |

## 2023

Expand Down
82 changes: 47 additions & 35 deletions src/year2024/day18.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,66 +14,78 @@
//! ```
//!
//! Now we can [BFS](https://en.wikipedia.org/wiki/Breadth-first_search) from any arbitrary
//! start time. Squares are blocked only if the grid time is less than or equal to the start time.
//!
//! A [binary search](https://en.wikipedia.org/wiki/Binary_search) is much faster than a
//! linear search with complexity `O(log₂n)` vs `O(n)`. For example `log₂(3450) = 12`.
//! start time. Squares are allowed if the grid time is greater than the start time.
use crate::util::grid::*;
use crate::util::iter::*;
use crate::util::parse::*;
use crate::util::point::*;
use crate::util::heap::*;
use std::collections::VecDeque;

pub fn parse(input: &str) -> Grid<u16> {
let mut grid = Grid::new(71, 71, u16::MAX);
pub fn parse(input: &str) -> Grid<i32> {
let mut grid = Grid::new(71, 71, i32::MAX);

for (i, [x, y]) in input.iter_signed::<i32>().chunk::<2>().enumerate() {
grid[Point::new(x, y)] = i as u16;
grid[Point::new(x, y)] = i as i32;
}

grid
}

pub fn part1(grid: &Grid<u16>) -> u32 {
bfs(grid, 1024).unwrap()
}

pub fn part2(grid: &Grid<u16>) -> String {
let mut lower = 0;
let mut upper = 5041;

while lower < upper {
let middle = (lower + upper) / 2;
if bfs(grid, middle).is_some() {
lower = middle + 1;
} else {
upper = middle;
}
}

let index = grid.bytes.iter().position(|&time| time == lower).unwrap() as i32;
format!("{},{}", index % grid.width, index / grid.width)
}

fn bfs(grid: &Grid<u16>, time: u16) -> Option<u32> {
pub fn part1(grid: &Grid<i32>) -> u32 {
let mut grid = grid.clone();
let mut todo = VecDeque::new();
let mut seen = grid.clone();

grid[ORIGIN] = 0;
todo.push_back((ORIGIN, 0));
seen[ORIGIN] = 0;

while let Some((position, cost)) = todo.pop_front() {
if position == Point::new(70, 70) {
return Some(cost);
return cost;
}

for next in ORTHOGONAL.map(|o| position + o) {
if seen.contains(next) && time < seen[next] {
if grid.contains(next) && grid[next] > 1024 {
grid[next] = 0;
todo.push_back((next, cost + 1));
seen[next] = 0;
}
}
}

None
unreachable!()
}

pub fn part2(grid: &Grid<i32>) -> String {
let mut time = i32::MAX;
let mut heap = MinHeap::new();

let mut grid = grid.clone();
let mut todo = VecDeque::new();

grid[ORIGIN] = 0;
todo.push_back(ORIGIN);

loop {
while let Some(position) = todo.pop_front() {
if position == Point::new(70, 70) {
let index = grid.bytes.iter().position(|&b| b == time).unwrap() as i32;
return format!("{},{}", index % grid.width, index / grid.width);
}

for next in ORTHOGONAL.map(|o| position + o) {
if grid.contains(next) {
if time < grid[next] {
grid[next] = 0;
todo.push_back(next);
} else {
heap.push(-grid[next], next);
}
}
}
}

let (first, saved) = heap.pop().unwrap();
time = -first;
todo.push_back(saved);
}
}

0 comments on commit 9b9bd69

Please sign in to comment.