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)]
27struct Rectangle {
28 x1: usize,
29 x2: usize,
30 y1: usize,
31 y2: usize,
32}
33
34impl Rectangle {
35 fn from([x1, y1, x2, y2]: [usize; 4]) -> Self {
37 Self { x1, y1, x2: x2 + 1, y2: y2 + 1 }
38 }
39}
40
41#[derive(Clone, Copy)]
42pub struct Instruction {
43 command: Command,
44 rectangle: Rectangle,
45}
46
47impl Instruction {
48 fn from((bytes, points): (&[u8], [usize; 4])) -> Self {
49 Self { command: Command::from(bytes), rectangle: Rectangle::from(points) }
50 }
51}
52
53pub fn parse(input: &str) -> Vec<Instruction> {
54 let first = input.lines().map(str::as_bytes);
55 let second = input.iter_unsigned().chunk::<4>();
56 first.zip(second).map(Instruction::from).collect()
57}
58
59pub fn part1(input: &[Instruction]) -> u32 {
60 let items: Vec<_> = (0..1000).collect();
61 let result = spawn_parallel_iterator(&items, |iter| worker_one(input, iter));
62 result.into_iter().sum()
63}
64
65pub fn part2(input: &[Instruction]) -> u32 {
66 let items: Vec<_> = (0..1000).collect();
67 let result = spawn_parallel_iterator(&items, |iter| worker_two(input, iter));
68 result.into_iter().sum()
69}
70
71fn worker_one(input: &[Instruction], iter: ParIter<'_, usize>) -> u32 {
72 iter.map(|row| {
73 let mut grid = [0_u8; 1_024];
74
75 for &Instruction { command, rectangle: Rectangle { x1, y1, x2, y2 } } in input {
76 if (y1..y2).contains(row) {
77 let iter = grid[x1..x2].iter_mut();
78 match command {
79 Command::On => iter.for_each(|b| *b = 1),
80 Command::Off => iter.for_each(|b| *b = 0),
81 Command::Toggle => iter.for_each(|b| *b ^= 1),
82 }
83 }
84 }
85
86 grid.into_iter().map(|b| b as u32).sum::<u32>()
87 })
88 .sum()
89}
90
91fn worker_two(input: &[Instruction], iter: ParIter<'_, usize>) -> u32 {
92 iter.map(|row| {
93 let mut grid = [0_u8; 1_024];
94
95 for &Instruction { command, rectangle: Rectangle { x1, y1, x2, y2 } } in input {
96 if (y1..y2).contains(row) {
97 let iter = grid[x1..x2].iter_mut();
98 match command {
99 Command::On => iter.for_each(|b| *b += 1),
100 Command::Off => iter.for_each(|b| *b = b.saturating_sub(1)),
101 Command::Toggle => iter.for_each(|b| *b += 2),
102 }
103 }
104 }
105
106 grid.into_iter().map(|b| b as u32).sum::<u32>()
107 })
108 .sum()
109}