chingu-pathfinding 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/chingu_pathfinding/chingu_pathfinding.cpp +57 -44
- data/ext/chingu_pathfinding/extconf.rb +1 -0
- data/lib/chingu_pathfinding.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: acbba82b0ce19c59d1968606277fca2f0ce65794
|
4
|
+
data.tar.gz: 3d4aa10838504fa9ce82a7116fcca2afe3a35868
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4ba0c8c9f2905de61d1c7491fd222a073b0dc161221dc772ca6803e593d497641e46a666a7f05aa7bb97591293e678c67046616f7fd53a408ec5b768e5188898
|
7
|
+
data.tar.gz: 42bd5a22cc0b2ea8cb93b25d78e1fdd66fdc820e6c096a73fc9e86f2216a719cafc5904d65feb81e7cc20992e7233996a138f4b35120a6fec685654e9c5ff2e2
|
@@ -1,9 +1,9 @@
|
|
1
1
|
#include <ruby.h>
|
2
2
|
#include <math.h>
|
3
3
|
#include <vector>
|
4
|
-
#include <
|
4
|
+
#include <unordered_map>
|
5
5
|
#include <queue>
|
6
|
-
#include <
|
6
|
+
#include <unordered_set>
|
7
7
|
#include <iostream>
|
8
8
|
#include <algorithm>
|
9
9
|
#include <functional>
|
@@ -19,16 +19,30 @@ extern "C" {
|
|
19
19
|
}
|
20
20
|
}
|
21
21
|
|
22
|
-
|
22
|
+
namespace std {
|
23
|
+
template<typename a, typename b>
|
24
|
+
struct hash< std::pair<a, b> > {
|
25
|
+
private:
|
26
|
+
const hash<a> ah;
|
27
|
+
const hash<b> bh;
|
28
|
+
public:
|
29
|
+
hash() : ah(), bh() {}
|
30
|
+
size_t operator()(const std::pair<a, b> &p) const {
|
31
|
+
return ah(p.first) ^ bh(p.second) << 5 ^ bh(p.second);
|
32
|
+
}
|
33
|
+
};
|
34
|
+
}
|
35
|
+
|
36
|
+
inline int dir(const int a, const int b) {
|
23
37
|
if (a == b) return 0;
|
24
38
|
if (a < b) return 1;
|
25
39
|
return -1;
|
26
40
|
}
|
27
41
|
|
28
42
|
struct point_t {
|
29
|
-
|
43
|
+
int x, y;
|
30
44
|
bool valid;
|
31
|
-
point_t(
|
45
|
+
point_t(int xx, int yy) {
|
32
46
|
x = xx;
|
33
47
|
y = yy;
|
34
48
|
valid = true;
|
@@ -36,7 +50,7 @@ struct point_t {
|
|
36
50
|
point_t() : x(0), y(0), valid(false) { }
|
37
51
|
point_t(const point_t& p) : x(p.x), y(p.y), valid(p.valid) { }
|
38
52
|
};
|
39
|
-
typedef std::pair<
|
53
|
+
typedef std::pair<int, int> location_t;
|
40
54
|
|
41
55
|
float dist(const location_t& a, const location_t& b) {
|
42
56
|
float dx = a.first-b.first;
|
@@ -45,19 +59,19 @@ float dist(const location_t& a, const location_t& b) {
|
|
45
59
|
}
|
46
60
|
|
47
61
|
class path_t {
|
48
|
-
std::
|
49
|
-
std::
|
62
|
+
std::unordered_map< location_t, point_t >* map_p;
|
63
|
+
std::unordered_multimap< location_t, location_t >* connectivity_p;
|
50
64
|
float cost_paid;
|
51
65
|
|
52
66
|
public:
|
53
67
|
std::vector<location_t> path;
|
54
|
-
path_t() : cost_paid(0) { }
|
68
|
+
path_t() : cost_paid(0), map_p(NULL), connectivity_p(NULL) { }
|
55
69
|
path_t(const path_t& p) : map_p(p.map_p), connectivity_p(p.connectivity_p), path(p.path), cost_paid(p.cost_paid) { }
|
56
|
-
path_t(std::
|
57
|
-
std::
|
70
|
+
path_t(std::unordered_map< location_t, point_t >* mm,
|
71
|
+
std::unordered_multimap< location_t, location_t >* cc)
|
58
72
|
: map_p(mm), connectivity_p(cc), cost_paid(0), path() { }
|
59
73
|
float get_cost_paid() const { return cost_paid; }
|
60
|
-
void add_loc(location_t l, const location_t& goal) {
|
74
|
+
void add_loc(const location_t& l, const location_t& goal) {
|
61
75
|
if (!path.empty()) {
|
62
76
|
location_t last = *path.crbegin();
|
63
77
|
cost_paid += dist(last, l);
|
@@ -87,23 +101,23 @@ class by_estimated_cost {
|
|
87
101
|
|
88
102
|
|
89
103
|
class pathfinder_t {
|
90
|
-
std::
|
91
|
-
std::
|
92
|
-
|
104
|
+
std::unordered_map< location_t, point_t > map; // Spartial hashing
|
105
|
+
std::unordered_multimap< location_t, location_t > connectivity; // sparse connectivity
|
106
|
+
int height, width, block_size;
|
93
107
|
ID blocked_method;
|
94
108
|
VALUE self;
|
95
109
|
|
96
|
-
bool is_blocked(const
|
110
|
+
bool is_blocked(const int x, const int y) {
|
97
111
|
VALUE blocked = rb_funcall(self, blocked_method, 2, INT2NUM(x), INT2NUM(y));
|
98
112
|
return blocked != Qfalse && blocked != Qnil;
|
99
113
|
}
|
100
114
|
|
101
|
-
bool line_blocked(const
|
115
|
+
bool line_blocked(const int x1, const int y1, const int x2, const int y2) {
|
102
116
|
if (block_size == 1) return false;
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
117
|
+
int dx = dir(x1, x2);
|
118
|
+
int dy = dir(y1, y2);
|
119
|
+
int runner_x = x1;
|
120
|
+
int runner_y = y1;
|
107
121
|
while (runner_x * dx <= x2 * dx &&
|
108
122
|
runner_y * dy <= y2 * dy) {
|
109
123
|
if (is_blocked(runner_x, runner_y)) {
|
@@ -116,11 +130,11 @@ class pathfinder_t {
|
|
116
130
|
}
|
117
131
|
|
118
132
|
typedef std::priority_queue<path_t, std::vector<path_t>, by_estimated_cost> queue_t;
|
119
|
-
path_t find_path_internal(queue_t queue, location_t goal) {
|
120
|
-
std::
|
133
|
+
path_t find_path_internal(queue_t& queue, location_t& goal) {
|
134
|
+
std::unordered_set<location_t> visited;
|
121
135
|
while (!queue.empty()) {
|
122
136
|
path_t current = queue.top();
|
123
|
-
location_t end = current.end();
|
137
|
+
const location_t& end = current.end();
|
124
138
|
queue.pop();
|
125
139
|
if (visited.find(end) != visited.end()) continue;
|
126
140
|
visited.insert(end);
|
@@ -136,7 +150,7 @@ class pathfinder_t {
|
|
136
150
|
if (visited.find(to) != visited.end()){
|
137
151
|
continue;
|
138
152
|
}
|
139
|
-
path_t new_path
|
153
|
+
path_t new_path(current);
|
140
154
|
new_path.add_loc(to, goal);
|
141
155
|
queue.push(new_path);
|
142
156
|
}
|
@@ -145,14 +159,14 @@ class pathfinder_t {
|
|
145
159
|
}
|
146
160
|
|
147
161
|
public:
|
148
|
-
path_t find_path(
|
162
|
+
path_t find_path(int x1, int y1, int x2, int y2) {
|
149
163
|
location_t start(x1,y1);
|
150
164
|
location_t goal(x2,y2);
|
151
165
|
by_estimated_cost estimator(goal);
|
152
166
|
queue_t queue(estimator);
|
153
167
|
path_t init_path(&map, &connectivity);
|
154
|
-
|
155
|
-
|
168
|
+
int next_node_x = (x1 / block_size)*block_size + block_size/2;
|
169
|
+
int next_node_y = (y1 / block_size)*block_size + block_size/2;
|
156
170
|
init_path.add_loc(start, goal);
|
157
171
|
location_t start_block(next_node_x, next_node_y);
|
158
172
|
if (start != start_block) {
|
@@ -162,7 +176,7 @@ class pathfinder_t {
|
|
162
176
|
return find_path_internal(queue, goal);
|
163
177
|
}
|
164
178
|
|
165
|
-
path_t find_path_update(
|
179
|
+
path_t find_path_update(int x1, int y1, int x2, int y2, std::vector<location_t> current) {
|
166
180
|
location_t start(x1,y1);
|
167
181
|
location_t goal(x2,y2);
|
168
182
|
path_t init_path;
|
@@ -190,15 +204,17 @@ class pathfinder_t {
|
|
190
204
|
return find_path_internal(queue, goal);
|
191
205
|
}
|
192
206
|
|
193
|
-
void Init(VALUE self,
|
207
|
+
void Init(VALUE self, int width, int height, int block_size) {
|
194
208
|
this->width = width;
|
195
209
|
this->height = height;
|
196
210
|
this->block_size = block_size;
|
197
211
|
this->self = self;
|
212
|
+
this->map.reserve(width/block_size * height/block_size);
|
213
|
+
this->connectivity.reserve(width/block_size * height/block_size*4);
|
198
214
|
blocked_method = rb_intern("blocked?");
|
199
215
|
// Build internal map:
|
200
|
-
for (
|
201
|
-
for (
|
216
|
+
for (int x = block_size/2; x < width; x += block_size) {
|
217
|
+
for (int y = block_size/2; y < height; y += block_size) {
|
202
218
|
// add point if it is not blocked
|
203
219
|
if (is_blocked(x, y)) continue;
|
204
220
|
auto cur_loc = location_t(x,y);
|
@@ -236,20 +252,19 @@ class pathfinder_t {
|
|
236
252
|
}
|
237
253
|
}
|
238
254
|
}
|
239
|
-
// print_map();
|
240
255
|
} // END Init
|
241
256
|
|
242
257
|
std::string print_map() {
|
243
258
|
// DEBUGGING
|
244
259
|
|
245
|
-
auto mapp = std::
|
246
|
-
for (
|
247
|
-
for (
|
260
|
+
auto mapp = std::unordered_map<location_t, char>();
|
261
|
+
for (int x = 0; x < width; x++) {
|
262
|
+
for (int y = 0; y < height; y++) {
|
248
263
|
mapp[location_t(x, y)] = ' ';
|
249
264
|
}
|
250
265
|
}
|
251
|
-
for (
|
252
|
-
for (
|
266
|
+
for (int x = block_size/2; x < width; x += block_size) {
|
267
|
+
for (int y = block_size/2; y < height; y += block_size) {
|
253
268
|
if (!map[location_t(x, y)].valid) {
|
254
269
|
mapp[location_t(x, y)] = '~';
|
255
270
|
continue;
|
@@ -269,9 +284,9 @@ class pathfinder_t {
|
|
269
284
|
}
|
270
285
|
std::stringstream out;
|
271
286
|
out << "map:";
|
272
|
-
for (
|
287
|
+
for (int y = 0; y < height; y++) {
|
273
288
|
out << std::endl;
|
274
|
-
for (
|
289
|
+
for (int x = 0; x < width; x++) {
|
275
290
|
out << mapp[location_t(x, y)];
|
276
291
|
}
|
277
292
|
}
|
@@ -293,8 +308,6 @@ static VALUE alloc_pathfinder(VALUE klass) {
|
|
293
308
|
|
294
309
|
static VALUE init(VALUE self, VALUE width_a, VALUE height_a, VALUE block_size_a) {
|
295
310
|
pathfinder_t* pf;
|
296
|
-
long int width, height, block_size;
|
297
|
-
long int x, y;
|
298
311
|
Data_Get_Struct(self, pathfinder_t, pf);
|
299
312
|
pf->Init(self, NUM2INT(width_a), NUM2INT(height_a), NUM2INT(block_size_a));
|
300
313
|
return self;
|
@@ -320,8 +333,8 @@ static VALUE find_path_update(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2
|
|
320
333
|
std::vector<location_t> p;
|
321
334
|
for (int i = 0; i < len; i++) {
|
322
335
|
VALUE pt = rb_ary_shift(prev);
|
323
|
-
|
324
|
-
|
336
|
+
int x = NUM2INT(rb_ary_shift(pt));
|
337
|
+
int y = NUM2INT(rb_ary_shift(pt));
|
325
338
|
p.push_back(location_t(x, y));
|
326
339
|
}
|
327
340
|
path_t path = pf->find_path_update(NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2), p);
|
data/lib/chingu_pathfinding.rb
CHANGED