mirror of
https://github.com/devZoGok/PlanetFleet.git
synced 2026-08-26 19:43:29 +00:00
Merge pull request #58 from devZoGok/imp-55-pathfinding
Imp 55 pathfinding
This commit is contained in:
Vendored
+1
-1
Submodule external/vb01 updated: 8d7a88688c...9cd660454c
@@ -22,17 +22,6 @@ using namespace gameBase;
|
||||
namespace battleship{
|
||||
using namespace configData;
|
||||
|
||||
//TODO check if edges have lower weight than impassible weight value for the Pathfinder
|
||||
int Map::Cell::getEdgeWeight(int destCellId){
|
||||
int weight = Pathfinder::getSingleton()->getImpassibleNodeVal();
|
||||
|
||||
for(Edge e : edges)
|
||||
if(e.destCellId == destCellId)
|
||||
weight = e.weight;
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
Map *map = nullptr;
|
||||
|
||||
Map* Map::getSingleton(){
|
||||
@@ -42,6 +31,37 @@ namespace battleship{
|
||||
return map;
|
||||
}
|
||||
|
||||
vector<Map::Edge> Map::generateAdjacentNodeEdges(int numVertCells, int i, int numHorCells, int j, int weight){
|
||||
vector<Map::Edge> edges;
|
||||
bool up = (i > 0), right = (j < numHorCells - 1), down = (i < numVertCells - 1), left = (j > 0);
|
||||
|
||||
if(left)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * i + j - 1));
|
||||
|
||||
if(right)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * i + j + 1));
|
||||
|
||||
if(up)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * (i - 1) + j));
|
||||
|
||||
if(down)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * (i + 1) + j));
|
||||
|
||||
if(up && left)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * (i - 1) + j - 1));
|
||||
|
||||
if(up && right)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * (i - 1) + j + 1));
|
||||
|
||||
if(down && left)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * (i + 1) + j - 1));
|
||||
|
||||
if(down && right)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * (i + 1) + j + 1));
|
||||
|
||||
return edges;
|
||||
}
|
||||
|
||||
void Map::update(){
|
||||
}
|
||||
|
||||
@@ -200,6 +220,7 @@ namespace battleship{
|
||||
cam->lookAt(Vector3(-1, -1, -1).norm(), Vector3(-1, 1, -1).norm());
|
||||
}
|
||||
|
||||
//TODO implement toggleable cell rendering
|
||||
void Map::loadCells(){
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
int numCells = SOL_LUA_VIEW[mapTable]["numCells"];
|
||||
@@ -230,7 +251,6 @@ namespace battleship{
|
||||
|
||||
Node *node = new Node(cellPos + Vector3::VEC_J * .1);
|
||||
node->attachMesh(quad);
|
||||
cellNode->attachChild(node);
|
||||
|
||||
cells.push_back(Cell(cellPos, cellType, edges, underWaterCellIds));
|
||||
}
|
||||
|
||||
@@ -38,11 +38,11 @@ namespace battleship{
|
||||
|
||||
Cell(){}
|
||||
Cell(vb01::Vector3 p, Type t, std::vector<Edge> e = std::vector<Edge>{}, std::vector<int> uc = std::vector<int>{}): pos(p), type(t), edges(e), underWaterCellIds(uc){}
|
||||
int getEdgeWeight(int);
|
||||
};
|
||||
|
||||
static Map* getSingleton();
|
||||
~Map(){}
|
||||
static std::vector<Edge> generateAdjacentNodeEdges(int, int, int, int, int);
|
||||
void update();
|
||||
void load(std::string, bool = false);
|
||||
void unload();
|
||||
|
||||
+1
-28
@@ -340,34 +340,7 @@ namespace battleship{
|
||||
}
|
||||
}
|
||||
|
||||
vector<Map::Edge> edges;
|
||||
int weight = 1;
|
||||
bool up = (i > 0), right = (j < numHorCells - 1), down = (i < numVertCells - 1), left = (j > 0);
|
||||
|
||||
if(left)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * i + j - 1));
|
||||
|
||||
if(right)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * i + j + 1));
|
||||
|
||||
if(up)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * (i - 1) + j));
|
||||
|
||||
if(down)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * (i + 1) + j));
|
||||
|
||||
if(up && left)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * (i - 1) + j - 1));
|
||||
|
||||
if(up && right)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * (i - 1) + j + 1));
|
||||
|
||||
if(down && left)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * (i + 1) + j - 1));
|
||||
|
||||
if(down && right)
|
||||
edges.push_back(Map::Edge(weight, numVertCells * i + j, numVertCells * (i + 1) + j + 1));
|
||||
|
||||
vector<Map::Edge> edges = Map::generateAdjacentNodeEdges(numVertCells, i, numHorCells, j, 1);
|
||||
cells.push_back(Map::Cell(pos, type, edges));
|
||||
}
|
||||
|
||||
|
||||
+46
-39
@@ -10,62 +10,69 @@ namespace battleship{
|
||||
static Pathfinder *pathfinder = nullptr;
|
||||
|
||||
Pathfinder* Pathfinder::getSingleton(){
|
||||
if(!pathfinder)
|
||||
pathfinder = new Pathfinder();
|
||||
if(!pathfinder)
|
||||
pathfinder = new Pathfinder();
|
||||
|
||||
return pathfinder;
|
||||
return pathfinder;
|
||||
}
|
||||
|
||||
Pathfinder::Pathfinder(){
|
||||
int Pathfinder::findMinDistVert(vector<pair<int, bool>> &cells, u32 distances[]){
|
||||
int numCells = cells.size(), minDistVert;
|
||||
|
||||
for(int i = 0; i < numCells; i++)
|
||||
if(!cells[i].second){
|
||||
minDistVert = i;
|
||||
break;
|
||||
}
|
||||
|
||||
for(int i = 0; i < numCells; i++){
|
||||
bool checked = cells[i].second;
|
||||
|
||||
if(!checked && distances[i] < distances[minDistVert])
|
||||
minDistVert = i;
|
||||
}
|
||||
|
||||
return minDistVert;
|
||||
}
|
||||
|
||||
vector<int> Pathfinder::findPath(vector<Map::Cell> &cells, int source, int dest, int unitType){
|
||||
int size = cells.size();
|
||||
u32 distances[size];
|
||||
vector<int> paths[size];
|
||||
paths[source].push_back(source);
|
||||
u32 distances[size];
|
||||
vector<int> paths[size];
|
||||
paths[source].push_back(source);
|
||||
vector<pair<int, bool>> cellsByCheck;
|
||||
|
||||
for(int i = 0; i < size; i++)
|
||||
distances[i] = (i == source ? 0 : impassibleNodeVal);
|
||||
for(int i = 0; i < size; i++){
|
||||
cellsByCheck.push_back(pair(i, false));
|
||||
distances[i] = (i == source ? 0 : impassibleNodeVal);
|
||||
}
|
||||
|
||||
vector<int> checkedNodes;
|
||||
while(!cellsByCheck[dest].second){
|
||||
int vertStrich = findMinDistVert(cellsByCheck, distances);
|
||||
cellsByCheck[vertStrich].second = true;
|
||||
|
||||
while(find(checkedNodes.begin(), checkedNodes.end(), dest) == checkedNodes.end()){
|
||||
bool initVertStrichSet = false;
|
||||
int vertStrich;
|
||||
int numEdges = cells[vertStrich].edges.size();
|
||||
|
||||
for(int i = 0; i < size; i++){
|
||||
bool isChecked = find(checkedNodes.begin(), checkedNodes.end(), i) != checkedNodes.end();
|
||||
for(int i = 0; i < numEdges; i++){
|
||||
bool canMoveToStrichCell = true;
|
||||
bool ship = ((UnitType)unitType == UnitType::UNDERWATER || (UnitType)unitType == UnitType::SEA_LEVEL);
|
||||
|
||||
if(!isChecked){
|
||||
if(!initVertStrichSet){
|
||||
vertStrich = i;
|
||||
initVertStrichSet = true;
|
||||
}
|
||||
if((ship && cells[vertStrich].type != Map::Cell::WATER) || ((UnitType)unitType == UnitType::LAND && cells[vertStrich].type != Map::Cell::LAND))
|
||||
canMoveToStrichCell = false;
|
||||
|
||||
if(initVertStrichSet && (distances[vertStrich] > distances[i]))
|
||||
vertStrich = i;
|
||||
}
|
||||
}
|
||||
if(canMoveToStrichCell){
|
||||
int edgeNode = cells[vertStrich].edges[i].destCellId;
|
||||
bool isChecked = cellsByCheck[edgeNode].second;
|
||||
|
||||
checkedNodes.push_back(vertStrich);
|
||||
|
||||
for(int i = 0; i < size; i++){
|
||||
bool isChecked = find(checkedNodes.begin(), checkedNodes.end(), i) != checkedNodes.end();
|
||||
bool canMoveToStrichCell = true;
|
||||
bool ship = ((UnitType)unitType == UnitType::UNDERWATER || (UnitType)unitType == UnitType::SEA_LEVEL);
|
||||
|
||||
if((ship && cells[vertStrich].type != Map::Cell::WATER) || ((UnitType)unitType == UnitType::LAND && cells[vertStrich].type != Map::Cell::LAND))
|
||||
canMoveToStrichCell = false;
|
||||
|
||||
if(!isChecked && (canMoveToStrichCell && distances[vertStrich] + cells[vertStrich].getEdgeWeight(i) < distances[i])){
|
||||
distances[i] = distances[vertStrich] + cells[vertStrich].getEdgeWeight(i);
|
||||
paths[i] = paths[vertStrich];
|
||||
paths[i].push_back(i);
|
||||
if(!isChecked && (distances[vertStrich] + cells[vertStrich].edges[i].weight < distances[edgeNode])){
|
||||
distances[edgeNode] = distances[vertStrich] + cells[vertStrich].edges[i].weight;
|
||||
paths[edgeNode] = paths[vertStrich];
|
||||
paths[edgeNode].push_back(edgeNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paths[dest];
|
||||
return paths[dest];
|
||||
}
|
||||
}
|
||||
|
||||
+11
-10
@@ -8,17 +8,18 @@
|
||||
#include <util.h>
|
||||
|
||||
namespace battleship{
|
||||
class Pathfinder{
|
||||
public:
|
||||
static Pathfinder* getSingleton();
|
||||
std::vector<int> findPath(std::vector<Map::Cell>&, int, int, int = -1);
|
||||
inline vb01::u32 getImpassibleNodeVal(){return impassibleNodeVal;}
|
||||
inline void setImpassibleNodeVal(vb01::u32 val){this->impassibleNodeVal = val;}
|
||||
private:
|
||||
Pathfinder();
|
||||
class Pathfinder{
|
||||
public:
|
||||
static Pathfinder* getSingleton();
|
||||
std::vector<int> findPath(std::vector<Map::Cell>&, int, int, int = -1);
|
||||
inline vb01::u32 getImpassibleNodeVal(){return impassibleNodeVal;}
|
||||
inline void setImpassibleNodeVal(vb01::u32 val){this->impassibleNodeVal = val;}
|
||||
private:
|
||||
Pathfinder(){}
|
||||
int findMinDistVert(std::vector<std::pair<int, bool>>&, vb01::u32[]);
|
||||
|
||||
vb01::u32 impassibleNodeVal;
|
||||
};
|
||||
vb01::u32 impassibleNodeVal;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+48
-13
@@ -1,6 +1,5 @@
|
||||
#include "pathfinderTest.h"
|
||||
#include "pathfinder.h"
|
||||
#include "map.h"
|
||||
|
||||
#include <util.h>
|
||||
|
||||
@@ -10,35 +9,71 @@ namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
|
||||
vector<Map::Cell> PathfinderTest::generateCellGraph(int numCellsOnSide){
|
||||
vector<Map::Cell> cells;
|
||||
|
||||
for(int i = 0; i < numCellsOnSide; i++)
|
||||
for(int j = 0; j < numCellsOnSide; j++){
|
||||
vector<Map::Edge> edges = Map::generateAdjacentNodeEdges(numCellsOnSide, i, numCellsOnSide, j, 1);
|
||||
cells.push_back(Map::Cell(Vector3::VEC_ZERO, Map::Cell::Type::LAND, edges));
|
||||
}
|
||||
|
||||
return cells;
|
||||
}
|
||||
|
||||
int PathfinderTest::calcPathLength(vector<int> &path){
|
||||
int sumPathWeights = 0;
|
||||
|
||||
for(int i = 0; i < path.size() - 1; i++)
|
||||
for(int j = 0; j < cells[path[i]].edges.size(); j++)
|
||||
if(cells[path[i]].edges[j].destCellId == path[i + 1])
|
||||
sumPathWeights += cells[path[i]].edges[j].weight;
|
||||
|
||||
return sumPathWeights;
|
||||
}
|
||||
|
||||
void PathfinderTest::testFindPath(){
|
||||
vector<Map::Cell> cells = vector<Map::Cell>{
|
||||
cells = vector<Map::Cell>{
|
||||
Map::Cell(Vector3::VEC_ZERO, Map::Cell::Type::LAND, vector<Map::Edge>{Map::Edge(0, 0, 0), Map::Edge(2, 0, 1), Map::Edge(4, 0, 2)}),
|
||||
Map::Cell(Vector3::VEC_ZERO, Map::Cell::Type::LAND, vector<Map::Edge>{Map::Edge(0, 1, 1), Map::Edge(1, 1, 2), Map::Edge(9, 1, 3), Map::Edge(13, 1, 4)}),
|
||||
Map::Cell(Vector3::VEC_ZERO, Map::Cell::Type::LAND, vector<Map::Edge>{Map::Edge(0, 2, 2), Map::Edge(2, 2, 1), Map::Edge(4, 2, 4), Map::Edge(5, 2, 5)}),
|
||||
Map::Cell(Vector3::VEC_ZERO, Map::Cell::Type::LAND, vector<Map::Edge>{Map::Edge(0, 3, 3), Map::Edge(1, 3, 6)}),
|
||||
Map::Cell(Vector3::VEC_ZERO, Map::Cell::Type::LAND, vector<Map::Edge>{Map::Edge(0, 4, 4), Map::Edge(1, 4, 0), Map::Edge(1, 4, 3), Map::Edge(3, 4, 6)}),
|
||||
Map::Cell(Vector3::VEC_ZERO, Map::Cell::Type::LAND, vector<Map::Edge>{Map::Edge(0, 4, 4), Map::Edge(1, 4, 1), Map::Edge(1, 4, 3), Map::Edge(2, 4, 5), Map::Edge(3, 4, 6)}),
|
||||
Map::Cell(Vector3::VEC_ZERO, Map::Cell::Type::LAND, vector<Map::Edge>{Map::Edge(0, 5, 5), Map::Edge(9, 5, 4), Map::Edge(2, 5, 6)}),
|
||||
Map::Cell(Vector3::VEC_ZERO, Map::Cell::Type::LAND, vector<Map::Edge>{Map::Edge(0, 6, 6)})
|
||||
};
|
||||
|
||||
int size = cells.size();
|
||||
const u16 INF = u16(0 - 1);
|
||||
pathfinder->setImpassibleNodeVal(INF);
|
||||
vector<int> path = pathfinder->findPath(cells, 0, size - 1);
|
||||
|
||||
vector<int> path = pathfinder->findPath(cells, 0, cells.size() - 1);
|
||||
CPPUNIT_ASSERT(path == vector<int>({0, 1, 2, 4, 3, 6}));
|
||||
|
||||
int sumPathWeights = 0;
|
||||
|
||||
for(int i = 1; i < path.size(); i++)
|
||||
sumPathWeights += cells[path[i - 1]].getEdgeWeight(path[i]);
|
||||
|
||||
int sumPathWeights = calcPathLength(path);
|
||||
CPPUNIT_ASSERT(sumPathWeights == 9);
|
||||
}
|
||||
|
||||
void PathfinderTest::setUp(){
|
||||
pathfinder = Pathfinder::getSingleton();
|
||||
void PathfinderTest::testFindBigPath(){
|
||||
int numIterations = 1;
|
||||
cells = generateCellGraph(60);
|
||||
s64 sumTime = 0;
|
||||
|
||||
for(int i = 0; i < numIterations; i++){
|
||||
s64 t0 = getTime();
|
||||
pathfinder->findPath(cells, 0, cells.size() - 1);
|
||||
s64 t1 = getTime();
|
||||
sumTime += t1 - t0;
|
||||
}
|
||||
|
||||
int threshold = 100;
|
||||
double avg = (double)sumTime / numIterations, eps = .1;
|
||||
cout << "Total time: " << sumTime << endl;
|
||||
CPPUNIT_ASSERT(sumTime <= threshold);
|
||||
}
|
||||
|
||||
void PathfinderTest::tearDown(){
|
||||
void PathfinderTest::setUp(){
|
||||
pathfinder = Pathfinder::getSingleton();
|
||||
}
|
||||
|
||||
void PathfinderTest::tearDown(){}
|
||||
}
|
||||
|
||||
+21
-13
@@ -4,22 +4,30 @@
|
||||
#include <cppunit/TestFixture.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
#include "map.h"
|
||||
|
||||
namespace battleship{
|
||||
class Pathfinder;
|
||||
class Pathfinder;
|
||||
|
||||
class PathfinderTest : public CppUnit::TestFixture{
|
||||
CPPUNIT_TEST_SUITE(PathfinderTest);
|
||||
CPPUNIT_TEST(testFindPath);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
class PathfinderTest : public CppUnit::TestFixture{
|
||||
CPPUNIT_TEST_SUITE(PathfinderTest);
|
||||
CPPUNIT_TEST(testFindPath);
|
||||
CPPUNIT_TEST(testFindBigPath);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
PathfinderTest(){}
|
||||
void testFindPath();
|
||||
void setUp();
|
||||
void tearDown();
|
||||
private:
|
||||
Pathfinder *pathfinder = nullptr;
|
||||
};
|
||||
public:
|
||||
PathfinderTest(){}
|
||||
void testFindPath();
|
||||
void testFindBigPath();
|
||||
void setUp();
|
||||
void tearDown();
|
||||
private:
|
||||
Pathfinder *pathfinder = nullptr;
|
||||
std::vector<Map::Cell> cells;
|
||||
|
||||
std::vector<Map::Cell> generateCellGraph(int);
|
||||
int calcPathLength(std::vector<int>&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user