Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #ifndef YAPF_BASE_HPP
00013 #define YAPF_BASE_HPP
00014
00015 #include "../../debug.h"
00016 #include "../../settings_type.h"
00017
00018 extern int _total_pf_time_us;
00019
00050 template <class Types>
00051 class CYapfBaseT {
00052 public:
00053 typedef typename Types::Tpf Tpf;
00054 typedef typename Types::TrackFollower TrackFollower;
00055 typedef typename Types::NodeList NodeList;
00056 typedef typename Types::VehicleType VehicleType;
00057 typedef typename NodeList::Titem Node;
00058 typedef typename Node::Key Key;
00059
00060
00061 NodeList m_nodes;
00062 protected:
00063 Node *m_pBestDestNode;
00064 Node *m_pBestIntermediateNode;
00065 const YAPFSettings *m_settings;
00066 int m_max_search_nodes;
00067 const VehicleType *m_veh;
00068
00069 int m_stats_cost_calcs;
00070 int m_stats_cache_hits;
00071
00072 public:
00073 CPerformanceTimer m_perf_cost;
00074 CPerformanceTimer m_perf_slope_cost;
00075 CPerformanceTimer m_perf_ts_cost;
00076 CPerformanceTimer m_perf_other_cost;
00077
00078 public:
00079 int m_num_steps;
00080
00081 public:
00083 inline CYapfBaseT()
00084 : m_pBestDestNode(NULL)
00085 , m_pBestIntermediateNode(NULL)
00086 , m_settings(&_settings_game.pf.yapf)
00087 , m_max_search_nodes(PfGetSettings().max_search_nodes)
00088 , m_veh(NULL)
00089 , m_stats_cost_calcs(0)
00090 , m_stats_cache_hits(0)
00091 , m_num_steps(0)
00092 {
00093 }
00094
00096 ~CYapfBaseT() {}
00097
00098 protected:
00100 inline Tpf& Yapf()
00101 {
00102 return *static_cast<Tpf*>(this);
00103 }
00104
00105 public:
00107 inline const YAPFSettings& PfGetSettings() const
00108 {
00109 return *m_settings;
00110 }
00111
00121 inline bool FindPath(const VehicleType *v)
00122 {
00123 m_veh = v;
00124
00125 #ifndef NO_DEBUG_MESSAGES
00126 CPerformanceTimer perf;
00127 perf.Start();
00128 #endif
00129
00130 Yapf().PfSetStartupNodes();
00131 bool bDestFound = true;
00132
00133 for (;;) {
00134 m_num_steps++;
00135 Node *n = m_nodes.GetBestOpenNode();
00136 if (n == NULL) {
00137 break;
00138 }
00139
00140
00141 if (m_pBestDestNode != NULL && m_pBestDestNode->GetCost() < n->GetCostEstimate()) {
00142 break;
00143 }
00144
00145 Yapf().PfFollowNode(*n);
00146 if (m_max_search_nodes == 0 || m_nodes.ClosedCount() < m_max_search_nodes) {
00147 m_nodes.PopOpenNode(n->GetKey());
00148 m_nodes.InsertClosedNode(*n);
00149 } else {
00150 bDestFound = false;
00151 break;
00152 }
00153 }
00154
00155 bDestFound &= (m_pBestDestNode != NULL);
00156
00157 #ifndef NO_DEBUG_MESSAGES
00158 perf.Stop();
00159 if (_debug_yapf_level >= 2) {
00160 int t = perf.Get(1000000);
00161 _total_pf_time_us += t;
00162
00163 if (_debug_yapf_level >= 3) {
00164 UnitID veh_idx = (m_veh != NULL) ? m_veh->unitnumber : 0;
00165 char ttc = Yapf().TransportTypeChar();
00166 float cache_hit_ratio = (m_stats_cache_hits == 0) ? 0.0f : ((float)m_stats_cache_hits / (float)(m_stats_cache_hits + m_stats_cost_calcs) * 100.0f);
00167 int cost = bDestFound ? m_pBestDestNode->m_cost : -1;
00168 int dist = bDestFound ? m_pBestDestNode->m_estimate - m_pBestDestNode->m_cost : -1;
00169
00170 DEBUG(yapf, 3, "[YAPF%c]%c%4d- %d us - %d rounds - %d open - %d closed - CHR %4.1f%% - C %d D %d - c%d(sc%d, ts%d, o%d) -- ",
00171 ttc, bDestFound ? '-' : '!', veh_idx, t, m_num_steps, m_nodes.OpenCount(), m_nodes.ClosedCount(),
00172 cache_hit_ratio, cost, dist, m_perf_cost.Get(1000000), m_perf_slope_cost.Get(1000000),
00173 m_perf_ts_cost.Get(1000000), m_perf_other_cost.Get(1000000)
00174 );
00175 }
00176 }
00177 #endif
00178 return bDestFound;
00179 }
00180
00185 inline Node *GetBestNode()
00186 {
00187 return (m_pBestDestNode != NULL) ? m_pBestDestNode : m_pBestIntermediateNode;
00188 }
00189
00194 inline Node& CreateNewNode()
00195 {
00196 Node& node = *m_nodes.CreateNewNode();
00197 return node;
00198 }
00199
00201 inline void AddStartupNode(Node& n)
00202 {
00203 Yapf().PfNodeCacheFetch(n);
00204
00205 if (m_nodes.FindOpenNode(n.m_key) == NULL) {
00206 m_nodes.InsertOpenNode(n);
00207 } else {
00208
00209
00210
00211 }
00212 }
00213
00215 inline void AddMultipleNodes(Node *parent, const TrackFollower &tf)
00216 {
00217 bool is_choice = (KillFirstBit(tf.m_new_td_bits) != TRACKDIR_BIT_NONE);
00218 for (TrackdirBits rtds = tf.m_new_td_bits; rtds != TRACKDIR_BIT_NONE; rtds = KillFirstBit(rtds)) {
00219 Trackdir td = (Trackdir)FindFirstBit2x64(rtds);
00220 Node& n = Yapf().CreateNewNode();
00221 n.Set(parent, tf.m_new_tile, td, is_choice);
00222 Yapf().AddNewNode(n, tf);
00223 }
00224 }
00225
00234 void PruneIntermediateNodeBranch()
00235 {
00236 while (Yapf().m_pBestIntermediateNode != NULL && (Yapf().m_pBestIntermediateNode->m_segment->m_end_segment_reason & ESRB_CHOICE_FOLLOWS) == 0) {
00237 Yapf().m_pBestIntermediateNode = Yapf().m_pBestIntermediateNode->m_parent;
00238 }
00239 }
00240
00245 void AddNewNode(Node &n, const TrackFollower &tf)
00246 {
00247
00248 bool bCached = Yapf().PfNodeCacheFetch(n);
00249 if (!bCached) {
00250 m_stats_cost_calcs++;
00251 } else {
00252 m_stats_cache_hits++;
00253 }
00254
00255 bool bValid = Yapf().PfCalcCost(n, &tf);
00256
00257 if (bCached) {
00258 Yapf().PfNodeCacheFlush(n);
00259 }
00260
00261 if (bValid) bValid = Yapf().PfCalcEstimate(n);
00262
00263
00264 if (!bValid) return;
00265
00266
00267 bool bDestination = Yapf().PfDetectDestination(n);
00268 if (bDestination) {
00269 if (m_pBestDestNode == NULL || n < *m_pBestDestNode) {
00270 m_pBestDestNode = &n;
00271 }
00272 m_nodes.FoundBestNode(n);
00273 return;
00274 }
00275
00276 if (m_max_search_nodes > 0 && (m_pBestIntermediateNode == NULL || (m_pBestIntermediateNode->GetCostEstimate() - m_pBestIntermediateNode->GetCost()) > (n.GetCostEstimate() - n.GetCost()))) {
00277 m_pBestIntermediateNode = &n;
00278 }
00279
00280
00281 Node *openNode = m_nodes.FindOpenNode(n.GetKey());
00282 if (openNode != NULL) {
00283
00284
00285 if (n.GetCostEstimate() < openNode->GetCostEstimate()) {
00286
00287 m_nodes.PopOpenNode(n.GetKey());
00288 *openNode = n;
00289
00290 m_nodes.InsertOpenNode(*openNode);
00291 }
00292 return;
00293 }
00294
00295
00296 Node *closedNode = m_nodes.FindClosedNode(n.GetKey());
00297 if (closedNode != NULL) {
00298
00299
00300 int node_est = n.GetCostEstimate();
00301 int closed_est = closedNode->GetCostEstimate();
00302 if (node_est < closed_est) {
00303
00304
00305
00306
00307
00308
00309 NOT_REACHED();
00310 }
00311 return;
00312 }
00313
00314
00315 m_nodes.InsertOpenNode(n);
00316 }
00317
00318 const VehicleType * GetVehicle() const
00319 {
00320 return m_veh;
00321 }
00322
00323 void DumpBase(DumpTarget &dmp) const
00324 {
00325 dmp.WriteStructT("m_nodes", &m_nodes);
00326 dmp.WriteLine("m_num_steps = %d", m_num_steps);
00327 }
00328
00329
00330
00331 #if 0
00332
00333 inline void PfSetStartupNodes()
00334 {
00335
00336 Node& n1 = *base::m_nodes.CreateNewNode();
00337 .
00338 .
00339 .
00340 base::m_nodes.InsertOpenNode(n1);
00341 }
00342
00344 inline void PfFollowNode(Node& org)
00345 {
00346 for (each follower of node org) {
00347 Node& n = *base::m_nodes.CreateNewNode();
00348 .
00349 .
00350 .
00351 n.m_parent = &org;
00352 AddNewNode(n);
00353 }
00354 }
00355
00357 inline bool PfCalcCost(Node& n)
00358 {
00359
00360 int cost = ...;
00361
00362 n.m_cost = n.m_parent->m_cost + cost;
00363 return true;
00364 }
00365
00367 inline bool PfCalcEstimate(Node& n)
00368 {
00369
00370 int distance = ...;
00371
00372 n.m_estimate = n.m_cost + distance;
00373 return true;
00374 }
00375
00377 inline bool PfDetectDestination(Node& n)
00378 {
00379 bool bDest = (n.m_key.m_x == m_x2) && (n.m_key.m_y == m_y2);
00380 return bDest;
00381 }
00382 #endif
00383 };
00384
00385 #endif