ScummVM API documentation
micropather.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 /*
23 
24 This is a lightly modified version of MicroPather, from
25 github.com/leethomason/MicroPather. Modifications were made to fit with
26 ScummVM coding style and APIs.
27 
28 The original copyright message is:
29 
30 -------
31 
32 Copyright (c) 2000-2013 Lee Thomason (www.grinninglizard.com)
33 Micropather
34 
35 This software is provided 'as-is', without any express or implied
36 warranty. In no event will the authors be held liable for any
37 damages arising from the use of this software.
38 
39 Permission is granted to anyone to use this software for any
40 purpose, including commercial applications, and to alter it and
41 redistribute it freely, subject to the following restrictions:
42 
43 1. The origin of this software must not be misrepresented; you must
44 not claim that you wrote the original software. If you use this
45 software in a product, an acknowledgment in the product documentation
46 would be appreciated but is not required.
47 
48 2. Altered source versions must be plainly marked as such, and
49 must not be misrepresented as being the original software.
50 
51 3. This notice may not be removed or altered from any source
52 distribution.
53 */
54 
55 
56 #ifndef TETRAEDGE_TE_MICROPATHER
57 #define TETRAEDGE_TE_MICROPATHER
58 
59 #include "common/array.h"
60 #include "common/util.h"
61 #include "common/types.h"
62 #include "math/utils.h"
63 
64 
73 namespace Tetraedge
74 {
75 
76 namespace micropather
77 {
78 
79  typedef uintptr MP_UPTR;
80 
87  struct StateCost
88  {
89  void* state;
90  float cost;
91  };
92 
93 
108  class Graph
109  {
110  public:
111  virtual ~Graph() {}
112 
119  virtual float LeastCostEstimate( void* stateStart, void* stateEnd ) = 0;
120 
127  virtual void AdjacentCost( void* state, Common::Array< micropather::StateCost > *adjacent ) = 0;
128 
134  virtual void PrintStateInfo( void* state ) = 0;
135  };
136 
137 
138  class PathNode;
139 
140  struct NodeCost
141  {
142  PathNode* node;
143  float cost;
144  };
145 
146 
147  /*
148  Every state (void*) is represented by a PathNode in MicroPather. There
149  can only be one PathNode for a given state.
150  */
151  class PathNode
152  {
153  public:
154  void Init( unsigned _frame,
155  void* _state,
156  float _costFromStart,
157  float _estToGoal,
158  PathNode* _parent );
159 
160  void Clear();
161  void InitSentinel() {
162  Clear();
163  Init( 0, 0, FLT_MAX, FLT_MAX, 0 );
164  prev = next = this;
165  }
166 
167  void *state; // the client state
168  float costFromStart; // exact
169  float estToGoal; // estimated
170  float totalCost; // could be a function, but save some math.
171  PathNode* parent; // the parent is used to reconstruct the path
172  unsigned frame; // unique id for this path, so the solver can distinguish
173  // correct from stale values
174 
175  int numAdjacent; // -1 is unknown & needs to be queried
176  int cacheIndex; // position in cache
177 
178  PathNode *child[2]; // Binary search in the hash table. [left, right]
179  PathNode *next, *prev; // used by open queue
180 
181  bool inOpen;
182  bool inClosed;
183 
184  void Unlink() {
185  next->prev = prev;
186  prev->next = next;
187  next = prev = 0;
188  }
189  void AddBefore( PathNode* addThis ) {
190  addThis->next = this;
191  addThis->prev = prev;
192  prev->next = addThis;
193  prev = addThis;
194  }
195 #ifdef TETRAEDGE_MICROPATHER_DEBUG
196  void CheckList()
197  {
198  MPASSERT( totalCost == FLT_MAX );
199  for( PathNode* it = next; it != this; it=it->next ) {
200  MPASSERT( it->prev == this || it->totalCost >= it->prev->totalCost );
201  MPASSERT( it->totalCost <= it->next->totalCost );
202  }
203  }
204 #endif
205 
206  void CalcTotalCost() {
207  if ( costFromStart < FLT_MAX && estToGoal < FLT_MAX )
208  totalCost = costFromStart + estToGoal;
209  else
210  totalCost = FLT_MAX;
211  }
212 
213  private:
214 
215  void operator=( const PathNode& );
216  };
217 
218 
219  /* Memory manager for the PathNodes. */
221  {
222  public:
223  PathNodePool( unsigned allocate, unsigned typicalAdjacent );
224  ~PathNodePool();
225 
226  // Free all the memory except the first block. Resets all memory.
227  void Clear();
228 
229  // Essentially:
230  // pNode = Find();
231  // if ( !pNode )
232  // pNode = New();
233  //
234  // Get the PathNode associated with this state. If the PathNode already
235  // exists (allocated and is on the current frame), it will be returned.
236  // Else a new PathNode is allocated and returned. The returned object
237  // is always fully initialized.
238  //
239  // NOTE: if the pathNode exists (and is current) all the initialization
240  // parameters are ignored.
241  PathNode* GetPathNode( unsigned frame,
242  void* _state,
243  float _costFromStart,
244  float _estToGoal,
245  PathNode* _parent );
246 
247  // Get a pathnode that is already in the pool.
248  PathNode* FetchPathNode( void* state );
249 
250  // Store stuff in cache
251  bool PushCache( const NodeCost* nodes, int nNodes, int* start );
252 
253  // Get neighbors from the cache
254  // Note - always access this with an offset. Can get re-allocated.
255  void GetCache( int start, int nNodes, NodeCost* nodes );
256 
257  // Return all the allocated states. Useful for visuallizing what
258  // the pather is doing.
259  void AllStates( unsigned frame, Common::Array< void* >* stateVec );
260 
261  private:
262  struct Block
263  {
264  Block* nextBlock;
265  PathNode pathNode[1];
266  };
267 
268  unsigned Hash( void* voidval );
269  unsigned HashSize() const { return 1<<hashShift; }
270  unsigned HashMask() const { return ((1<<hashShift)-1); }
271  void AddPathNode( unsigned key, PathNode* p );
272  Block* NewBlock();
273  PathNode* Alloc();
274 
275  PathNode** hashTable;
276  Block* firstBlock;
277  Block* blocks;
278 
279  NodeCost* cache;
280  int cacheCap;
281  int cacheSize;
282 
283  PathNode freeMemSentinel;
284  unsigned allocate; // how big a block of pathnodes to allocate at once
285  unsigned nAllocated; // number of pathnodes allocated (from Alloc())
286  unsigned nAvailable; // number available for allocation
287 
288  unsigned hashShift;
289  unsigned totalCollide;
290  };
291 
292 
293  /* Used to cache results of paths. Much, much faster
294  to return an existing solution than to calculate
295  a new one. A post on this is here:
296  https://web.archive.org/web/20170714084918/http://grinninglizard.com/altera/programming/a-path-caching-2/
297  */
298  class PathCache
299  {
300  public:
301  struct Item {
302  // The key:
303  void* start;
304  void* end;
305 
306  bool KeyEqual( const Item& item ) const { return start == item.start && end == item.end; }
307  bool Empty() const { return start == 0 && end == 0; }
308 
309  // Data:
310  void* next;
311  float cost; // from 'start' to 'next'. FLT_MAX if unsolveable.
312 
313  unsigned Hash() const {
314  const unsigned char *p = (const unsigned char *)(&start);
315  uint h = 2166136261U;
316 
317  for( unsigned i=0; i<sizeof(void*)*2; ++i, ++p ) {
318  h ^= *p;
319  h *= 16777619;
320  }
321  return h;
322  }
323  };
324 
325  PathCache( int itemsToAllocate );
326  ~PathCache();
327 
328  void Reset();
329  void Add( const Common::Array< void* >& path, const Common::Array< float >& cost );
330  void AddNoSolution( void* end, void* states[], int count );
331  int Solve( void* startState, void* endState, Common::Array< void* >* path, float* totalCost );
332 
333  int AllocatedBytes() const { return allocated * sizeof(Item); }
334  int UsedBytes() const { return nItems * sizeof(Item); }
335 
336  int hit;
337  int miss;
338 
339  private:
340  void AddItem( const Item& item );
341  const Item* Find( void* start, void* end );
342 
343  Item* mem;
344  int allocated;
345  int nItems;
346  };
347 
348  struct CacheData {
349  CacheData() { reset(); }
350 
351  int nBytesAllocated;
352  int nBytesUsed;
353  float memoryFraction;
354 
355  int hit;
356  int miss;
357  float hitFraction;
358 
359  void reset() {
360  nBytesAllocated = 0;
361  nBytesUsed = 0;
362  memoryFraction = 0;
363 
364  hit = 0;
365  miss = 0;
366  hitFraction = 0;
367  }
368  };
369 
375  {
376  friend class micropather::PathNode;
377 
378  public:
379  enum
380  {
381  SOLVED,
382  NO_SOLUTION,
383  START_END_SAME,
384 
385  // internal
386  NOT_CACHED
387  };
388 
412  MicroPather( Graph* graph, unsigned allocate = 250, unsigned typicalAdjacent=6, bool cache=true );
413  ~MicroPather();
414 
424  int Solve( void* startState, void* endState, Common::Array< void* >* path, float* totalCost );
425 
435  int SolveForNearStates( void* startState, Common::Array< StateCost >* near, float maxCost );
436 
440  void Reset();
441 
442  // Debugging function to return all states that were used by the last "solve"
443  void StatesInPool( Common::Array< void* >* stateVec );
444  void GetCacheData( CacheData* data );
445 
446  private:
447  MicroPather( const MicroPather& ); // undefined and unsupported
448  void operator=( const MicroPather ); // undefined and unsupported
449 
450  void GoalReached( PathNode* node, void* start, void* end, Common::Array< void* > *path );
451 
452  void GetNodeNeighbors( PathNode* node, Common::Array< NodeCost >* neighborNode );
453 
454 #ifdef TETRAEDGE_MICROPATHER_DEBUG
455  void DumpStats();
456 #endif
457 
458  PathNodePool pathNodePool;
459  Common::Array< StateCost > stateCostVec; // local to Solve, but put here to reduce memory allocation
460  Common::Array< NodeCost > nodeCostVec; // local to Solve, but put here to reduce memory allocation
461  Common::Array< float > costVec;
462 
463  Graph* graph;
464  unsigned frame; // incremented with every solve, used to determine if cached data needs to be refreshed
465  PathCache* pathCache;
466  };
467 
468 } // namespace micropather
469 
470 } // namespace Tetraedge
471 
472 #endif // TETRAEDGE_TE_MICROPATHER
473 
Definition: detection.h:27
Definition: micropather.h:374
Definition: array.h:52
float cost
The cost to the state. Use FLT_MAX for infinite cost.
Definition: micropather.h:90
Definition: micropather.h:220
Definition: micropather.h:87
Definition: micropather.h:151
void * state
The state as a void*.
Definition: micropather.h:89
Definition: micropather.h:301
Definition: micropather.h:348
Definition: micropather.h:298
Definition: micropather.h:140
Definition: micropather.h:108