-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.rs
110 lines (96 loc) · 2.59 KB
/
main.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
#![warn(clippy::all, clippy::pedantic, clippy::nursery)]
use itertools::Itertools;
pub fn main() {
let data = include_str!("input.txt");
println!("Part 1: {}", part_one(data));
println!("Part 2: {}", part_two(data, "northpole object storage"));
}
fn part_one(data: &'static str) -> u32 {
data.lines()
.map(Room::new)
.filter(Room::real)
.map(|r| r.sector_id)
.sum()
}
fn part_two(data: &'static str, check: &str) -> u32 {
let room = data
.lines()
.map(Room::new)
.filter(Room::real)
.find(|r| r.decrypted_equals(check))
.unwrap();
room.sector_id
}
struct Room {
encrypted_name: &'static str,
sector_id: u32,
checksum: &'static str,
}
impl Room {
fn new(line: &'static str) -> Self {
let (body, checksum) = line.split_once('[').unwrap();
let checksum = checksum.trim_end_matches(']');
let (encrypted_name, sector_id) = body.rsplit_once('-').unwrap();
let sector_id = sector_id.parse().unwrap();
Self {
encrypted_name,
sector_id,
checksum,
}
}
fn real(&self) -> bool {
self.encrypted_name
.chars()
.filter(|&c| c != '-')
.sorted_unstable()
.dedup_with_count()
.sorted_unstable_by_key(|&(c, _)| std::cmp::Reverse(c))
.take(5)
.map(|(_, ch)| ch)
.collect::<String>()
== self.checksum
}
fn decrypted_equals(&self, check: &str) -> bool {
if self.encrypted_name.len() != check.len() {
return false;
}
let shift = u8::try_from(self.sector_id % 26).unwrap();
let limit = b'z' - shift;
for (this, test) in self
.encrypted_name
.as_bytes()
.iter()
.zip(check.as_bytes().iter())
{
if this == &b'-' && test == &b' ' {
continue;
}
let shifted = if this > &limit {
this - 26 + shift
} else {
this + shift
};
if shifted != *test {
return false;
}
}
true
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn one() {
let data = include_str!("test.txt");
assert_eq!(1514, part_one(data));
assert_eq!(343, part_one("qzmt-zixmtkozy-ivhz-343[zimth]"));
}
#[test]
fn two() {
assert_eq!(
343,
part_two("qzmt-zixmtkozy-ivhz-343[zimth]", "very encrypted name")
);
}
}