y2016d4
This commit is contained in:
119
y2016/src/days/d4.rs
Normal file
119
y2016/src/days/d4.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn process_part1(input: &str) -> u32 {
|
||||
input
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let name = get_name(line);
|
||||
let id = get_id(line);
|
||||
let checksum = get_checksum(line);
|
||||
let stats = get_freq_and_position(&name);
|
||||
let mut sorted_stats = stats.into_iter().collect::<Vec<(char, i32)>>();
|
||||
sorted_stats.sort_by(|(a, a_freq), (b, b_freq)| match b_freq.cmp(a_freq) {
|
||||
std::cmp::Ordering::Less => std::cmp::Ordering::Less,
|
||||
std::cmp::Ordering::Greater => std::cmp::Ordering::Greater,
|
||||
std::cmp::Ordering::Equal => a.cmp(b),
|
||||
});
|
||||
for (char, _stats) in sorted_stats.into_iter().take(5) {
|
||||
if !checksum.contains(char) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
id
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
||||
pub fn process_part2(input: &str) -> String {
|
||||
input
|
||||
.lines()
|
||||
.filter(|line| {
|
||||
let name = get_name(line);
|
||||
let checksum = get_checksum(line);
|
||||
let stats = get_freq_and_position(&name);
|
||||
let mut sorted_stats = stats.into_iter().collect::<Vec<(char, i32)>>();
|
||||
sorted_stats.sort_by(|(a, a_freq), (b, b_freq)| match b_freq.cmp(a_freq) {
|
||||
std::cmp::Ordering::Less => std::cmp::Ordering::Less,
|
||||
std::cmp::Ordering::Greater => std::cmp::Ordering::Greater,
|
||||
std::cmp::Ordering::Equal => a.cmp(b),
|
||||
});
|
||||
for (char, _stats) in sorted_stats.into_iter().take(5) {
|
||||
if !checksum.contains(char) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
})
|
||||
.map(|line| {
|
||||
let name = get_name(line);
|
||||
let id = get_id(line);
|
||||
format!("{}: {id}", rot(&name, id))
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
fn rot(name: &str, count: u32) -> String {
|
||||
let mut decrypted = Vec::new();
|
||||
for &byte in name.as_bytes() {
|
||||
if byte == b'-' {
|
||||
decrypted.push(b' ');
|
||||
continue;
|
||||
}
|
||||
let shift = (byte - b'a') as u32 + count;
|
||||
decrypted.push((shift % 26) as u8 + b'a');
|
||||
}
|
||||
String::from_utf8(decrypted).unwrap()
|
||||
}
|
||||
|
||||
fn get_name(room: &str) -> String {
|
||||
room.rsplit_once("-").unwrap().0.to_string()
|
||||
}
|
||||
|
||||
fn get_id(room: &str) -> u32 {
|
||||
let id_start = room.rfind("-").unwrap() + 1;
|
||||
let id_end = room.find("[").unwrap();
|
||||
room[id_start..id_end].parse().unwrap()
|
||||
}
|
||||
|
||||
fn get_checksum(room: &str) -> String {
|
||||
let id_start = room.find("[").unwrap() + 1;
|
||||
room[id_start..room.len() - 1].to_string()
|
||||
}
|
||||
|
||||
fn get_freq_and_position(name: &str) -> HashMap<char, i32> {
|
||||
let mut freq = HashMap::new();
|
||||
for char in name.chars() {
|
||||
if char == '-' {
|
||||
continue;
|
||||
}
|
||||
freq.entry(char)
|
||||
.and_modify(|count| {
|
||||
*count += 1;
|
||||
})
|
||||
.or_insert(1);
|
||||
}
|
||||
freq
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{rot, *};
|
||||
|
||||
const INPUT: &str = "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]";
|
||||
|
||||
#[test]
|
||||
fn part1() {
|
||||
let result = process_part1(INPUT);
|
||||
assert_eq!(result, 1514);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2() {
|
||||
let res = rot("qzmt-zixmtkozy-ivhz", 343);
|
||||
assert_eq!(res, "very encrypted name".to_string());
|
||||
}
|
||||
}
|
||||
@@ -3,3 +3,5 @@ pub mod d1;
|
||||
pub mod d2;
|
||||
|
||||
pub mod d3;
|
||||
|
||||
pub mod d4;
|
||||
|
||||
Reference in New Issue
Block a user