Files
adventofcode/2016/04/src/main.rs
2016-12-04 18:31:07 +01:00

166 lines
4.0 KiB
Rust

#[macro_use] extern crate lazy_static;
extern crate regex;
use std::collections::HashMap;
use std::str::FromStr;
use std::io::{self, BufRead};
use regex::Regex;
#[derive(Debug, PartialEq)]
pub struct Room {
enc_name: String,
sector_id: u32,
checksum: Vec<char>
}
impl Room {
pub fn encoded_name(&self) -> &str {
self.enc_name.as_str()
}
pub fn decoded_name(&self) -> String {
self.enc_name.chars()
.map(|x| {
if x == '-' {
' '
} else {
((((x as u32 - 97 + self.sector_id()) % 26) + 97) as u8) as char
}
})
.collect::<String>()
}
pub fn sector_id(&self) -> u32 {
self.sector_id
}
pub fn checksum(&self) -> &Vec<char> {
&self.checksum
}
pub fn calculate_checksum(&self) -> Vec<char> {
let map = self.enc_name.chars()
.filter(|x| *x != '-')
.fold(HashMap::new(), |mut map, x| {
*map.entry(x).or_insert(0) += 1;
map
});
let mut vec: Vec<_> = map.iter().collect();
vec.sort_by(|a, b| if a.1 != b.1 { b.1.cmp(a.1) } else { a.0.cmp(b.0) });
vec.iter().take(5).map(|x| *x.0).collect::<Vec<_>>()
}
pub fn verify(&self) -> bool {
*self.checksum() == self.calculate_checksum()
}
}
impl FromStr for Room {
type Err = ();
fn from_str(s: &str) -> Result<Room, ()> {
lazy_static! {
static ref RE: Regex = Regex::new(r"^(.*)-(\d+)\[([a-z]+)\]$").unwrap();
}
if let Some(caps) = RE.captures(s) {
let enc_name = String::from(caps.at(1).unwrap());
let sector_id = caps.at(2).unwrap().parse::<u32>().unwrap();
let checksum = caps.at(3).unwrap().chars().collect::<Vec<_>>();
return Ok(Room {
enc_name: enc_name,
sector_id: sector_id,
checksum: checksum
});
}
Err(())
}
}
fn main() {
let stdin = io::stdin();
let input = stdin.lock().lines()
.filter_map(|x| x.ok())
.filter_map(|x| Room::from_str(&x).ok())
.filter(|x| x.verify())
.collect::<Vec<_>>();
let count: i64 = input.iter()
.map(|x| x.sector_id() as i64)
.sum();
for room in input {
println!("{}: {}", room.sector_id(), room.decoded_name());
}
println!("count={}", count);
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn example_01() {
let room = Room::from_str("aaaaa-bbb-z-y-x-123[abxyz]").unwrap();
assert_eq!("aaaaa-bbb-z-y-x", room.encoded_name());
assert_eq!(123, room.sector_id());
assert_eq!(&vec!['a', 'b', 'x', 'y', 'z'], room.checksum());
assert_eq!(true, room.verify());
}
#[test]
fn example_02() {
let room = Room::from_str("a-b-c-d-e-f-g-h-987[abcde]").unwrap();
assert_eq!("a-b-c-d-e-f-g-h", room.encoded_name());
assert_eq!(987, room.sector_id());
assert_eq!(&vec!['a', 'b', 'c', 'd', 'e'], room.checksum());
assert_eq!(true, room.verify());
}
#[test]
fn example_03() {
let room = Room::from_str("not-a-real-room-404[oarel]").unwrap();
assert_eq!("not-a-real-room", room.encoded_name());
assert_eq!(404, room.sector_id());
assert_eq!(&vec!['o', 'a', 'r', 'e', 'l'], room.checksum());
assert_eq!(true, room.verify());
}
#[test]
fn example_04() {
let room = Room::from_str("totally-real-room-200[decoy]").unwrap();
assert_eq!("totally-real-room", room.encoded_name());
assert_eq!(200, room.sector_id());
assert_eq!(&vec!['d', 'e', 'c', 'o', 'y'], room.checksum());
assert_eq!(false, room.verify());
}
#[test]
fn example_05() {
let room = Room::from_str("qzmt-zixmtkozy-ivhz-343[decoy]").unwrap();
assert_eq!(String::from("very encrypted name"), room.decoded_name());
}
}