advent_of_code/year2016/
day04.rs1use crate::input::Input;
2
3pub fn solve(input: &Input) -> Result<u32, String> {
4 const NUM_ASCII_LOWERCASE: usize = 26;
5
6 let mut sector_ids_sum = 0;
7
8 for (line_idx, line) in input.text.lines().enumerate() {
9 let on_error = || format!("Line {}: Invalid input", line_idx + 1);
10
11 let (room_name, sector_id_and_checksum) = line.rsplit_once('-').ok_or_else(on_error)?;
12
13 let (sector_id, stated_checksum) = sector_id_and_checksum
14 .split_once('[')
15 .and_then(|(id, checksum_str)| {
16 let checksum: usize =
17 checksum_str
18 .bytes()
19 .take(5)
20 .enumerate()
21 .try_fold(0, |acc, (idx, b)| {
22 b.is_ascii_lowercase()
23 .then_some(acc * idx * NUM_ASCII_LOWERCASE + (b - b'a') as usize)
24 })?;
25
26 Some((id.parse::<u32>().ok()?, checksum))
27 })
28 .ok_or_else(on_error)?;
29
30 if input.is_part_one() {
31 let mut char_frequency: [(u8, u32); NUM_ASCII_LOWERCASE] =
32 std::array::from_fn(|i| (i as u8, 0));
33 for c in room_name.bytes().filter(u8::is_ascii_lowercase) {
34 char_frequency[(c - b'a') as usize].1 += 1;
35 }
36
37 char_frequency.sort_unstable_by(|(c1, f1), (c2, f2)| f2.cmp(f1).then(c1.cmp(c2)));
38
39 let computed_checksum = char_frequency
40 .iter()
41 .take(5)
42 .enumerate()
43 .fold(0, |acc, (idx, (c, _f))| {
44 acc * idx * NUM_ASCII_LOWERCASE + *c as usize
45 });
46
47 if computed_checksum == stated_checksum {
48 sector_ids_sum += sector_id;
49 }
50 } else {
51 let desired_name = b"northpole object storage".iter();
52 if room_name
53 .bytes()
54 .map(|a| match a {
55 b'-' => b' ',
56 _ if a.is_ascii_lowercase() => {
57 ((u32::from(a) - 'a' as u32 + sector_id) % (NUM_ASCII_LOWERCASE as u32))
58 as u8
59 + b'a'
60 }
61 _ => u8::MAX,
62 })
63 .zip(desired_name)
64 .all(|(a, &b)| a == b)
65 {
66 return Ok(sector_id);
67 }
68 }
69 }
70
71 Ok(sector_ids_sum)
72}
73
74#[test]
75pub fn tests() {
76 use crate::input::{test_part_one_no_allocations, test_part_two_no_allocations};
77
78 let real_input = include_str!("day04_input.txt");
79
80 test_part_one_no_allocations!(real_input => 245_102);
81 test_part_two_no_allocations!(real_input => 324);
82}