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[¤t] + heuristic(¤t, &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(¤t) {
162 current = previous[¤t];
163 path.push(current);
164 }
165 path.reverse();
166 return Some(path);
167 }
168
169 openset.remove(¤t);
170 closedset.insert(current);
171
172 let edges = graph[¤t].clone();
173
174 for edge in edges {
175 if closedset.contains(&edge.end) {
176 continue;
177 }
178
179 let potentialcost = gscore[¤t] + 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}