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  PathNode() = default;
155  PathNode(const PathNode &) = delete;
156  PathNode(PathNode &&) = delete;
157  PathNode &operator=(const PathNode &) = delete;
158  PathNode &operator=(PathNode &&) = delete;
159 
160  void Init( unsigned _frame,
161  void* _state,
162  float _costFromStart,
163  float _estToGoal,
164  PathNode* _parent );
165 
166  void Clear();
167  void InitSentinel() {
168  Clear();
169  Init( 0, 0, FLT_MAX, FLT_MAX, 0 );
170  prev = next = this;
171  }
172 
173  void *state; // the client state
174  float costFromStart; // exact
175  float estToGoal; // estimated
176  float totalCost; // could be a function, but save some math.
177  PathNode* parent; // the parent is used to reconstruct the path
178  unsigned frame; // unique id for this path, so the solver can distinguish
179  // correct from stale values
180 
181  int numAdjacent; // -1 is unknown & needs to be queried
182  int cacheIndex; // position in cache
183 
184  PathNode *child[2]; // Binary search in the hash table. [left, right]
185  PathNode *next, *prev; // used by open queue
186 
187  bool inOpen;
188  bool inClosed;
189 
190  void Unlink() {
191  next->prev = prev;
192  prev->next = next;
193  next = prev = 0;
194  }
195  void AddBefore( PathNode* addThis ) {
196  addThis->next = this;
197  addThis->prev = prev;
198  prev->next = addThis;
199  prev = addThis;
200  }
201 #ifdef TETRAEDGE_MICROPATHER_DEBUG
202  void CheckList()
203  {
204  MPASSERT( totalCost == FLT_MAX );
205  for( PathNode* it = next; it != this; it=it->next ) {
206  MPASSERT( it->prev == this || it->totalCost >= it->prev->totalCost );
207  MPASSERT( it->totalCost <= it->next->totalCost );
208  }
209  }
210 #endif
211 
212  void CalcTotalCost() {
213  if ( costFromStart < FLT_MAX && estToGoal < FLT_MAX )
214  totalCost = costFromStart + estToGoal;
215  else
216  totalCost = FLT_MAX;
217  }
218  };
219 
220 
221  /* Memory manager for the PathNodes. */
223  {
224  public:
225  PathNodePool( unsigned allocate, unsigned typicalAdjacent );
226  ~PathNodePool();
227 
228  // Free all the memory except the first block. Resets all memory.
229  void Clear();
230 
231  // Essentially:
232  // pNode = Find();
233  // if ( !pNode )
234  // pNode = New();
235  //
236  // Get the PathNode associated with this state. If the PathNode already
237  // exists (allocated and is on the current frame), it will be returned.
238  // Else a new PathNode is allocated and returned. The returned object
239  // is always fully initialized.
240  //
241  // NOTE: if the pathNode exists (and is current) all the initialization
242  // parameters are ignored.
243  PathNode* GetPathNode( unsigned frame,
244  void* _state,
245  float _costFromStart,
246  float _estToGoal,
247  PathNode* _parent );
248 
249  // Get a pathnode that is already in the pool.
250  PathNode* FetchPathNode( void* state );
251 
252  // Store stuff in cache
253  bool PushCache( const NodeCost* nodes, int nNodes, int* start );
254 
255  // Get neighbors from the cache
256  // Note - always access this with an offset. Can get re-allocated.
257  void GetCache( int start, int nNodes, NodeCost* nodes );
258 
259  // Return all the allocated states. Useful for visuallizing what
260  // the pather is doing.
261  void AllStates( unsigned frame, Common::Array< void* >* stateVec );
262 
263  private:
264  struct Block
265  {
266  Block* nextBlock;
267  PathNode pathNode[1];
268  };
269 
270  unsigned Hash( void* voidval );
271  unsigned HashSize() const { return 1<<hashShift; }
272  unsigned HashMask() const { return ((1<<hashShift)-1); }
273  void AddPathNode( unsigned key, PathNode* p );
274  Block* NewBlock();
275  PathNode* Alloc();
276 
277  PathNode** hashTable;
278  Block* firstBlock;
279  Block* blocks;
280 
281  NodeCost* cache;
282  int cacheCap;
283  int cacheSize;
284 
285  PathNode freeMemSentinel;
286  unsigned allocate; // how big a block of pathnodes to allocate at once
287  unsigned nAllocated; // number of pathnodes allocated (from Alloc())
288  unsigned nAvailable; // number available for allocation
289 
290  unsigned hashShift;
291  unsigned totalCollide;
292  };
293 
294 
295  /* Used to cache results of paths. Much, much faster
296  to return an existing solution than to calculate
297  a new one. A post on this is here:
298  https://web.archive.org/web/20170714084918/http://grinninglizard.com/altera/programming/a-path-caching-2/
299  */
300  class PathCache
301  {
302  public:
303  struct Item {
304  // The key:
305  void* start;
306  void* end;
307 
308  bool KeyEqual( const Item& item ) const { return start == item.start && end == item.end; }
309  bool Empty() const { return start == 0 && end == 0; }
310 
311  // Data:
312  void* next;
313  float cost; // from 'start' to 'next'. FLT_MAX if unsolveable.
314 
315  unsigned Hash() const {
316  const unsigned char *p = (const unsigned char *)(&start);
317  uint h = 2166136261U;
318 
319  for( unsigned i=0; i<sizeof(void*)*2; ++i, ++p ) {
320  h ^= *p;
321  h *= 16777619;
322  }
323  return h;
324  }
325  };
326 
327  PathCache( int itemsToAllocate );
328  ~PathCache();
329 
330  void Reset();
331  void Add( const Common::Array< void* >& path, const Common::Array< float >& cost );
332  void AddNoSolution( void* end, void* states[], int count );
333  int Solve( void* startState, void* endState, Common::Array< void* >* path, float* totalCost );
334 
335  int AllocatedBytes() const { return allocated * sizeof(Item); }
336  int UsedBytes() const { return nItems * sizeof(Item); }
337 
338  int hit;
339  int miss;
340 
341  private:
342  void AddItem( const Item& item );
343  const Item* Find( void* start, void* end );
344 
345  Item* mem;
346  int allocated;
347  int nItems;
348  };
349 
350  struct CacheData {
351  CacheData() { reset(); }
352 
353  int nBytesAllocated;
354  int nBytesUsed;
355  float memoryFraction;
356 
357  int hit;
358  int miss;
359  float hitFraction;
360 
361  void reset() {
362  nBytesAllocated = 0;
363  nBytesUsed = 0;
364  memoryFraction = 0;
365 
366  hit = 0;
367  miss = 0;
368  hitFraction = 0;
369  }
370  };
371 
377  {
378  friend class micropather::PathNode;
379 
380  public:
381  enum
382  {
383  SOLVED,
384  NO_SOLUTION,
385  START_END_SAME,
386 
387  // internal
388  NOT_CACHED
389  };
390 
414  MicroPather( Graph* graph, unsigned allocate = 250, unsigned typicalAdjacent=6, bool cache=true );
415  ~MicroPather();
416 
426  int Solve( void* startState, void* endState, Common::Array< void* >* path, float* totalCost );
427 
437  int SolveForNearStates( void* startState, Common::Array< StateCost >* near, float maxCost );
438 
442  void Reset();
443 
444  // Debugging function to return all states that were used by the last "solve"
445  void StatesInPool( Common::Array< void* >* stateVec );
446  void GetCacheData( CacheData* data );
447 
448  private:
449  MicroPather( const MicroPather& ); // undefined and unsupported
450  void operator=( const MicroPather ); // undefined and unsupported
451 
452  void GoalReached( PathNode* node, void* start, void* end, Common::Array< void* > *path );
453 
454  void GetNodeNeighbors( PathNode* node, Common::Array< NodeCost >* neighborNode );
455 
456 #ifdef TETRAEDGE_MICROPATHER_DEBUG
457  void DumpStats();
458 #endif
459 
460  PathNodePool pathNodePool;
461  Common::Array< StateCost > stateCostVec; // local to Solve, but put here to reduce memory allocation
462  Common::Array< NodeCost > nodeCostVec; // local to Solve, but put here to reduce memory allocation
463  Common::Array< float > costVec;
464 
465  Graph* graph;
466  unsigned frame; // incremented with every solve, used to determine if cached data needs to be refreshed
467  PathCache* pathCache;
468  };
469 
470 } // namespace micropather
471 
472 } // namespace Tetraedge
473 
474 #endif // TETRAEDGE_TE_MICROPATHER
475 
Definition: detection.h:27
Definition: micropather.h:376
Definition: array.h:52
float cost
The cost to the state. Use FLT_MAX for infinite cost.
Definition: micropather.h:90
Definition: micropather.h:222
Definition: micropather.h:87
Definition: micropather.h:151
void * state
The state as a void*.
Definition: micropather.h:89
Definition: micropather.h:303
Definition: micropather.h:350
Definition: micropather.h:300
Definition: micropather.h:140
Definition: micropather.h:108