summaryrefslogtreecommitdiff
path: root/src/bin/day9.rs
blob: 685a17872d18c5d47333ee224a51dd6e1ee922e7 (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
use std::collections::{HashMap, HashSet};
use regex::Regex;
use itertools::Itertools;

fn main() {
    let input = advent::read_lines(9);
    println!("9a: {}", shortest_route(&input));
    println!("9b: {}", longest_route(&input));
}

fn parse_routes<T: AsRef<str>>(input: &[T]) -> HashMap<String, HashMap<String, u32>> {
    let re = Regex::new(r"^([A-Za-z]+) to ([A-Za-z]+) = ([0-9]+)$").unwrap();

    let mut routes = HashMap::new();

    for line in input {
        let cap = re.captures(line.as_ref()).unwrap();
        let from = cap[1].to_string();
        let to = cap[2].to_string();
        let distance = cap[3].parse::<u32>().unwrap();

        let entry = routes.entry(from.clone()).or_insert_with(HashMap::new);
        entry.insert(to.clone(), distance);

        let entry = routes.entry(to).or_insert_with(HashMap::new);
        entry.insert(from, distance);
    }

    routes
}

fn distances<T: AsRef<str>>(input: &[T]) -> HashSet<u32> {
    let routes = parse_routes(input);

    let mut distances = HashSet::new();
    for route in routes.keys().permutations(routes.keys().len()) {
        let mut distance = 0;
        let mut prev_city = (*route.first().unwrap()).clone();
        for city in route.iter().skip(1).cloned().cloned() {
            let reachable_from_prev = routes.get(&prev_city).unwrap();
            distance += reachable_from_prev.get(&city).unwrap();
            prev_city = city;
        }
        distances.insert(distance);
    }

    distances
}

fn shortest_route<T: AsRef<str>>(input: &[T]) -> u32 {
    *distances(input).iter().min().unwrap()
}

fn longest_route<T: AsRef<str>>(input: &[T]) -> u32 {
    *distances(input).iter().max().unwrap()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test() {
        let input = [
            "London to Dublin = 464",
            "London to Belfast = 518",
            "Dublin to Belfast = 141",
        ];
        assert_eq!(shortest_route(&input), 605);
        assert_eq!(longest_route(&input), 982);
    }
}