You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
2.8 KiB
115 lines
2.8 KiB
use std::collections::{HashMap, HashSet};
|
|
use std::hash::{Hash, Hasher};
|
|
|
|
use permutohedron::Heap;
|
|
|
|
#[test]
|
|
fn test_day_09() {
|
|
let input = "London to Dublin = 464
|
|
London to Belfast = 518
|
|
Dublin to \
|
|
Belfast = 141";
|
|
let day = Day09::new(input);
|
|
|
|
assert_eq!(464,
|
|
day.distances[&LocationPair(Location("Dublin"),
|
|
Location("London"))]);
|
|
assert_eq!(464,
|
|
day.distances[&LocationPair(Location("London"),
|
|
Location("Dublin"))]);
|
|
|
|
let route = day.route(vec![Location("Dublin"),
|
|
Location("London"),
|
|
Location("Belfast")]);
|
|
assert_eq!(982, route.distance);
|
|
|
|
assert_eq!(6, day.routes().len());
|
|
|
|
assert_eq!(982, solve(input));
|
|
}
|
|
|
|
pub fn solve(input: &str) -> usize {
|
|
let day = Day09::new(input);
|
|
day.routes().iter().map(|r| r.distance).max().unwrap()
|
|
}
|
|
|
|
struct Day09<'a> {
|
|
locations: HashSet<Location<'a>>,
|
|
distances: HashMap<LocationPair<'a>, usize>,
|
|
}
|
|
|
|
impl<'a> Day09<'a> {
|
|
fn new(input: &str) -> Day09 {
|
|
let mut locations = HashSet::new();
|
|
let mut distances = HashMap::new();
|
|
|
|
for line in input.lines() {
|
|
let mut split_eq = line.split(" = ");
|
|
let mut split_to = split_eq.next().unwrap().split(" to ");
|
|
let a = Location(split_to.next().unwrap());
|
|
let b = Location(split_to.last().unwrap());
|
|
let distance = split_eq.last().unwrap().parse::<usize>().unwrap();
|
|
|
|
locations.insert(a);
|
|
locations.insert(b);
|
|
distances.insert(LocationPair(a, b), distance);
|
|
}
|
|
|
|
Day09 {
|
|
locations: locations,
|
|
distances: distances,
|
|
}
|
|
}
|
|
|
|
fn routes(&self) -> Vec<Route> {
|
|
let mut locations = self.locations
|
|
.iter()
|
|
.cloned()
|
|
.collect::<Vec<Location>>();
|
|
let heap = Heap::new(&mut locations);
|
|
heap.map(|p| self.route(p)).collect()
|
|
}
|
|
|
|
fn route(&self, locations: Vec<Location<'a>>) -> Route {
|
|
let distance = locations.windows(2)
|
|
.map(|w| self.distances[&LocationPair(w[0], w[1])])
|
|
.fold(0, |sum, dist| sum + dist);
|
|
Route {
|
|
locations: locations,
|
|
distance: distance,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct Route<'a> {
|
|
locations: Vec<Location<'a>>,
|
|
distance: usize,
|
|
}
|
|
|
|
#[derive(Clone,Copy,Debug,Eq,Hash,PartialEq,PartialOrd,Ord)]
|
|
struct Location<'a>(&'a str);
|
|
|
|
#[derive(Debug,Eq)]
|
|
struct LocationPair<'a>(Location<'a>, Location<'a>);
|
|
|
|
impl<'a> PartialEq for LocationPair<'a> {
|
|
fn eq(&self, other: &LocationPair) -> bool {
|
|
let mut a = vec![&self.0, &self.1];
|
|
a.sort();
|
|
|
|
let mut b = vec![&other.0, &other.1];
|
|
b.sort();
|
|
|
|
a == b
|
|
}
|
|
}
|
|
|
|
impl<'a> Hash for LocationPair<'a> {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
let mut locations = vec![&self.0, &self.1];
|
|
locations.sort();
|
|
locations.hash(state);
|
|
}
|
|
}
|