[2018][rust][15.1] should probably start committing...

sorbet
Alpha Chen 6 years ago
parent c911c4d72a
commit cbe51dc6e1

@ -0,0 +1,263 @@
use std::cmp::Ordering;
use std::collections::{BinaryHeap, HashMap, HashSet};
use std::error::Error;
use std::str::FromStr;
use advent_of_code::main;
main!();
fn solve(input: &str) -> Result<String, Box<Error>> {
unimplemented!();
}
struct Combat {
map: Map,
}
impl Combat {}
struct Map {
walls: HashSet<Square>,
units: HashMap<Square, Unit>,
}
impl Map {
fn is_open(&self, square: &Square) -> bool {
!self.walls.contains(&square) && !self.units.contains_key(&square)
}
fn open_neighbors(&self, square: &Square) -> HashSet<Square> {
square
.neighbors()
.iter()
.filter(|x| self.is_open(x))
.map(|&x| x)
.collect()
}
fn distances(&self, from: &Square) -> HashMap<Square, usize> {
#[derive(Eq, PartialEq)]
struct State {
distance: usize,
square: Square,
}
impl Ord for State {
fn cmp(&self, other: &Self) -> Ordering {
other.distance.cmp(&self.distance)
}
}
impl PartialOrd for State {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
let mut distances = HashMap::new();
let mut queue = BinaryHeap::new();
queue.push(State{distance: 0, square: *from});
while let Some(State {distance, square}) = queue.pop() {
distances.entry(square).or_insert(distance);
self
.open_neighbors(&square)
.iter()
.filter(|x| !distances.contains_key(x))
.map(|&x| State {
distance: distance + 1,
square: x,
})
.for_each(|x| queue.push(x));
}
distances
}
}
impl FromStr for Map {
type Err = Box<Error>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut walls = HashSet::new();
let mut units = HashMap::new();
s.trim()
.lines()
.enumerate()
.flat_map(|(y, line)| {
line.chars()
.enumerate()
.map(move |(x, c)| (Square((y, x)), c))
})
.for_each(|(square, c)| {
match c {
'#' => {
walls.insert(square);
}
'G' => {
units.insert(square, Unit::new(Race::Goblin));
}
'E' => {
units.insert(square, Unit::new(Race::Elf));
}
'.' => {}
_ => panic!(),
};
});
Ok(Self { walls, units })
}
}
#[test]
fn test_map_distances() {
let map: Map = r"
#######
#E..G.#
#...#.#
#.G.#G#
#######
"
.parse()
.unwrap();
let distances = map.distances(&Square((1, 1)));
assert!(!distances.contains_key(&Square((0, 0))));
assert!(!distances.contains_key(&Square((1, 4))));
assert!(!distances.contains_key(&Square((1, 5))));
assert_eq!(distances.get(&Square((2, 2))).unwrap(), &2);
assert_eq!(distances.get(&Square((1, 3))).unwrap(), &2);
assert_eq!(distances.get(&Square((3, 3))).unwrap(), &4);
}
#[test]
fn test_map_from_str() {
let input = r"
#######
#.G.E.#
#E.G.E#
#.G.E.#
#######
";
let map: Map = input.parse().unwrap();
assert!(map.walls.contains(&Square((0, 0))));
assert!(!map.walls.contains(&Square((1, 1))));
assert_eq!(map.units.get(&Square((1, 2))).unwrap().race, Race::Goblin);
assert_eq!(map.units.get(&Square((1, 4))).unwrap().race, Race::Elf);
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct Square((usize, usize));
impl Square {
fn neighbors(&self) -> HashSet<Self> {
let (y, x) = self.0;
let mut set = HashSet::new();
set.insert(Square((y - 1, x)));
set.insert(Square((y + 1, x)));
set.insert(Square((y, x - 1)));
set.insert(Square((y, x + 1)));
set
}
}
impl Ord for Square {
fn cmp(&self, other: &Self) -> Ordering {
self.0.cmp(&other.0)
}
}
impl PartialOrd for Square {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[test]
fn test_square_ord() {
let mut squares: Vec<Square> = vec![(1, 2), (1, 4), (2, 1), (2, 3), (2, 5), (3, 2), (3, 4)]
.iter()
.map(|&x| Square(x))
.collect();
squares.sort();
assert_eq!(
squares.iter().map(|x| x.0).collect::<Vec<_>>(),
vec![(1, 2), (1, 4), (2, 1), (2, 3), (2, 5), (3, 2), (3, 4)]
);
}
struct Unit {
race: Race,
hp: usize,
}
impl Unit {
fn new(race: Race) -> Self {
let hp = 200;
Unit { race, hp }
}
fn targets(&self, map: &Map) -> HashSet<Square> {
map.units
.iter()
.filter(|(_, x)| x.race == self.race.enemy())
.map(|(&x, _)| x)
.collect()
}
fn in_range(&self, map: &Map) -> HashSet<Square> {
self.targets(&map)
.iter()
.flat_map(|x| map.open_neighbors(x))
.collect()
}
}
#[test]
fn test_unit_targets() {
let map: Map = r"
#######
#E..G.#
#...#.#
#.G.#G#
#######
"
.parse()
.unwrap();
let square = Square((1, 1));
let unit = map.units.get(&square).unwrap();
let targets = unit.targets(&map);
assert_eq!(targets.len(), 3);
assert!(vec![(1, 4), (3, 2), (3, 5)]
.iter()
.map(|&x| Square(x))
.all(|x| targets.contains(&x)));
let in_range = unit.in_range(&map);
assert_eq!(in_range.len(), 6);
assert!(vec![(1, 3), (1, 5), (2, 2), (2, 5), (3, 1), (3, 3)]
.iter()
.map(|&x| Square(x))
.all(|x| in_range.contains(&x)));
}
#[derive(Debug, Eq, PartialEq)]
enum Race {
Elf,
Goblin,
}
impl Race {
fn enemy(&self) -> Race {
match self {
Race::Elf => Race::Goblin,
Race::Goblin => Race::Elf,
}
}
}
Loading…
Cancel
Save