MegaGlest/source/glest_game/ai/node_pool.h

196 lines
8.0 KiB
C++

// ==============================================================
// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2009 James McCulloch <silnarm at gmail>
//
// You can redistribute this code and/or modify it under
// the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
//
// File: node_pool.h
//
#ifndef _GLEST_GAME_PATHFINDER_NODE_POOL_H_
#define _GLEST_GAME_PATHFINDER_NODE_POOL_H_
#include "vec.h"
#include "game_constants.h"
#include "heap.h"
#include "types.h"
#include <algorithm>
#include <set>
#include <list>
//#include <limits>
namespace Glest { namespace Game {
using Shared::Util::MinHeap;
using Shared::Graphics::Vec2i;
using namespace Shared::Platform;
#pragma pack(push, 4)
struct PosOff { /**< A bit packed position (Vec2i) and offset (direction) pair */
PosOff() : x(0), y(0), ox(0), oy(0) {} /**< Construct a PosOff [0,0] */
PosOff(Vec2i pos) : ox(0),oy(0) { *this = pos; } /**< Construct a PosOff [pos.x, pos.y] */
PosOff(int x, int y) : x(x) ,y(y) ,ox(0), oy(0) {} /**< Construct a PosOff [x,y] */
PosOff& operator=(Vec2i pos) { /**< Assign from Vec2i */
assert(pos.x <= 8191 && pos.y <= 8191);
x = pos.x; y = pos.y; return *this;
}
bool operator==(PosOff &p) const
{ return x == p.x && y == p.y; } /**< compare position components only */
Vec2i getPos() const { return Vec2i(x, y); } /**< this packed pos as Vec2i */
Vec2i getPrev() const { return Vec2i(x + ox, y + oy); } /**< return pos + offset */
Vec2i getOffset() const { return Vec2i(ox, oy); } /**< return offset */
bool hasOffset() const { return ox || oy; } /**< has an offset */
bool valid() const { return x >= 0 && y >= 0; } /**< is this position valid */
int32 x : 14; /**< x coordinate */
int32 y : 14; /**< y coordinate */
int32 ox : 2; /**< x offset */
int32 oy : 2; /**< y offset */
};
#pragma pack(pop)
// =====================================================
// struct AStarNode
// =====================================================
#pragma pack(push, 2)
struct AStarNode { /**< A node structure for A* with NodePool */
PosOff posOff; /**< position of this node, and direction of best path to it */
float heuristic; /**< estimate of distance to goal */
float distToHere; /**< cost from origin to this node */
float est() const { return distToHere + heuristic;} /**< estimate, costToHere + heuristic */
Vec2i pos() const { return posOff.getPos(); } /**< position of this node */
Vec2i prev() const { return posOff.getPrev(); } /**< best path to this node is from */
bool hasPrev() const{ return posOff.hasOffset(); } /**< has valid previous 'pointer' */
int32 heap_ndx;
void setHeapIndex(int ndx) { heap_ndx = ndx; }
int getHeapIndex() const { return heap_ndx; }
bool operator<(const AStarNode &that) const {
const float diff = est() - that.est();
if (diff < 0.f) return true;
if (diff > 0.f) return false;
// tie, prefer closer to goal...
const float h_diff = heuristic - that.heuristic;
if (h_diff < 0.f) return true;
if (h_diff > 0.f) return false;
// still tied... just distinguish them somehow...
return pos() < that.pos();
}
}; // == 128 bits (16 bytes)
#pragma pack(pop)
// ========================================================
// class NodePool
// ========================================================
class NodePool { /**< A NodeStorage class (template interface) for A* */
private:
static const int size = 512; /**< total number of AStarNodes in each pool */
AStarNode *stock; /**< The block of nodes */
int counter; /**< current counter */
// =====================================================
// struct MarkerArray
// =====================================================
/** An Marker & Pointer Array supporting two mark types, open and closed. */
///@todo replace pointers with indices, interleave mark and index arrays
struct MarkerArray {
private:
int stride; /**< stride of array */
unsigned int counter; /**< the counter */
unsigned int *marker; /**< the mark array */
AStarNode **pArray; /**< the pointer array */
public:
MarkerArray(int w, int h) : stride(w), counter(0) {
marker = new unsigned int[w * h];
memset(marker, 0, w * h * sizeof(unsigned int));
pArray = new AStarNode*[w * h];
memset(pArray, 0, w * h * sizeof(AStarNode*));
}
~MarkerArray() { delete [] marker; delete [] pArray; }
inline void newSearch() { counter += 2; }
inline void setOpen(const Vec2i &pos) { marker[pos.y * stride + pos.x] = counter; }
inline void setClosed(const Vec2i &pos) { marker[pos.y * stride + pos.x] = counter + 1; }
inline bool isOpen(const Vec2i &pos) { return marker[pos.y * stride + pos.x] == counter; }
inline bool isClosed(const Vec2i &pos) { return marker[pos.y * stride + pos.x] == counter + 1; }
inline bool isListed(const Vec2i &pos) { return marker[pos.y * stride + pos.x] >= counter; } /**< @deprecated not needed? */
inline void setNeither(const Vec2i &pos){ marker[pos.y * stride + pos.x] = 0; } /**< @deprecated not needed? */
inline void set(const Vec2i &pos, AStarNode *ptr) { pArray[pos.y * stride + pos.x] = ptr; } /**< set the pointer for pos to ptr */
inline AStarNode* get(const Vec2i &pos) { return pArray[pos.y * stride + pos.x]; } /**< get the pointer for pos */
};
private:
AStarNode *leastH; /**< The 'best' node seen so far this search */
int numNodes; /**< number of nodes used so far this search */
int tmpMaxNodes; /**< a temporary maximum number of nodes to use */
MarkerArray markerArray; /**< An array the size of the map, indicating node status (unvisited, open, closed) */
MinHeap<AStarNode> openHeap; /**< the open list, binary heap with index aware nodes */
public:
NodePool(int w, int h);
~NodePool();
// NodeStorage template interface
//
void setMaxNodes(const int max);
void reset();
bool isOpen(const Vec2i &pos) { return markerArray.isOpen(pos); } /**< test if a position is open */
bool isClosed(const Vec2i &pos) { return markerArray.isClosed(pos); } /**< test if a position is closed */
bool isListed(const Vec2i &pos) { return markerArray.isListed(pos); } /**< @deprecated needed for canPathOut() */
bool setOpen(const Vec2i &pos, const Vec2i &prev, float h, float d);
void updateOpen(const Vec2i &pos, const Vec2i &prev, const float cost);
/** get the best candidate from the open list, and close it.
* @return the lowest estimate node from the open list, or -1,-1 if open list empty */
Vec2i getBestCandidate() {
if (openHeap.empty()) {
return Vec2i(-1);
}
AStarNode *ptr = openHeap.extract();
markerArray.setClosed(ptr->pos());
return ptr->pos();
}
/** get the best heuristic node seen this search */
Vec2i getBestSeen() { return leastH->pos(); }
/** get the heuristic of the node at pos [known to be visited] */
float getHeuristicAt(const Vec2i &pos) { return markerArray.get(pos)->heuristic; }
/** get the cost to the node at pos [known to be visited] */
float getCostTo(const Vec2i &pos) { return markerArray.get(pos)->distToHere; }
/** get the estimate for the node at pos [known to be visited] */
float getEstimateFor(const Vec2i &pos) { return markerArray.get(pos)->est(); }
/** get the best path to the node at pos [known to be closed] */
Vec2i getBestTo(const Vec2i &pos) {
AStarNode *ptr = markerArray.get(pos);
assert(ptr);
return ptr->hasPrev() ? ptr->prev() : Vec2i(-1);
}
private:
void addOpenNode(AStarNode *node);
AStarNode* newNode() { return ( counter < size ? &stock[counter++] : NULL ); }
#if _GAE_DEBUG_EDITION_
public:
// interface to support debugging textures
list<Vec2i>* getOpenNodes();
list<Vec2i>* getClosedNodes();
list<Vec2i> listedNodes;
#endif
};
}}
#endif