|
|
|
@ -1,3 +1,5 @@ |
|
|
|
|
use crate::lib::screen::Screen; |
|
|
|
|
use crate::lib::world::World; |
|
|
|
|
use std::collections::{HashMap, HashSet}; |
|
|
|
|
|
|
|
|
|
#[derive(Hash, PartialEq, Eq, Clone, Debug, Copy)] |
|
|
|
@ -5,42 +7,32 @@ pub struct Point(pub i32, pub i32); |
|
|
|
|
|
|
|
|
|
impl Point { |
|
|
|
|
pub fn get_neighbors(&self) -> Vec<Point> { |
|
|
|
|
vec![ |
|
|
|
|
self.left(), |
|
|
|
|
self.right(), |
|
|
|
|
self.up(), |
|
|
|
|
self.down() |
|
|
|
|
] |
|
|
|
|
vec![self.left(), self.right(), self.up(), self.down()] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn is_above(&self, other: &Point) -> bool { |
|
|
|
|
other.up() == *self |
|
|
|
|
pub fn left(&self) -> Point { |
|
|
|
|
Point(self.0 - 1, self.1) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn is_below(&self, other: &Point) -> bool { |
|
|
|
|
other.down() == *self |
|
|
|
|
pub fn right(&self) -> Point { |
|
|
|
|
Point(self.0 + 1, self.1) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn is_left(&self, other: &Point) -> bool { |
|
|
|
|
other.left() == *self |
|
|
|
|
pub fn uldiag(&self) -> Point { |
|
|
|
|
Point(self.0 - 1, self.1 - 1) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn is_right(&self, other:&Point) -> bool { |
|
|
|
|
other.right() == *self |
|
|
|
|
pub fn bldiag(&self) -> Point { |
|
|
|
|
Point(self.0 + 1, self.1 - 1) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn is_adjacent(&self, other: &Point) -> bool { |
|
|
|
|
other.is_left(self) || other.is_right(self) |
|
|
|
|
pub fn brdiag(&self) -> Point { |
|
|
|
|
Point(self.0 + 1, self.1 + 1) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn left(&self) -> Point { |
|
|
|
|
Point(self.0 - 1, self.1) |
|
|
|
|
pub fn urdiag(&self) -> Point { |
|
|
|
|
Point(self.0 - 1, self.1 + 1) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn right(&self) -> Point { |
|
|
|
|
Point(self.0 + 1, self.1) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// y values are reversed in ncurses
|
|
|
|
|
pub fn down(&self) -> Point { |
|
|
|
|
Point(self.0, self.1 + 1) |
|
|
|
@ -55,8 +47,18 @@ fn manhattan(c1: &Point, c2: &Point) -> i32 { |
|
|
|
|
return (c2.0 - c1.0).abs() + (c2.1 - c1.1).abs(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn astar(start: &Point, goal: &Point) -> Vec<Point> { |
|
|
|
|
let mut open_set : HashSet<Point> = HashSet::new(); |
|
|
|
|
fn weigh_point(w: &World, p: &Point) -> i32 { |
|
|
|
|
if w.is_cleared(p) { |
|
|
|
|
3 |
|
|
|
|
} else { |
|
|
|
|
15 |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub struct PathNotFoundError; |
|
|
|
|
|
|
|
|
|
pub fn astar(start: &Point, goal: &Point, w: Option<&World>, s: Option<&Screen>) -> Result<Vec<Point>, PathNotFoundError> { |
|
|
|
|
let mut open_set: HashSet<Point> = HashSet::new(); |
|
|
|
|
open_set.insert(*start); |
|
|
|
|
|
|
|
|
|
let mut came_from: HashMap<Point, Point> = HashMap::new(); |
|
|
|
@ -86,21 +88,37 @@ pub fn astar(start: &Point, goal: &Point) -> Vec<Point> { |
|
|
|
|
answer.push(current.clone()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
return Ok(answer); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
open_set.remove(¤t); |
|
|
|
|
|
|
|
|
|
let current_gscore = gscore[¤t]; |
|
|
|
|
|
|
|
|
|
let all_neighbors: Vec<Point> = current.get_neighbors(); |
|
|
|
|
let all_neighbors: Vec<Point> = match w { |
|
|
|
|
Some(w) => current |
|
|
|
|
.get_neighbors() |
|
|
|
|
.iter() |
|
|
|
|
.filter(|p| w.is_valid_movement(p, s.unwrap())) |
|
|
|
|
.map(|e| e.clone()) |
|
|
|
|
.collect(), |
|
|
|
|
None => current.get_neighbors(), |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
for neighbor in all_neighbors.iter() { |
|
|
|
|
let neighbor_score = if gscore.contains_key(&neighbor) { |
|
|
|
|
gscore[neighbor] |
|
|
|
|
gscore[&neighbor] |
|
|
|
|
} else { |
|
|
|
|
i32::MAX |
|
|
|
|
}; |
|
|
|
|
let score = current_gscore + 1; |
|
|
|
|
|
|
|
|
|
let weight = match w { |
|
|
|
|
Some(w) => weigh_point(&w, neighbor), |
|
|
|
|
None => 1, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let score = current_gscore + weight; |
|
|
|
|
|
|
|
|
|
if score < neighbor_score { |
|
|
|
|
gscore.insert(neighbor.clone(), score); |
|
|
|
|
fscore.insert(neighbor.clone(), score + manhattan(&neighbor, &goal)); |
|
|
|
@ -110,7 +128,7 @@ pub fn astar(start: &Point, goal: &Point) -> Vec<Point> { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
answer |
|
|
|
|
Err(PathNotFoundError) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
@ -118,9 +136,18 @@ fn test_astar() { |
|
|
|
|
let start = Point(0, 0); |
|
|
|
|
|
|
|
|
|
let goal = Point(10, 10); |
|
|
|
|
let answers: Vec<Point> = astar(&start, &goal); |
|
|
|
|
let answers = astar(&start, &goal, None, None); |
|
|
|
|
|
|
|
|
|
for a in answers.iter() { |
|
|
|
|
match answers { |
|
|
|
|
Ok(ans) => { |
|
|
|
|
for a in ans.iter() { |
|
|
|
|
println!("{:?}", &a); |
|
|
|
|
}
|
|
|
|
|
}, |
|
|
|
|
Err(_) => { |
|
|
|
|
panic!("Path not found. That shouldn't happen!") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|