rustpather/
lib.rs

1use std::collections::HashSet;
2use std::collections::HashMap;
3
4#[derive(Clone, Debug)]
5struct Edge<T> {
6	cost : i64,
7	end : T
8}
9
10pub type Graph<T> = HashMap<T, Vec<Edge<T>>>;
11
12pub type Node = (i64, i64);
13
14pub fn to_fourway(grid : &Vec<Vec<u32>>) -> Graph<Node> {
15	let mut graph : HashMap<(i64, i64), i64> = HashMap::new();
16
17	for (y, row) in grid.iter().enumerate() {
18		for (x, point) in row.iter().enumerate() {
19			if *point > 0 {
20				graph.insert((x as i64, y as i64), *point as i64);
21			}
22		}
23	}
24
25	let mut fullgraph : Graph<Node> = HashMap::new();
26	for (point, _) in graph.iter() {
27		let mut peers : Vec<Edge<Node>> = Vec::new();
28
29		if graph.contains_key(&(point.0 - 1, point.1)) {
30			peers.push(Edge{
31				cost : graph[&(point.0 - 1, point.1)],
32				end : (point.0 - 1, point.1)
33			});
34		}
35		if graph.contains_key(&(point.0 + 1, point.1)) {
36			peers.push(Edge{
37				cost : graph[&(point.0 + 1, point.1)],
38				end : (point.0 + 1, point.1)
39			});
40		}
41		if graph.contains_key(&(point.0, point.1-1)) {
42			peers.push(Edge{
43				cost : graph[&(point.0, point.1 - 1)],
44				end : (point.0, point.1 - 1)
45			});
46		}
47		if graph.contains_key(&(point.0, point.1+1)) {
48			peers.push(Edge{
49				cost : graph[&(point.0, point.1 + 1)],
50				end : (point.0, point.1 + 1)
51			});
52		}
53		fullgraph.insert(*point, peers);
54	}
55
56	fullgraph
57}
58
59pub fn to_eightway(grid : &Vec<Vec<u32>>) -> Graph<Node> {
60	let mut graph : HashMap<(i64, i64), i64> = HashMap::new();
61
62	for (y, row) in grid.iter().enumerate() {
63		for (x, point) in row.iter().enumerate() {
64			if *point > 0 {
65				graph.insert((x as i64, y as i64), *point as i64);
66			}
67		}
68	}
69
70	let mut fullgraph : Graph<Node> = HashMap::new();
71	for (point, _) in graph.iter() {
72		let mut peers : Vec<Edge<Node>> = Vec::new();
73
74		if graph.contains_key(&(point.0 - 1, point.1)) {
75			peers.push(Edge{
76				cost : graph[&(point.0 - 1, point.1)],
77				end : (point.0 - 1, point.1)
78			});
79		}
80		if graph.contains_key(&(point.0 - 1, point.1 - 1)) {
81			peers.push(Edge{
82				cost : graph[&(point.0 - 1, point.1 - 1)],
83				end : (point.0 - 1, point.1 - 1)
84			});
85		}
86
87		if graph.contains_key(&(point.0 + 1, point.1)) {
88			peers.push(Edge{
89				cost : graph[&(point.0 + 1, point.1)],
90				end : (point.0 + 1, point.1)
91			});
92		}
93		if graph.contains_key(&(point.0 + 1, point.1 + 1)) {
94			peers.push(Edge{
95				cost : graph[&(point.0 + 1, point.1 + 1)],
96				end : (point.0 + 1, point.1 + 1)
97			});
98		}
99
100		if graph.contains_key(&(point.0, point.1-1)) {
101			peers.push(Edge{
102				cost : graph[&(point.0, point.1 - 1)],
103				end : (point.0, point.1 - 1)
104			});
105		}
106		if graph.contains_key(&(point.0+1, point.1-1)) {
107			peers.push(Edge{
108				cost : graph[&(point.0 + 1, point.1 - 1)],
109				end : (point.0 + 1, point.1 - 1)
110			});
111		}
112
113		if graph.contains_key(&(point.0, point.1+1)) {
114			peers.push(Edge{
115				cost : graph[&(point.0, point.1 + 1)],
116				end : (point.0, point.1 + 1)
117			});
118		}
119		if graph.contains_key(&(point.0-1, point.1+1)) {
120			peers.push(Edge{
121				cost : graph[&(point.0 - 1, point.1 + 1)],
122				end : (point.0 - 1, point.1 + 1)
123			});
124		}
125		fullgraph.insert(*point, peers);
126	}
127
128	fullgraph
129}
130
131pub fn heuristic(first : &Node, second : &Node) -> i64 {
132	(first.0 - second.0).abs() + (first.1 - second.1).abs()
133}
134
135pub fn astar<T: Eq + std::hash::Hash + Clone + Copy, F: FnOnce(&T, &T) -> i64 + Copy>
136(graph : &Graph<T>, start : T, end : T, heuristic: &F) -> Option<Vec<T>> {
137
138	let mut openset : HashSet<T> = HashSet::new();
139	let mut closedset : HashSet<T> = HashSet::new();
140	let mut gscore : HashMap<T, i64> = HashMap::new();
141	let mut fscore : HashMap<T, i64> = HashMap::new();
142	let mut previous : HashMap<T, T> = HashMap::new();
143
144	openset.insert(start);
145	gscore.insert(start, 0);
146	fscore.insert(start, heuristic(&start, &end));
147
148	while openset.len() > 0 {
149		let mut current = openset.iter().nth(0).unwrap().clone();
150
151		for node in openset.iter() {
152			let cost1 = gscore[&current] + heuristic(&current, &end);
153			let cost2 = gscore[node] + heuristic(&node, &end);
154			if cost2 < cost1 {
155				current = node.clone();
156			}
157		}
158
159		if current == end {
160			let mut path : Vec<T> = vec![current];
161			while previous.contains_key(&current) {
162				current = previous[&current];
163				path.push(current);
164			}
165			path.reverse();
166			return Some(path);
167		}
168
169		openset.remove(&current);
170		closedset.insert(current);
171
172		let edges = graph[&current].clone();
173
174		for edge in edges {
175			if closedset.contains(&edge.end) {
176				continue;
177			}
178
179			let potentialcost = gscore[&current] + edge.cost;
180
181			if !openset.contains(&edge.end) {
182				openset.insert(edge.end);
183			}
184			else if potentialcost >= gscore[&edge.end] {
185				continue;
186			}
187
188			previous.insert(edge.end, current);
189			gscore.insert(edge.end, potentialcost);
190			fscore.insert(edge.end, potentialcost + heuristic(&edge.end, &end));
191		}
192	}
193	None
194}