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