00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "hexmove.h"
00025
00026 #include <cmath>
00027
00028
00029 namespace hex {
00030 namespace move {
00031
00032
00033 Topography::Topography()
00034 : _has_default(false), _default(0.0), _hexes(), _edges()
00035 {}
00036
00037
00038 Topography::Topography(Cost default_hex_cost)
00039 : _has_default(true), _default(default_hex_cost), _hexes(), _edges()
00040 {}
00041
00042
00043 std::set<hex::Hex*>
00044 Topography::accessible(void) const
00045 {
00046 using namespace std;
00047 set<hex::Hex*> result;
00048 for(map<hex::Hex*,Cost>::const_iterator i=_hexes.begin(); i!=_hexes.end();++i)
00049 result.insert(i->first);
00050 for(map<hex::Edge*,Cost>::const_iterator i=_edges.begin();i!=_edges.end();++i)
00051 result.insert(i->first->hex());
00052 return result;
00053 }
00054
00055
00056 void
00057 Topography::increase_hex_cost(hex::Hex* h, Cost c)
00058 {
00059 {
00060 std::map<hex::Hex*,Cost>::iterator pos = _hexes.find(h);
00061 if(pos==_hexes.end())
00062 _hexes[h] = _default + c;
00063 else
00064 pos->second += c;
00065 }
00066 for(int d=0; d<DIRECTIONS; ++d)
00067 {
00068 hex::Edge* e =h->edge(hex::A+d);
00069 std::map<hex::Edge*,Cost>::iterator pos = _edges.find(e);
00070 if(pos!=_edges.end())
00071 pos->second += c;
00072 }
00073 }
00074
00075
00076 void
00077 Topography::override_hex_cost(hex::Hex* h, Cost c)
00078 {
00079 _hexes[h] = c;
00080 for(int d=0; d<DIRECTIONS; ++d)
00081 {
00082 hex::Edge* e =h->edge(hex::A+d);
00083 _edges.erase(e);
00084 }
00085 }
00086
00087 void Topography::increase_edge_cost(hex::Edge* e, Cost c)
00088 {
00089 if(!e)
00090 return;
00091 std::map<hex::Edge*,Cost>::iterator epos = _edges.find(e);
00092 if(epos==_edges.end())
00093 {
00094 std::map<hex::Hex*,Cost>::iterator hpos = _hexes.find( e->hex() );
00095 if(hpos!=_hexes.end())
00096 _edges[e] = hpos->second + c;
00097 else if(_has_default)
00098 _edges[e] = _default + c;
00099 }
00100 else
00101 {
00102 epos->second += c;
00103 }
00104 }
00105
00106
00107 void
00108 Topography::override_edge_cost(hex::Edge* e, Cost c)
00109 {
00110 if(e)
00111 _edges[e] = c;
00112 }
00113
00114
00115 void
00116 Topography::increase_cost(const hex::Area& a, Cost c)
00117 {
00118 const std::set<hex::Hex*>& hexes = a.hexes();
00119 for(std::set<hex::Hex*>::const_iterator i=hexes.begin(); i!=hexes.end(); ++i)
00120 increase_hex_cost(*i,c);
00121 }
00122
00123
00124 void
00125 Topography::override_cost(const hex::Area& a, Cost c)
00126 {
00127 const std::set<hex::Hex*>& hexes = a.hexes();
00128 for(std::set<hex::Hex*>::const_iterator i=hexes.begin(); i!=hexes.end(); ++i)
00129 override_hex_cost(*i,c);
00130 }
00131
00132
00133 void
00134 Topography::increase_cost(const hex::Boundary& b, Cost c)
00135 {
00136 const std::list<hex::Edge*>& edges = b.edges();
00137 for(std::list<hex::Edge*>::const_iterator i=edges.begin(); i!=edges.end(); ++i)
00138 increase_edge_cost(*i,c);
00139 }
00140
00141
00142 void
00143 Topography::override_cost(const hex::Boundary& b, Cost c)
00144 {
00145 const std::list<hex::Edge*>& edges = b.edges();
00146 for(std::list<hex::Edge*>::const_iterator i=edges.begin(); i!=edges.end(); ++i)
00147 override_edge_cost(*i,c);
00148 }
00149
00150
00151 hex::Path
00152 Topography::best_path(hex::Hex* start, hex::Hex* goal) const throw(no_solution)
00153 {
00154 std::set<hex::Hex*> visited;
00155 std::multiset<_Route> queue;
00156 queue.insert( _Route::factory(start,goal) );
00157 while(!queue.empty())
00158 {
00159 _Route curr_route = *queue.begin();
00160 queue.erase( queue.begin() );
00161 hex::Hex* curr_hex = curr_route.path.back();
00162 if(visited.count(curr_hex))
00163 continue;
00164 if(curr_hex==goal)
00165 return hex::Path(curr_route.path);
00166 visited.insert(curr_hex);
00167 for(int dir=0; dir<DIRECTIONS; ++dir)
00168 {
00169 Topography::Step s = step(curr_hex,hex::A+dir);
00170 if(s.to_hex && 0==visited.count(s.to_hex))
00171 queue.insert( curr_route.step(s.to_hex,s.cost,goal) );
00172 }
00173 }
00174 throw no_solution("best_path");
00175 }
00176
00177
00178 hex::Area
00179 Topography::horizon(hex::Hex* start, Cost budget) const throw(no_solution)
00180 {
00181 std::set<hex::Hex*> visited;
00182 std::multiset<_Route> queue;
00183 queue.insert( _Route::factory(start) );
00184 while(!queue.empty())
00185 {
00186 _Route curr_route = *queue.begin();
00187 queue.erase( queue.begin() );
00188 hex::Hex* curr_hex = curr_route.path.back();
00189 if(visited.count(curr_hex))
00190 continue;
00191 if(curr_route.cost > budget)
00192 continue;
00193 visited.insert(curr_hex);
00194 for(int dir=0; dir<DIRECTIONS; ++dir)
00195 {
00196 Topography::Step s = step(curr_hex,hex::A+dir);
00197 if(s.to_hex && 0==visited.count(s.to_hex))
00198 queue.insert( curr_route.step(s.to_hex,s.cost) );
00199 }
00200 }
00201 return visited;
00202 }
00203
00204
00205 Topography::Step
00206 Topography::step(hex::Hex* from_hex, Direction direction) const
00207 {
00208 Step result = {NULL,_default};
00209
00210 result.to_hex = from_hex->go(direction);
00211 if(!result.to_hex)
00212 return result;
00213
00214 hex::Edge* to_edge = result.to_hex->edge(direction+3);
00215 std::map<hex::Edge*,Cost>::const_iterator epos = _edges.find(to_edge);
00216 if(epos!=_edges.end())
00217 {
00218 result.cost = epos->second;
00219 return result;
00220 }
00221
00222 std::map<hex::Hex*,Cost>::const_iterator hpos = _hexes.find( result.to_hex );
00223 if(hpos!=_hexes.end())
00224 result.cost = hpos->second;
00225 else if(!_has_default)
00226 result.to_hex = NULL;
00227 return result;
00228 }
00229
00230
00231
00232
00233
00234 _Route
00235 _Route::factory(hex::Hex* start, hex::Hex* goal)
00236 {
00237 _Route result;
00238 result.path.push_back(start);
00239 result.cost = 0;
00240 result._value = result.distance(goal);
00241 return result;
00242 }
00243
00244
00245 _Route
00246 _Route::step(hex::Hex* next, Cost cost, hex::Hex* goal) const
00247 {
00248 _Route result;
00249 result.path = path;
00250 result.path.push_back(next);
00251 result.cost = this->cost + cost;
00252 result._value = result.cost + result.distance(goal);
00253 return result;
00254 }
00255
00256
00257 hex::Distance
00258 _Route::distance(hex::Hex* goal) const
00259 {
00260 if(goal)
00261 {
00262 hex::Point vector = goal->centre() - path.back()->centre();
00263 return sqrt( vector.x * vector.x + vector.y * vector.y );
00264 }
00265 return 0;
00266 }
00267
00268
00269 }
00270 }