1use utils::prelude::*;
2
3#[derive(Clone, Debug)]
5pub struct Day06 {
6 frequencies: Vec<[u32; 26]>,
7}
8
9impl Day06 {
10 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
11 if let Some(b) = input.bytes().find(|b| !matches!(b, b'a'..=b'z' | b'\n')) {
12 return Err(InputError::new(
13 input,
14 b as char,
15 "expected lowercase letter or newline",
16 ));
17 }
18
19 let Some(length) = input.find('\n') else {
20 return Err(InputError::new(input, 0, "expected at least one newline"));
21 };
22
23 let mut frequencies = vec![[0; 26]; length];
24 for l in input.lines() {
25 if l.len() != length {
26 return Err(InputError::new(input, 0, "expected line length to match"));
27 }
28
29 for (i, c) in l.bytes().enumerate() {
30 frequencies[i][(c - b'a') as usize] += 1;
31 }
32 }
33
34 Ok(Self { frequencies })
35 }
36
37 #[must_use]
38 pub fn part1(&self) -> String {
39 self.decode_message(|c| c)
41 }
42
43 #[must_use]
44 pub fn part2(&self) -> String {
45 self.decode_message(|c| if c == 0 { 0 } else { u32::MAX - c })
48 }
49
50 fn decode_message(&self, count_map_fn: impl Fn(u32) -> u32) -> String {
51 self.frequencies
52 .iter()
53 .map(|counts| {
54 (counts
55 .iter()
56 .enumerate()
57 .rev()
58 .max_by_key(|&(_, &c)| count_map_fn(c))
59 .unwrap()
60 .0 as u8
61 + b'a') as char
62 })
63 .collect()
64 }
65}
66
67examples!(Day06 -> (&'static str, &'static str) [
68 {file: "day06_example0.txt", part1: "easter", part2: "advent"},
69]);