1use utils::prelude::*;
2use utils::queue::BucketQueue;
3
4#[derive(Clone, Debug)]
6pub struct Day22 {
7 depth: u32,
8 target_x: usize,
9 target_y: usize,
10}
11
12impl Day22 {
13 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
14 let (depth, target_x, target_y) = parser::u32()
15 .with_prefix("depth: ")
16 .with_eol()
17 .then(parser::number_range(0..=31).with_prefix("target: "))
18 .then(parser::number_range(0..=1021).with_prefix(b','))
19 .parse_complete(input)?;
20
21 Ok(Self {
22 depth,
23 target_x,
24 target_y,
25 })
26 }
27
28 #[must_use]
29 pub fn part1(&self) -> u32 {
30 self.scan::<0>(self.target_x + 1, self.target_y + 1)
31 .iter()
32 .sum()
33 }
34
35 #[must_use]
36 pub fn part2(&self) -> u32 {
37 let width = self.target_x + 75;
38 let height = self.target_y + 75;
39
40 let mut grid = vec![[u32::MAX; 3]; width * height];
43 for x in 0..width {
44 grid[x] = [0; 3];
45 grid[(height - 1) * width + x] = [0; 3];
46 }
47 for y in 0..height {
48 grid[y * width] = [0; 3];
49 grid[(y + 1) * width - 1] = [0; 3];
50 }
51
52 let scan = self.scan::<1>(width, height);
55 for (times, ®ion_type) in grid.iter_mut().zip(scan.iter()) {
56 times[region_type as usize] = 0;
57 }
58
59 let start_index = width + 1;
60 let target_index = (self.target_y + 1) * width + self.target_x + 1;
61
62 let mut queue = BucketQueue::<_, 8>::with_capacity(256);
63 queue.push(0, start_index << 2 | 1);
65 grid[start_index][1] = 0;
66
67 while let Some((time, packed)) = queue.pop_entry() {
68 let (time, index, tool) = (time as u32, packed >> 2, packed & 3);
69
70 if index == target_index && tool == 1 {
71 return time;
72 }
73
74 if grid[index][tool] != time {
75 continue;
76 }
77
78 let region_type = scan[index] as usize;
79 let other_tool = 3 - tool - region_type;
80
81 for (next_index, next_tool, next_time) in [
82 (index - 1, tool, time + 1),
83 (index + 1, tool, time + 1),
84 (index - width, tool, time + 1),
85 (index + width, tool, time + 1),
86 (index, other_tool, time + 7),
87 ] {
88 if grid[next_index][next_tool] > next_time {
89 grid[next_index][next_tool] = next_time;
90 queue.push(next_time as usize, next_index << 2 | next_tool);
91 }
92 }
93 }
94
95 panic!("no solution found")
96 }
97
98 fn scan<const PADDING: usize>(&self, width: usize, height: usize) -> Vec<u32> {
99 let inner_width = width - 2 * PADDING;
102 let inner_height = height - 2 * PADDING;
103 let target_index = (self.target_y + PADDING) * width + self.target_x + PADDING;
104
105 let mut erosion = vec![0u32; width * height];
106
107 let base = PADDING * width + PADDING;
108 for (x, e) in erosion[base..base + inner_width].iter_mut().enumerate() {
109 *e = ((x as u32 * 16807) + self.depth) % 20183;
110 }
111
112 for y in 1..inner_height {
113 let base = (y + PADDING) * width + PADDING;
114
115 let mut prev = ((y as u32 * 48271) + self.depth) % 20183;
116 erosion[base] = prev;
117
118 for index in base + 1..base + inner_width {
119 if index == target_index {
120 prev = self.depth % 20183;
121 } else {
122 prev = ((prev * erosion[index - width]) + self.depth) % 20183;
123 }
124 erosion[index] = prev;
125 }
126 }
127
128 erosion.into_iter().map(|x| x % 3).collect()
129 }
130}
131
132examples!(Day22 -> (u32, u32) [
133 {input: "depth: 510\ntarget: 10,10", part1: 114, part2: 45},
134]);