summaryrefslogtreecommitdiff
path: root/2016/aoc4/src/main.rs
blob: ea1edd8254874c198a4f51802975d7f91e87d0be (plain)
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
use std::io::BufReader;
use std::io::prelude::*;
use std::fs::File;
use std::collections::BTreeMap;

#[derive(Debug)]
struct Room {
    encrypted_name: String,
    sector_id: u32,
    checksum: String
}

impl Room {
    fn new(line: String) -> Room {
        let name_length = line.find(char::is_numeric).unwrap();
        let (name, sector_and_check) = line.split_at(name_length);
        let (sector, check) = sector_and_check.split_at(sector_and_check.len()-7);
        
        Room {
            encrypted_name: name.trim_matches('-').to_string(),
            sector_id: sector.parse().unwrap(),
            checksum: check.trim_matches(|c| c=='[' || c==']').to_string()
        }
    }

    fn is_valid(&self) -> bool {
        let mut char_counts: BTreeMap<char, i32> = BTreeMap::new();
        let chars = self.encrypted_name.chars()
            .filter(|&c| c != '-');
        for c in chars {
            *char_counts.entry(c).or_insert(0) += 1;
        }

        let mut vec_char_counts = char_counts.iter().collect::<Vec<_>>();
        vec_char_counts.sort_by_key(|&(_, &value)| -value);
        let expected_checksum = vec_char_counts
            .iter()
            .take(5)
            .map(|&(&key, _)| key)
            .collect::<String>();

        expected_checksum == self.checksum
    }

    fn decrypt_name(&self) -> String {
        self.encrypted_name.chars().map(|c| {
            if c == '-' {
                ' '
            } else {
                let current_digit = c as u8 - 'a' as u8;
                let new_digit = ((current_digit as u32 + self.sector_id) % 26) as u8;
                (new_digit + 'a' as u8) as char
            }
        }).collect()
    }
}

fn main() {
    let rooms = read_file();
    let valid_rooms = rooms.iter()
        .filter(|r| r.is_valid())
        .collect::<Vec<_>>();
    let sector_sum: u32 = valid_rooms.iter()
        .map(|r| r.sector_id)
        .sum();

    println!("Sector sum {}", sector_sum);

    let north_poles = rooms.iter()
        .filter(|r| r.decrypt_name().contains("north"))
        .inspect(|r| println!("{} {}", r.decrypt_name(), r.sector_id))
        .collect::<Vec<_>>();
    println!("{:?}", north_poles);
}

fn read_file() -> Vec<Room> {
    let file = BufReader::new(File::open("input.txt").unwrap());
    file.lines()
        .map(|line| line.unwrap().trim().to_string())
        .filter(|line| line.len() > 0)
        .map(Room::new)
        .collect()
}