1use bindings::ffi;
2use bindings::{AsNative, c_bool, c_float, c_int, c_void};
3use map::Map;
4
5enum PathInnerData<'a> {
6 Map(Map),
7 Callback(Box<FnMut((i32, i32), (i32, i32)) -> f32+'a>),
8}
9
10pub struct AStar<'a>{
11 tcod_path: ffi::TCOD_path_t,
12 #[allow(dead_code)]
13 inner: PathInnerData<'a>,
14 width: i32,
15 height: i32,
16}
17
18impl<'a> AsNative<ffi::TCOD_path_t> for AStar<'a> {
19 unsafe fn as_native(&self) -> &ffi::TCOD_path_t {
20 &self.tcod_path
21 }
22
23 unsafe fn as_native_mut(&mut self) -> &mut ffi::TCOD_path_t {
24 &mut self.tcod_path
25 }
26}
27
28impl<'a> Drop for AStar<'a> {
29 fn drop(&mut self) {
30 unsafe {
31 ffi::TCOD_path_delete(self.tcod_path);
32 }
33 }
34}
35
36extern "C" fn c_path_callback<T: FnMut((i32, i32), (i32, i32)) -> f32>(xf: c_int, yf: c_int,
37 xt: c_int, yt: c_int,
38 user_data: *mut c_void) -> c_float {
39 let callback_ptr = user_data as *mut T;
40 let cb: &mut T = unsafe {
41 &mut *callback_ptr
42 };
43 cb((xf, yf), (xt, yt))
44}
45
46impl<'a> AStar<'a> {
47 pub fn new_from_callback<T: 'a+FnMut((i32, i32), (i32, i32)) -> f32>(
48 width: i32, height: i32, path_callback: T,
49 diagonal_cost: f32) -> AStar<'a> {
50 let callback = Box::new(path_callback);
51 let user_data = &*callback as *const T as *mut c_void;
52 unsafe {
53 let tcod_path = ffi::TCOD_path_new_using_function(width, height,
54 Some(c_path_callback::<T>),
55 user_data,
56 diagonal_cost);
57 AStar {
58 tcod_path: tcod_path,
59 inner: PathInnerData::Callback(callback),
62 width: width,
63 height: height,
64 }
65 }
66 }
67
68 pub fn new_from_map(map: Map, diagonal_cost: f32) -> AStar<'static> {
69 let tcod_path = unsafe {
70 ffi::TCOD_path_new_using_map(*map.as_native(), diagonal_cost)
71 };
72 let (w, h) = map.size();
73 AStar {
74 tcod_path: tcod_path,
75 inner: PathInnerData::Map(map),
76 width: w,
77 height: h,
78 }
79 }
80
81 pub fn find(&mut self,
82 from: (i32, i32),
83 to: (i32, i32)) -> bool {
84 let (from_x, from_y) = from;
85 let (to_x, to_y) = to;
86 assert!(from_x >= 0 && from_y >= 0 && to_x >= 0 && to_y >= 0);
87 assert!(from_x < self.width && from_y < self.height && to_x < self.width && to_y < self.height);
88 unsafe {
89 ffi::TCOD_path_compute(self.tcod_path,
90 from_x, from_y,
91 to_x, to_y) != 0
92 }
93 }
94
95 pub fn iter(&'a self) -> AStarPathIter<'a> {
96 AStarPathIter { current: -1, path: self }
97 }
98
99 pub fn walk(&mut self) -> AStarIterator {
100 AStarIterator{tcod_path: self.tcod_path, recalculate: false}
101 }
102
103 pub fn walk_recalculate(&mut self) -> AStarIterator {
104 AStarIterator{tcod_path: self.tcod_path, recalculate: true}
105 }
106
107 pub fn walk_one_step(&mut self, recalculate_when_needed: bool) -> Option<(i32, i32)> {
108 unsafe {
109 let mut x: c_int = 0;
110 let mut y: c_int = 0;
111 match ffi::TCOD_path_walk(self.tcod_path, &mut x, &mut y,
112 recalculate_when_needed as c_bool) != 0 {
113 true => Some((x, y)),
114 false => None,
115 }
116 }
117 }
118
119 pub fn reverse(&mut self) {
120 unsafe {
121 ffi::TCOD_path_reverse(self.tcod_path)
122 }
123 }
124
125 pub fn origin(&self) -> (isize, isize) {
126 unsafe {
127 let mut x: c_int = 0;
128 let mut y: c_int = 0;
129 ffi::TCOD_path_get_origin(self.tcod_path, &mut x, &mut y);
130 (x as isize, y as isize)
131 }
132 }
133
134 pub fn destination(&self) -> (isize, isize) {
135 unsafe {
136 let mut x: c_int = 0;
137 let mut y: c_int = 0;
138 ffi::TCOD_path_get_destination(self.tcod_path, &mut x, &mut y);
139 (x as isize, y as isize)
140 }
141 }
142
143 pub fn get(&self, index: i32) -> Option<(i32, i32)> {
144 if index < 0 || index >= self.len() {
145 return None;
146 }
147 unsafe {
148 let mut x: c_int = 0;
149 let mut y: c_int = 0;
150 ffi::TCOD_path_get(self.tcod_path, index, &mut x, &mut y);
151 (Some((x, y)))
152 }
153 }
154
155 pub fn is_empty(&self) -> bool {
156 unsafe {
157 ffi::TCOD_path_is_empty(self.tcod_path) != 0
158 }
159 }
160
161 pub fn len(&self) -> i32 {
162 unsafe {
163 ffi::TCOD_path_size(self.tcod_path)
164 }
165 }
166}
167
168pub struct Dijkstra<'a> {
169 tcod_path: ffi::TCOD_dijkstra_t,
170 #[allow(dead_code)]
171 inner: PathInnerData<'a>,
172 width: i32,
173 height: i32,
174}
175
176impl<'a> AsNative<ffi::TCOD_path_t> for Dijkstra<'a> {
177 unsafe fn as_native(&self) -> &ffi::TCOD_dijkstra_t {
178 &self.tcod_path
179 }
180
181 unsafe fn as_native_mut(&mut self) -> &mut ffi::TCOD_dijkstra_t {
182 &mut self.tcod_path
183 }
184}
185
186impl<'a> Drop for Dijkstra<'a> {
187 fn drop(&mut self) {
188 unsafe {
189 ffi::TCOD_dijkstra_delete(self.tcod_path);
190 }
191 }
192}
193
194impl<'a> Dijkstra<'a> {
195 pub fn new_from_callback<T: 'a+FnMut((i32, i32), (i32, i32)) -> f32>(
196 width: i32, height: i32,
197 path_callback: T,
198 diagonal_cost: f32) -> Dijkstra<'a> {
199 let callback = Box::new(path_callback);
200 let user_data = &*callback as *const T as *mut c_void;
201 unsafe {
202 let tcod_path = ffi::TCOD_dijkstra_new_using_function(width,
203 height,
204 Some(c_path_callback::<T>),
205 user_data,
206 diagonal_cost);
207 Dijkstra {
208 tcod_path: tcod_path,
209 inner: PathInnerData::Callback(callback),
210 width: width,
211 height: height,
212 }
213 }
214 }
215
216 pub fn new_from_map(map: Map, diagonal_cost: f32) -> Dijkstra<'static> {
217 let tcod_path = unsafe {
218 ffi::TCOD_dijkstra_new(*map.as_native(), diagonal_cost)
219 };
220 let (w, h) = map.size();
221 Dijkstra {
222 tcod_path: tcod_path,
223 inner: PathInnerData::Map(map),
224 width: w,
225 height: h,
226 }
227 }
228
229 pub fn compute_grid(&mut self, root: (i32, i32)) {
230 let (x, y) = root;
231 assert!(x >= 0 && y >= 0 && x < self.width && y < self.height);
232 unsafe {
233 ffi::TCOD_dijkstra_compute(self.tcod_path, x, y);
234 }
235 }
236
237 pub fn find(&mut self, destination: (i32, i32)) -> bool {
238 let (x, y) = destination;
239 if x >= 0 && y >= 0 && x < self.width && y < self.height {
240 unsafe {
241 ffi::TCOD_dijkstra_path_set(self.tcod_path, x, y) != 0
242 }
243 } else {
244 false
245 }
246 }
247
248 pub fn iter(&'a self) -> DijkstraPathIter<'a> {
249 DijkstraPathIter { current: -1, path: self }
250 }
251
252 pub fn walk(&mut self) -> DijkstraIterator {
253 DijkstraIterator{tcod_path: self.tcod_path}
254 }
255
256 pub fn walk_one_step(&mut self) -> Option<(i32, i32)> {
257 unsafe {
258 let mut x: c_int = 0;
259 let mut y: c_int = 0;
260 match ffi::TCOD_dijkstra_path_walk(self.tcod_path, &mut x, &mut y) != 0 {
261 true => Some((x, y)),
262 false => None,
263 }
264 }
265 }
266
267
268 pub fn distance_from_root(&self, point: (i32, i32)) -> Option<f32> {
269 let (x, y) = point;
270 let result = unsafe {
271 ffi::TCOD_dijkstra_get_distance(self.tcod_path, x, y)
272 };
273 if result == -1.0 {
274 None
275 } else {
276 Some(result)
277 }
278 }
279
280 pub fn reverse(&mut self) {
281 unsafe {
282 ffi::TCOD_dijkstra_reverse(self.tcod_path);
283 }
284 }
285
286 pub fn get(&self, index: i32) -> Option<(i32, i32)> {
287 if index < 0 || index >= self.len() {
288 return None;
289 }
290 unsafe {
291 let mut x: c_int = 0;
292 let mut y: c_int = 0;
293 ffi::TCOD_dijkstra_get(self.tcod_path, index, &mut x, &mut y);
294 Some((x, y))
295 }
296 }
297
298 pub fn is_empty(&self) -> bool {
299 unsafe {
300 ffi::TCOD_dijkstra_is_empty(self.tcod_path) != 0
301 }
302 }
303
304 pub fn len(&self) -> i32 {
305 unsafe {
306 ffi::TCOD_dijkstra_size(self.tcod_path)
307 }
308 }
309}
310
311pub struct AStarIterator {
312 tcod_path: ffi::TCOD_path_t,
313 recalculate: bool,
314}
315
316impl Iterator for AStarIterator {
317 type Item = (i32, i32);
318
319 fn next(&mut self) -> Option<(i32, i32)> {
320 unsafe {
321 let mut x: c_int = 0;
322 let mut y: c_int = 0;
323 match ffi::TCOD_path_walk(self.tcod_path, &mut x, &mut y,
324 self.recalculate as c_bool) != 0 {
325 true => Some((x, y)),
326 false => None,
327 }
328 }
329 }
330}
331
332pub struct DijkstraIterator {
333 tcod_path: ffi::TCOD_path_t,
334}
335
336impl Iterator for DijkstraIterator {
337 type Item = (i32, i32);
338
339 fn next(&mut self) -> Option<(i32, i32)> {
340 unsafe {
341 let mut x: c_int = 0;
342 let mut y: c_int = 0;
343 match ffi::TCOD_dijkstra_path_walk(self.tcod_path, &mut x, &mut y) != 0 {
344 true => Some((x, y)),
345 false => None,
346 }
347 }
348 }
349}
350
351pub struct AStarPathIter<'a> {
352 current: i32,
353 path: &'a AStar<'a>,
354}
355
356impl<'a> Iterator for AStarPathIter<'a> {
357 type Item = (i32, i32);
358
359 fn next(&mut self) -> Option<Self::Item> {
360 if self.current == self.path.len() - 1 {
361 None
362 } else {
363 self.current += 1;
364 unsafe {
365 let mut x: c_int = 0;
366 let mut y: c_int = 0;
367 ffi::TCOD_path_get(*self.path.as_native(), self.current, &mut x, &mut y);
368 Some((x, y))
369 }
370 }
371 }
372}
373
374pub struct DijkstraPathIter<'a> {
375 current: i32,
376 path: &'a Dijkstra<'a>,
377}
378
379impl<'a> Iterator for DijkstraPathIter<'a> {
380 type Item = (i32, i32);
381
382 fn next(&mut self) -> Option<Self::Item> {
383 if self.current == self.path.len() - 1 {
384 None
385 } else {
386 self.current += 1;
387 unsafe {
388 let mut x: c_int = 0;
389 let mut y: c_int = 0;
390 ffi::TCOD_dijkstra_get(*self.path.as_native(), self.current, &mut x, &mut y);
391 Some((x, y))
392 }
393 }
394 }
395}