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