1use utils::prelude::*;
2
3#[derive(Clone, Debug)]
5pub struct Day08 {
6 grid: [[bool; 50]; 6],
7}
8
9#[derive(Copy, Clone, Debug)]
10enum Instruction {
11 Rect { width: u32, height: u32 },
12 RotateRow { y: u32, by: u32 },
13 RotateCol { x: u32, by: u32 },
14}
15
16impl Day08 {
17 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
18 let rect = parser::u32()
19 .with_prefix("rect ")
20 .with_suffix("x")
21 .then(parser::u32())
22 .map(|(width, height)| Instruction::Rect { width, height });
23 let rotate_row = parser::u32()
24 .with_prefix("rotate row y=")
25 .with_suffix(" by ")
26 .then(parser::u32())
27 .map(|(y, by)| Instruction::RotateRow { y, by });
28 let rotate_col = parser::u32()
29 .with_prefix("rotate column x=")
30 .with_suffix(" by ")
31 .then(parser::u32())
32 .map(|(x, by)| Instruction::RotateCol { x, by });
33
34 let mut grid = [[false; 50]; 6];
35 for item in parser::one_of((rect, rotate_row, rotate_col))
36 .with_suffix(parser::eol())
37 .parse_iterator(input)
38 {
39 match item? {
40 Instruction::Rect { width, height } => {
41 for row in &mut grid[..height as usize] {
42 row[..width as usize].fill(true);
43 }
44 }
45 Instruction::RotateRow { y, by } => grid[y as usize].rotate_right(by as usize),
46 Instruction::RotateCol { x, by } => {
47 let col = grid.map(|row| row[x as usize]);
48 for y in 0..6 {
49 grid[y][x as usize] = col[(y + 6 - by as usize) % 6];
50 }
51 }
52 }
53 }
54
55 Ok(Self { grid })
56 }
57
58 #[must_use]
59 pub fn part1(&self) -> usize {
60 self.grid.as_flattened().iter().filter(|&&x| x).count()
61 }
62
63 #[must_use]
64 pub fn part2(&self) -> String {
65 let mut output = String::with_capacity(10);
66
67 for i in (0..50).step_by(5) {
68 let mut letter = 0;
69 for row in self.grid {
70 for &b in &row[i..i + 5] {
71 letter <<= 1;
72 if b {
73 letter |= 1;
74 }
75 }
76 }
77 output.push(Self::ocr(letter));
78 }
79
80 output
81 }
82
83 fn ocr(letter: u32) -> char {
84 match letter {
91 0b011001001010010111101001010010 => 'A',
93 0b111001001011100100101001011100 => 'B',
94 0b011001001010000100001001001100 => 'C',
95 0b111101000011100100001000011110 => 'E',
96 0b111101000011100100001000010000 => 'F',
97 0b011001001010000101101001001110 => 'G',
98 0b100101001011110100101001010010 => 'H',
99 0b011100010000100001000010001110 => 'I',
100 0b001100001000010000101001001100 => 'J',
101 0b100101010011000101001010010010 => 'K',
102 0b100001000010000100001000011110 => 'L',
103 0b011001001010010100101001001100 => 'O',
104 0b111001001010010111001000010000 => 'P',
105 0b111001001010010111001010010010 => 'R',
106 0b011101000010000011000001011100 => 'S',
107 0b100101001010010100101001001100 => 'U',
108 0b100011000101010001000010000100 => 'Y',
109 0b111100001000100010001000011110 => 'Z',
110 _ => {
111 let mut display = String::new();
112 for b in (0..30).rev() {
113 display.push(if letter & (1 << b) == 0 { ' ' } else { '#' });
114 if b % 5 == 0 {
115 display.push('\n');
116 }
117 }
118 panic!("unknown letter {letter:#032b}:\n{display}");
119 }
120 }
121 }
122}
123
124examples!(Day08 -> (usize, &'static str) [
125 {
126 input: "rect 3x2\n\
127 rotate column x=1 by 1\n\
128 rotate row y=0 by 4\n\
129 rotate column x=1 by 1",
130 part1: 6,
131 },
132]);