Skip to main content

aoc/year2016/
day13.rs

1//! # A Maze of Twisty Little Cubicles
2//!
3//! We first generate the maze dynamically then explore it using a
4//! [BFS](https://en.wikipedia.org/wiki/Breadth-first_search) solving both part one and part
5//! two simultaneously.
6//!
7//! As we start at (1, 1) and the most steps that we are interested in for part two is 50, while
8//! part one requires more than 50 steps but should easily be reachable without exceeding bounds,
9//! we can bound the maze to 2 + 50 = 52 in each dimension and use a fixed-size array. Rather
10//! than filling the array up front, we can lazily populate it as the horizon expands.
11use crate::util::parse::*;
12use std::collections::VecDeque;
13
14type Input = (u32, u32);
15
16pub fn parse(input: &str) -> Input {
17    let favorite: usize = input.unsigned();
18
19    // Lazy evaluation. Set maze[x][y] to true once a point is visited.
20    let mut maze = [[false; 52]; 52];
21    maze[1][1] = true;
22    let mut at = |x: usize, y: usize| -> bool {
23        if maze[x][y] {
24            return false;
25        }
26        maze[x][y] = true;
27        let n = (x * x) + (3 * x) + (2 * x * y) + y + (y * y) + favorite;
28        n.count_ones().is_multiple_of(2)
29    };
30
31    let mut part_two = 0;
32    let mut todo = VecDeque::new();
33
34    todo.push_back((1, 1, 0));
35
36    while let Some((x, y, cost)) = todo.pop_front() {
37        // Target is at least 68 moves from the start. Since we're doing a BFS we're guaranteed
38        // to have checked all locations less than or equal to 50 before reaching the target.
39        if x == 31 && y == 39 {
40            return (cost, part_two);
41        }
42        if cost <= 50 {
43            part_two += 1;
44        }
45
46        if x > 0 && at(x - 1, y) {
47            todo.push_back((x - 1, y, cost + 1));
48        }
49        if y > 0 && at(x, y - 1) {
50            todo.push_back((x, y - 1, cost + 1));
51        }
52        if at(x + 1, y) {
53            todo.push_back((x + 1, y, cost + 1));
54        }
55        if at(x, y + 1) {
56            todo.push_back((x, y + 1, cost + 1));
57        }
58    }
59
60    unreachable!()
61}
62
63pub fn part1(input: &Input) -> u32 {
64    input.0
65}
66
67pub fn part2(input: &Input) -> u32 {
68    input.1
69}