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