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 let (rows, []) = self.image.as_chunks::<WIDTH>() else {
67 unreachable!("LAYER_LEN is a multiple of WIDTH");
68 };
69
70 for x in (0..WIDTH).step_by(5) {
71 let mut letter = 0;
72 for row in rows {
73 for &pixel in &row[x..x + 5] {
74 letter = (letter << 1) | u32::from(pixel == b'1');
75 }
76 }
77
78 output.push(Self::ocr(letter));
79 }
80
81 output
82 }
83
84 #[inline]
85 pub(crate) fn ocr(letter: u32) -> char {
86 match letter {
93 0b011001001010010111101001010010 => 'A',
95 0b111001001011100100101001011100 => 'B',
96 0b011001001010000100001001001100 => 'C',
97 0b111101000011100100001000011110 => 'E',
98 0b111101000011100100001000010000 => 'F',
99 0b011001001010000101101001001110 => 'G',
100 0b100101001011110100101001010010 => 'H',
101 0b001100001000010000101001001100 => 'J',
102 0b100101010011000101001010010010 => 'K',
103 0b100001000010000100001000011110 => 'L',
104 0b111001001010010111001000010000 => 'P',
105 0b111001001010010111001010010010 => 'R',
106 0b100101001010010100101001001100 => 'U',
107 0b100011000101010001000010000100 => 'Y',
108 0b111100001000100010001000011110 => 'Z',
109 _ => Self::unknown_letter(letter),
110 }
111 }
112
113 #[cold]
114 fn unknown_letter(letter: u32) -> char {
115 let mut display = String::new();
116 for b in (0..30).rev() {
117 display.push(if letter & (1 << b) == 0 { ' ' } else { '#' });
118 if b % 5 == 0 {
119 display.push('\n');
120 }
121 }
122 panic!("unknown letter {letter:#032b}:\n{display}");
123 }
124}
125
126examples!(Day08 -> (u32, &'static str) []);