Skip to content

Commit ebf73cf

Browse files
committed
Create astar.rs
1 parent d7ef7da commit ebf73cf

File tree

1 file changed

+150
-0
lines changed

1 file changed

+150
-0
lines changed

packages/solver-r/src/astar.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
use crate::grid::{Point, DIRECTIONS};
2+
use std::cmp::Reverse;
3+
use std::collections::{BinaryHeap, HashMap};
4+
5+
struct Node {
6+
point: Point,
7+
weight: u8,
8+
h: u8,
9+
parent: Option<Point>,
10+
}
11+
12+
impl Eq for Node {}
13+
impl PartialEq for Node {
14+
fn eq(&self, other: &Self) -> bool {
15+
self.parent == other.parent && self.point == other.point
16+
}
17+
}
18+
impl Ord for Node {
19+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
20+
let f1 = self.h + self.weight;
21+
let f2 = other.h + other.weight;
22+
f1.cmp(&f2)
23+
}
24+
}
25+
impl PartialOrd for Node {
26+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
27+
Some(self.cmp(other))
28+
}
29+
}
30+
31+
fn get_heuristic(a: &Point, b: &Point) -> u8 {
32+
(a.x - b.x).abs() as u8 + (a.y - b.y).abs() as u8
33+
}
34+
35+
pub fn get_path<F>(mut walkable: F, start: &Point, end: &Point) -> Option<Vec<Point>>
36+
where
37+
F: FnMut(&Point) -> bool,
38+
{
39+
let mut open_list = BinaryHeap::new();
40+
let mut close_list: HashMap<Point, Node> = HashMap::new();
41+
42+
open_list.push(Reverse(Node {
43+
point: start.clone(),
44+
parent: None,
45+
h: get_heuristic(start, end),
46+
weight: 0,
47+
}));
48+
49+
while let Some(n) = open_list.pop() {
50+
let node = n.0;
51+
52+
for dir in DIRECTIONS {
53+
let point = Point {
54+
x: node.point.x + dir.x,
55+
y: node.point.y + dir.y,
56+
};
57+
58+
if !walkable(&point) {
59+
continue;
60+
}
61+
62+
let weight = node.weight + 1;
63+
let parent = node.point;
64+
65+
if let Some(closed) = close_list.get_mut(&point) {
66+
if weight < closed.weight {
67+
closed.parent = Some(parent);
68+
closed.weight = weight;
69+
}
70+
71+
continue;
72+
}
73+
74+
if &point == end {
75+
let mut path = Vec::new();
76+
let mut e = &node;
77+
78+
path.push(point);
79+
path.push(e.point);
80+
81+
while let Some(p) = e.parent {
82+
e = close_list.get(&p).unwrap();
83+
path.push(e.point);
84+
}
85+
86+
path.reverse();
87+
88+
return Some(path);
89+
}
90+
91+
open_list.push(Reverse(Node {
92+
h: get_heuristic(&point, end),
93+
parent: Some(parent),
94+
point,
95+
weight,
96+
}));
97+
}
98+
99+
close_list.insert(node.point, node);
100+
}
101+
102+
None
103+
}
104+
105+
#[test]
106+
fn it_should_find_path() {
107+
let path = get_path(|_| true, &Point { x: 0, y: 0 }, &Point { x: 5, y: 0 });
108+
109+
assert_eq!(
110+
path,
111+
Some(vec![
112+
//
113+
Point { x: 0, y: 0 },
114+
Point { x: 1, y: 0 },
115+
Point { x: 2, y: 0 },
116+
Point { x: 3, y: 0 },
117+
Point { x: 4, y: 0 },
118+
Point { x: 5, y: 0 },
119+
])
120+
);
121+
}
122+
#[test]
123+
fn it_should_find_path_2() {
124+
let walls = vec![
125+
//
126+
Point { x: 1, y: 0 },
127+
Point { x: 1, y: 1 },
128+
Point { x: 1, y: 2 },
129+
];
130+
let path = get_path(
131+
|p| !walls.contains(p),
132+
&Point { x: 0, y: 0 },
133+
&Point { x: 5, y: 0 },
134+
);
135+
136+
assert_eq!(
137+
path,
138+
Some(vec![
139+
//
140+
Point { x: 0, y: 0 },
141+
Point { x: 0, y: -1 },
142+
Point { x: 1, y: -1 },
143+
Point { x: 2, y: -1 },
144+
Point { x: 2, y: 0 },
145+
Point { x: 3, y: 0 },
146+
Point { x: 4, y: 0 },
147+
Point { x: 5, y: 0 }
148+
])
149+
);
150+
}

0 commit comments

Comments
 (0)