Skip to main content

aoc/year2015/
day06.rs

1//! # Probably a Fire Hazard
2//!
3//! Brute force approach that calculates each row independently, parallelizing the work across
4//! multiple threads.
5use 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
26pub struct Instruction {
27    command: Command,
28    x1: usize,
29    x2: usize,
30    y1: usize,
31    y2: usize,
32}
33
34impl Instruction {
35    /// Add one to both x2 and y2 to make ranges easier.
36    fn from((bytes, [x1, y1, x2, y2]): (&[u8], [usize; 4])) -> Self {
37        Self { command: Command::from(bytes), x1, x2: x2 + 1, y1, y2: y2 + 1 }
38    }
39}
40
41pub fn parse(input: &str) -> Vec<Instruction> {
42    let first = input.lines().map(str::as_bytes);
43    let second = input.iter_unsigned().chunk::<4>();
44    first.zip(second).map(Instruction::from).collect()
45}
46
47pub fn part1(input: &[Instruction]) -> u32 {
48    let items: Vec<_> = (0..1000).collect();
49    spawn_parallel_iterator(&items, |iter| worker_one(input, iter)).into_iter().sum()
50}
51
52pub fn part2(input: &[Instruction]) -> u32 {
53    let items: Vec<_> = (0..1000).collect();
54    spawn_parallel_iterator(&items, |iter| worker_two(input, iter)).into_iter().sum()
55}
56
57fn worker_one(input: &[Instruction], iter: ParIter<'_, usize>) -> u32 {
58    iter.flat_map(|row| {
59        let mut grid = [0_u8; 1_024];
60
61        for &Instruction { command, x1, x2, y1, y2 } in input {
62            if (y1..y2).contains(row) {
63                let iter = grid[x1..x2].iter_mut();
64                match command {
65                    Command::On => iter.for_each(|b| *b = 1),
66                    Command::Off => iter.for_each(|b| *b = 0),
67                    Command::Toggle => iter.for_each(|b| *b ^= 1),
68                }
69            }
70        }
71
72        grid.into_iter().map(u32::from)
73    })
74    .sum()
75}
76
77fn worker_two(input: &[Instruction], iter: ParIter<'_, usize>) -> u32 {
78    iter.flat_map(|row| {
79        let mut grid = [0_u8; 1_024];
80
81        for &Instruction { command, x1, x2, y1, y2 } in input {
82            if (y1..y2).contains(row) {
83                let iter = grid[x1..x2].iter_mut();
84                match command {
85                    Command::On => iter.for_each(|b| *b += 1),
86                    Command::Off => iter.for_each(|b| *b = b.saturating_sub(1)),
87                    Command::Toggle => iter.for_each(|b| *b += 2),
88                }
89            }
90        }
91
92        grid.into_iter().map(u32::from)
93    })
94    .sum()
95}