1use crate::util::thread::*;
9use std::array::from_fn;
10
11pub fn parse(input: &str) -> Vec<u8> {
13 let prefix = input.trim();
14 let rows: Vec<_> = (0..128).collect();
15 let result = spawn_parallel_iterator(&rows, |iter| worker(prefix, iter));
16
17 let mut sorted: Vec<_> = result.into_iter().flatten().collect();
18 sorted.sort_unstable_by_key(|&(index, _)| index);
19 sorted.into_iter().flat_map(|(_, row)| row).collect()
20}
21
22pub fn part1(input: &[u8]) -> u32 {
23 input.iter().map(|&n| n as u32).sum()
24}
25
26pub fn part2(input: &[u8]) -> u32 {
27 let mut grid: Vec<_> = input.iter().map(|&n| n == 1).collect();
28 let mut groups = 0;
29
30 for start in 0..0x4000 {
31 if grid[start] {
33 groups += 1;
34 dfs(&mut grid, start);
35 }
36 }
37
38 groups
39}
40
41fn worker(prefix: &str, iter: ParIter<'_, usize>) -> Vec<(usize, Vec<u8>)> {
44 iter.map(|&index| (index, fill_row(prefix, index))).collect()
45}
46
47fn fill_row(prefix: &str, index: usize) -> Vec<u8> {
49 let s = format!("{prefix}-{index}");
50 let mut lengths: Vec<_> = s.bytes().map(|b| b as usize).collect();
51 lengths.extend([17, 31, 73, 47, 23]);
52
53 let knot = knot_hash(&lengths);
54 let mut result = vec![0; 128];
55
56 for (i, chunk) in knot.chunks_exact(16).enumerate() {
57 let reduced = chunk.iter().fold(0, |acc, n| acc ^ n);
58 for j in 0..8 {
59 result[8 * i + j] = (reduced >> (7 - j)) & 1;
60 }
61 }
62
63 result
64}
65
66#[inline]
69fn knot_hash(lengths: &[usize]) -> [u8; 256] {
70 let mut knot: [u8; 256] = from_fn(|i| i as u8);
71 let mut position = 0;
72 let mut skip = 0;
73
74 for _ in 0..64 {
75 for &length in lengths {
76 let next = length + skip;
77 knot[0..length].reverse();
78 knot.rotate_left(next % 256);
79 position += next;
80 skip += 1;
81 }
82 }
83
84 knot.rotate_right(position % 256);
86 knot
87}
88
89fn dfs(grid: &mut [bool], index: usize) {
91 grid[index] = false;
92 let x = index % 128;
93 let y = index / 128;
94
95 if x > 0 && grid[index - 1] {
96 dfs(grid, index - 1);
97 }
98 if x < 127 && grid[index + 1] {
99 dfs(grid, index + 1);
100 }
101 if y > 0 && grid[index - 128] {
102 dfs(grid, index - 128);
103 }
104 if y < 127 && grid[index + 128] {
105 dfs(grid, index + 128);
106 }
107}