-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday4.rs
148 lines (118 loc) · 4.11 KB
/
day4.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//! [Day 4: Security Through Obscurity](https://adventofcode.com/2016/day/4)
use lazy_static::lazy_static;
use regex::Regex;
use rustc_hash::FxHashMap;
use std::convert::TryFrom;
lazy_static! {
/// Regex that matches a line of input
static ref RE_INPUT: Regex = Regex::new(r"([\w-]+)\-(\d+)\[(\w+)\]").unwrap();
}
pub fn main() {
let args = aoc::parse_args();
args.run(solve);
}
/// # Panics
#[must_use]
pub fn solve(data: &str) -> (u32, u32) {
(part1(data), part2(data))
}
/// ``part1`` returns the sum of sector id of valid rooms.
fn part1(data: &str) -> u32 {
let mut sum = 0;
for line in data.lines() {
let (name, checksum, sector_id) = extract(line);
if is_real_room(&name, &checksum) {
sum += sector_id;
}
}
sum
}
/// ``part2`` returns the sector id of the room with name ``northpole object``.
/// if no such room is found, returns ``0``.
fn part2(data: &str) -> u32 {
for line in data.lines() {
let (name, _, sector_id) = extract(line);
// Nota: the full decrypted name of the room is "northpole object storage"
// and there is only one room with that name.
if decrypt(&name, sector_id).contains("northpole object") {
return sector_id;
}
}
0
}
/// ``decrypt`` decrypts the name of a room given the sector id with the Caesar cipher.
fn decrypt(name: &str, sector_id: u32) -> String {
let mut decrypted_name = String::new();
for c in name.chars() {
if c == '-' {
decrypted_name.push(' ');
} else {
let c = (c as u32 - 'a' as u32 + sector_id) % 26 + 'a' as u32;
decrypted_name.push(char::try_from(c).unwrap());
}
}
decrypted_name
}
/// ``extract`` extracts the name, checksum and sector id from a line of data.
fn extract(line: &str) -> (String, String, u32) {
let caps = RE_INPUT.captures(line).unwrap();
let name = caps.get(1).unwrap().as_str().to_string();
let sector_id = caps.get(2).unwrap().as_str().parse::<u32>().unwrap();
let checksum = caps.get(3).unwrap().as_str().to_string();
(name, checksum, sector_id)
}
/// ``is_real_room`` checks if the room is real by comparing the checksum.
fn is_real_room(name: &str, checksum: &str) -> bool {
let mut freqs = FxHashMap::<char, i32>::default();
for c in name.chars() {
if c.is_ascii_lowercase() {
*freqs.entry(c).or_default() += 1;
}
}
let mut freqs = freqs.iter().map(|(c, n)| (-n, c)).collect::<Vec<_>>();
freqs.sort_unstable();
let check = freqs.iter().take(5).map(|(_, &c)| c).collect::<String>();
check == checksum
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_extract() {
let (name, checksum, sector_id) = extract("aaaaa-bbb-z-y-x-123[abxyz]");
assert_eq!(name, "aaaaa-bbb-z-y-x");
assert_eq!(checksum, "abxyz");
assert_eq!(sector_id, 123);
let (name, checksum, sector_id) = extract("a-b-c-d-e-f-g-h-987[abcde]");
assert_eq!(name, "a-b-c-d-e-f-g-h");
assert_eq!(checksum, "abcde");
assert_eq!(sector_id, 987);
let (name, checksum, sector_id) = extract("not-a-real-room-404[oarel]");
assert_eq!(name, "not-a-real-room");
assert_eq!(checksum, "oarel");
assert_eq!(sector_id, 404);
let (name, checksum, sector_id) = extract("totally-real-room-200[decoy]");
assert_eq!(name, "totally-real-room");
assert_eq!(checksum, "decoy");
assert_eq!(sector_id, 200);
}
#[test]
fn test_is_real_room() {
assert!(is_real_room("aaaaa-bbb-z-y-x", "abxyz"));
assert!(is_real_room("a-b-c-d-e-f-g-h", "abcde"));
assert!(is_real_room("not-a-real-room", "oarel"));
assert!(!is_real_room("totally-real-room", "decoy"));
}
#[test]
fn test_part1() {
let data = "aaaaa-bbb-z-y-x-123[abxyz]
a-b-c-d-e-f-g-h-987[abcde]
not-a-real-room-404[oarel]
totally-real-room-200[decoy]";
assert_eq!(part1(data), 1514);
}
#[test]
fn test_decrypt() {
assert_eq!(decrypt("qzmt-zixmtkozy-ivhz", 343), "very encrypted name");
}
}