-
Notifications
You must be signed in to change notification settings - Fork 0
/
gpath.h
156 lines (137 loc) · 3.73 KB
/
gpath.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#ifndef GPATH_H_
#define GPATH_H_
#include <string.h>
#include <queue>
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
#include "enable_if.h"
#include "grid.h"
template <typename Passable, typename Cost>
class Gpath : public Grid<int>
{
protected:
struct QElem {
QElem(const Location &l, int d)
: loc(l), dist(d) { }
QElem(int r, int c, int d)
: loc(Location(r,c)), dist(d) { }
Location loc;
int dist;
};
public:
Gpath()
: empty_(true)
{ }
Gpath(std::string _name)
: name(_name)
, empty_(true)
{ }
Gpath(std::string _name, Passable p)
: name(_name)
, passable(p)
, empty_(true)
{ }
Gpath(std::string _name, Cost c)
: name(_name)
, cost(c)
, empty_(true)
{ }
Gpath(std::string _name, Passable p, Cost c)
: name(_name)
, passable(p)
, cost(c)
, empty_(true)
{ }
template <typename I>
void update(I begin, I end)
{
fill(9999);
std::queue<QElem> food;
for (; begin != end; ++begin)
enqueue(food, 0, *begin);
update(food);
}
int gradient(const Location &loc, int *close = 0) const
{
if (empty_)
return -1;
int best_dist = (*this)(loc);
int best = -1;
for (int d = 0; d < TDIRECTIONS; ++d) {
Location targ = state.getLocation(loc, d);
if ((*this)(targ) < best_dist) {
best_dist = (*this)(targ);
best = d;
}
}
if (close)
*close = best_dist;
return best;
}
bool toward(const Location &loc, const Location &dest) const
{
return (*this)(dest) < (*this)(loc);
}
bool empty() const { return empty_; }
protected:
inline void enqueue(std::queue<QElem> & q, int d, const Location &loc)
{
d += cost(loc);
if ((*this)(loc) > d) {
(*this)(loc) = d;
q.push(QElem(loc, d));
}
}
void enqueue(std::queue<QElem> & q, int d, const Location &loc, int dr, int dc)
{
const Location dest = state.deltaLocation(loc, dr, dc);
int p = passable(dest);
if (p)
enqueue(q, d + (p - 1), dest);
}
template <typename V>
struct has_member_setOrigin
{
template <typename U, void (U::*)(const Location &)> struct SFINAE {};
template <typename U> static char test(SFINAE<U, &U::setOrigin>*);
template <typename U> static int test(...);
static const bool value = sizeof(test<V>(0)) == sizeof(char);
};
template<typename V>
inline __attribute__((__always_inline__))
void callSetOrigin(typename enable_if <has_member_setOrigin<V>::value, V>::type &p, const Location &loc) const
{
p.setOrigin(loc);
}
template<typename V>
inline __attribute__((__always_inline__))
void callSetOrigin(typename enable_if <!has_member_setOrigin<V>::value, V>::type &p, const Location &loc) const
{
}
inline void enqueueAll(std::queue<QElem> & q, int d, const Location &loc) __attribute__((__flatten__))
{
callSetOrigin<Passable>(passable, loc);
enqueue(q, d, loc, +1, 0);
enqueue(q, d, loc, 0, +1);
enqueue(q, d, loc, -1, 0);
enqueue(q, d, loc, 0, -1);
}
void update(std::queue<QElem> &food) __attribute__((__flatten__))
{
empty_ = food.empty();
while (!food.empty()) {
const QElem &qe = food.front();
enqueueAll(food, qe.dist, qe.loc);
food.pop();
}
}
public:
std::string name;
protected:
Passable passable;
Cost cost;
bool empty_;
};
#endif