1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use crate::input::Input;
use std::cmp::Reverse;
use std::collections::{BinaryHeap, HashSet};
const fn is_wall(x: i32, y: i32, magic_number: i32) -> bool {
let sum = x * x + 3 * x + 2 * x * y + y + y * y + magic_number;
sum.count_ones() % 2 == 1
}
pub fn solve(input: &mut Input) -> Result<u32, String> {
const TARGET: (i32, i32) = (31, 39);
let magic_number = input
.text
.parse::<i32>()
.map_err(|e| format!("Invalid magic number: {}", e))?;
let mut to_visit = BinaryHeap::new();
let mut visited_states = HashSet::new();
let initial_state = (1, 1);
let mut visit_count = 0;
to_visit.push(Reverse((0, 0, initial_state)));
visited_states.insert(initial_state);
while let Some(Reverse((_estimate, visited_state_cost, visited_state))) = to_visit.pop() {
if input.is_part_one() {
if visited_state == TARGET {
return Ok(visited_state_cost);
}
} else if visited_state_cost > 50 {
return Ok(visit_count);
} else {
visit_count += 1;
}
for (diffx, diffy) in [(-1, 0), (1, 0), (0, -1), (0, 1)] {
let new_x = visited_state.0 + diffx;
let new_y = visited_state.1 + diffy;
if new_x < 0 || new_y < 0 || is_wall(new_x, new_y, magic_number) {
continue;
}
let new_cost = visited_state_cost + 1;
let do_insert = visited_states.insert((new_x, new_y));
if do_insert {
let new_estimate = new_cost
+ if input.is_part_one() {
(new_x - TARGET.0).unsigned_abs() + (new_y - TARGET.1).unsigned_abs()
} else {
0
};
to_visit.push(Reverse((new_estimate, new_cost, (new_x, new_y))));
}
}
}
Err("No solution found".to_string())
}
#[test]
pub fn tests() {
use crate::input::{test_part_one, test_part_two};
let real_input = include_str!("day13_input.txt");
test_part_one!(real_input => 82);
test_part_two!(real_input => 138);
}