use crate::util::thread::*;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;
pub struct Shared {
prefix: String,
counter: AtomicUsize,
mutex: Mutex<Exclusive>,
}
struct Exclusive {
grid: Vec<u8>,
}
pub fn parse(input: &str) -> Vec<u8> {
let shared = Shared {
prefix: input.trim().to_owned(),
counter: AtomicUsize::new(0),
mutex: Mutex::new(Exclusive { grid: vec![0; 0x4000] }),
};
spawn(|| worker(&shared));
shared.mutex.into_inner().unwrap().grid
}
pub fn part1(input: &[u8]) -> u32 {
input.iter().map(|&n| n as u32).sum()
}
pub fn part2(input: &[u8]) -> u32 {
let mut grid: Vec<_> = input.iter().map(|&n| n == 1).collect();
let mut groups = 0;
for start in 0..0x4000 {
if grid[start] {
groups += 1;
dfs(&mut grid, start);
}
}
groups
}
fn worker(shared: &Shared) {
loop {
let index = shared.counter.fetch_add(1, Ordering::Relaxed);
if index >= 128 {
break;
}
let row = fill_row(&shared.prefix, index);
let start = index * 128;
let end = start + 128;
let mut exclusive = shared.mutex.lock().unwrap();
exclusive.grid[start..end].copy_from_slice(&row);
}
}
fn fill_row(prefix: &str, index: usize) -> [u8; 128] {
let s = format!("{prefix}-{index}");
let mut lengths: Vec<_> = s.bytes().map(|b| b as usize).collect();
lengths.extend([17, 31, 73, 47, 23]);
let knot = knot_hash(&lengths);
let mut result = [0; 128];
for (i, chunk) in knot.chunks_exact(16).enumerate() {
let reduced = chunk.iter().fold(0, |acc, n| acc ^ n);
for j in 0..8 {
result[8 * i + j] = (reduced >> (7 - j)) & 1;
}
}
result
}
fn knot_hash(lengths: &[usize]) -> Vec<u8> {
let mut knot: Vec<_> = (0..=255).collect();
let mut position = 0;
let mut skip = 0;
for _ in 0..64 {
for &length in lengths {
let next = length + skip;
knot[0..length].reverse();
knot.rotate_left(next % 256);
position += next;
skip += 1;
}
}
knot.rotate_right(position % 256);
knot
}
fn dfs(grid: &mut [bool], index: usize) {
grid[index] = false;
let x = index % 128;
let y = index / 128;
if x > 0 && grid[index - 1] {
dfs(grid, index - 1);
}
if x < 127 && grid[index + 1] {
dfs(grid, index + 1);
}
if y > 0 && grid[index - 128] {
dfs(grid, index - 128);
}
if y < 127 && grid[index + 128] {
dfs(grid, index + 128);
}
}