1use crate::util::iter::*;
6use crate::util::parse::*;
7use crate::util::thread::*;
8
9#[derive(Clone, Copy)]
10enum Command {
11 On,
12 Off,
13 Toggle,
14}
15
16impl Command {
17 fn from(bytes: &[u8]) -> Self {
18 match bytes[6] {
19 b'n' => Self::On,
20 b'f' => Self::Off,
21 _ => Self::Toggle,
22 }
23 }
24}
25
26#[derive(Clone, Copy)]
27pub struct Instruction {
28 command: Command,
29 x1: usize,
30 x2: usize,
31 y1: usize,
32 y2: usize,
33}
34
35impl Instruction {
36 fn from((bytes, [x1, y1, x2, y2]): (&[u8], [usize; 4])) -> Self {
38 Self { command: Command::from(bytes), x1, x2: x2 + 1, y1, y2: y2 + 1 }
39 }
40}
41
42pub fn parse(input: &str) -> Vec<Instruction> {
43 let first = input.lines().map(str::as_bytes);
44 let second = input.iter_unsigned().chunk::<4>();
45 first.zip(second).map(Instruction::from).collect()
46}
47
48pub fn part1(input: &[Instruction]) -> u32 {
49 let items: Vec<_> = (0..1000).collect();
50 spawn_parallel_iterator(&items, |iter| worker_one(input, iter)).into_iter().sum()
51}
52
53pub fn part2(input: &[Instruction]) -> u32 {
54 let items: Vec<_> = (0..1000).collect();
55 spawn_parallel_iterator(&items, |iter| worker_two(input, iter)).into_iter().sum()
56}
57
58fn worker_one(input: &[Instruction], iter: ParIter<'_, usize>) -> u32 {
59 iter.map(|row| {
60 let mut grid = [0_u8; 1_024];
61
62 for &Instruction { command, x1, x2, y1, y2 } in input {
63 if (y1..y2).contains(row) {
64 let iter = grid[x1..x2].iter_mut();
65 match command {
66 Command::On => iter.for_each(|b| *b = 1),
67 Command::Off => iter.for_each(|b| *b = 0),
68 Command::Toggle => iter.for_each(|b| *b ^= 1),
69 }
70 }
71 }
72
73 grid.into_iter().map(u32::from).sum::<u32>()
74 })
75 .sum()
76}
77
78fn worker_two(input: &[Instruction], iter: ParIter<'_, usize>) -> u32 {
79 iter.map(|row| {
80 let mut grid = [0_u8; 1_024];
81
82 for &Instruction { command, x1, x2, y1, y2 } in input {
83 if (y1..y2).contains(row) {
84 let iter = grid[x1..x2].iter_mut();
85 match command {
86 Command::On => iter.for_each(|b| *b += 1),
87 Command::Off => iter.for_each(|b| *b = b.saturating_sub(1)),
88 Command::Toggle => iter.for_each(|b| *b += 2),
89 }
90 }
91 }
92
93 grid.into_iter().map(u32::from).sum::<u32>()
94 })
95 .sum()
96}