1use utils::prelude::*;
2
3#[derive(Clone, Debug)]
5pub struct Day08 {
6 part1: u32,
7 image: [u8; LAYER_LEN],
8}
9
10const WIDTH: usize = 25;
11const HEIGHT: usize = 6;
12const LAYER_LEN: usize = WIDTH * HEIGHT;
13
14impl Day08 {
15 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
16 let (layers, remainder) = input.as_bytes().as_chunks::<LAYER_LEN>();
17 if layers.is_empty() || !remainder.is_empty() {
18 return Err(InputError::new(
19 input,
20 0,
21 "expected input length to be a multiple of the layer size",
22 ));
23 }
24
25 let mut image = [b'2'; LAYER_LEN];
26 let (mut min_zeroes, mut part1) = (u8::MAX, 0);
27
28 for layer in layers {
29 let (mut zeroes, mut ones, mut twos) = (0, 0, 0);
30 for (&b, o) in layer.iter().zip(image.iter_mut()) {
31 zeroes += u8::from(b == b'0');
32 ones += u8::from(b == b'1');
33 twos += u8::from(b == b'2');
34 *o = if *o == b'2' { b } else { *o };
35 }
36
37 if zeroes < min_zeroes {
38 min_zeroes = zeroes;
39 part1 = u32::from(ones) * u32::from(twos);
40 }
41
42 if zeroes + ones + twos != LAYER_LEN as u8 {
43 return Err(InputError::new(
44 input,
45 layer
46 .iter()
47 .copied()
48 .find(|&b| b != b'0' && b != b'1' && b != b'2')
49 .unwrap() as char,
50 "expected '0', '1' or '2'",
51 ));
52 }
53 }
54
55 Ok(Self { part1, image })
56 }
57
58 #[must_use]
59 pub fn part1(&self) -> u32 {
60 self.part1
61 }
62
63 #[must_use]
64 pub fn part2(&self) -> String {
65 let mut output = String::with_capacity(WIDTH / 5);
66
67 for x in (0..WIDTH).step_by(5) {
68 let mut letter = 0;
69 for row in self.image.chunks_exact(WIDTH) {
70 for &pixel in &row[x..x + 5] {
71 letter = (letter << 1) | u32::from(pixel == b'1');
72 }
73 }
74
75 output.push(Self::ocr(letter));
76 }
77
78 output
79 }
80
81 #[inline]
82 fn ocr(letter: u32) -> char {
83 match letter {
90 0b011001001010010111101001010010 => 'A',
92 0b111001001011100100101001011100 => 'B',
93 0b011001001010000100001001001100 => 'C',
94 0b111101000011100100001000011110 => 'E',
95 0b111101000011100100001000010000 => 'F',
96 0b011001001010000101101001001110 => 'G',
97 0b100101001011110100101001010010 => 'H',
98 0b001100001000010000101001001100 => 'J',
99 0b100101010011000101001010010010 => 'K',
100 0b100001000010000100001000011110 => 'L',
101 0b111001001010010111001000010000 => 'P',
102 0b111001001010010111001010010010 => 'R',
103 0b100101001010010100101001001100 => 'U',
104 0b100011000101010001000010000100 => 'Y',
105 0b111100001000100010001000011110 => 'Z',
106 _ => Self::unknown_letter(letter),
107 }
108 }
109
110 #[cold]
111 fn unknown_letter(letter: u32) -> char {
112 let mut display = String::new();
113 for b in (0..30).rev() {
114 display.push(if letter & (1 << b) == 0 { ' ' } else { '#' });
115 if b % 5 == 0 {
116 display.push('\n');
117 }
118 }
119 panic!("unknown letter {letter:#032b}:\n{display}");
120 }
121}
122
123examples!(Day08 -> (u32, &'static str) []);