Move manhattan metric function to trait.

This commit is contained in:
2018-12-22 09:40:09 +01:00
parent ba321caa37
commit 3b825ac933
5 changed files with 53 additions and 38 deletions

View File

@@ -1,11 +1,36 @@
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use std::io;
use std::io::Read;
use std::str::FromStr;
use std::ops::Add;
use std::ops::Sub;
use std::fmt::Debug;
use std::str::FromStr;
/// Utility trait for things representing coordinates.
///
/// This is implemented by default for any simple pair-tuple
pub trait Point {
type CoordType;
/// Compute the manhattan distance between this and another.
///
/// The distance will always be >= 0.
fn manhattan(self, other: Self) -> Self::CoordType;
}
impl<T> Point for (T, T)
where T: Add<Output=T> + Sub<Output=T> + Copy + Ord
{
type CoordType = T;
fn manhattan(self, other: Self) -> T {
let (xa, ya) = self;
let (xb, yb) = other;
xa.max(xb) + ya.max(yb) - xa.min(xb) - ya.min(yb)
}
}
/// Apply Erathostenes's sieve to the supplied array
///
@@ -68,16 +93,6 @@ pub fn read_single_input<T>(input: &mut Read) -> T
buf.trim().parse().unwrap()
}
/// Compute the manhattan distance between two points of arbitrary type.
pub fn manhattan_distance<T>(a: (T, T), b: (T, T)) -> T
where T: Copy + Add<Output=T> + Sub<Output=T> + Ord
{
let (xa, ya) = a;
let (xb, yb) = b;
xa.max(xb) + ya.max(yb) - xa.min(xb) - ya.min(yb)
}
/// An interface to count elements in particular categories.
pub trait GroupingCount {
/// The type of the categories under inspection

View File

@@ -4,7 +4,7 @@ use std::io::BufReader;
use std::io::Read;
use common::GroupingCount;
use common::manhattan_distance;
use common::Point;
use common::Solution;
type Coordinate = (usize, usize);
@@ -61,7 +61,7 @@ impl Day06 {
let mut cur_best = None;
for (i, point) in self.points.iter().enumerate() {
let dist = manhattan_distance(*point, (x, y));
let dist = point.manhattan((x, y));
if dist < cur_dist {
cur_dist = dist;
cur_best = Some(i);
@@ -82,7 +82,7 @@ impl Day06 {
self.read_points(input);
self.range()
.map(|x| self.points.iter().map(|y| manhattan_distance(x, *y)).sum::<usize>())
.map(|x| self.points.iter().map(|y| y.manhattan(x)).sum::<usize>())
.filter(|&x| x < limit)
.count()
}

View File

@@ -6,7 +6,7 @@ use std::io::BufRead;
use std::io::BufReader;
use std::io::Read;
use common::manhattan_distance;
use common::Point;
use common::Solution;
type Coordinate = (usize, usize);
@@ -122,7 +122,7 @@ impl Day15 {
let to_attack = self.units.iter()
.enumerate()
.filter(|(_, x)| x.faction != faction && x.is_alive())
.filter(|(_, x)| manhattan_distance(x.pos, initial) == 1)
.filter(|(_, x)| x.pos.manhattan(initial) == 1)
.min_by(|&(_, a), &(_, b)| a.hp.cmp(&b.hp).then(a.pos.cmp(&b.pos)));
if let Some((index, _)) = to_attack {

View File

@@ -5,7 +5,7 @@ use std::io::BufRead;
use std::io::BufReader;
use std::io::Read;
use common::manhattan_distance;
use common::Point;
use common::Solution;
type Coordinate = (usize, usize);
@@ -107,7 +107,7 @@ impl Solution for Day22 {
let mut visited: HashSet<State> = HashSet::new();
let target_state = State { pos: target, climbing: false, torch: true };
todo.push((Reverse(manhattan_distance((0, 0), target)), Reverse(0), State { pos: (0, 0), climbing: false, torch: true }));
todo.push((Reverse((0, 0).manhattan(target)), Reverse(0), State { pos: (0, 0), climbing: false, torch: true }));
while let Some((Reverse(approx), Reverse(dist), state)) = todo.pop() {
if visited.contains(&state) {
@@ -147,7 +147,7 @@ impl Solution for Day22 {
};
if !visited.contains(&new_state) && new_state.is_valid(table[yn][xn]) && (x == xn || y == yn) {
todo.push((Reverse(dist + 1 + manhattan_distance(target, new_state.pos)), Reverse(dist + 1), new_state));
todo.push((Reverse(dist + 1 + target.manhattan(new_state.pos)), Reverse(dist + 1), new_state));
}
}
}