diff --git a/external/vb01 b/external/vb01 index 8d7a886..9cd6604 160000 --- a/external/vb01 +++ b/external/vb01 @@ -1 +1 @@ -Subproject commit 8d7a88688c6ac93e9d40a181aded07351b848d77 +Subproject commit 9cd660454cc2b3d6bd988539848a08659c100a19 diff --git a/map.cpp b/map.cpp index a6d562f..25b63cb 100755 --- a/map.cpp +++ b/map.cpp @@ -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::generateAdjacentNodeEdges(int numVertCells, int i, int numHorCells, int j, int weight){ + vector 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)); } diff --git a/map.h b/map.h index 951ebc2..e0f8958 100755 --- a/map.h +++ b/map.h @@ -38,11 +38,11 @@ namespace battleship{ Cell(){} Cell(vb01::Vector3 p, Type t, std::vector e = std::vector{}, std::vector uc = std::vector{}): pos(p), type(t), edges(e), underWaterCellIds(uc){} - int getEdgeWeight(int); }; static Map* getSingleton(); ~Map(){} + static std::vector generateAdjacentNodeEdges(int, int, int, int, int); void update(); void load(std::string, bool = false); void unload(); diff --git a/mapEditorAppState.cpp b/mapEditorAppState.cpp index 4d44b4c..67df437 100644 --- a/mapEditorAppState.cpp +++ b/mapEditorAppState.cpp @@ -340,34 +340,7 @@ namespace battleship{ } } - vector 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 edges = Map::generateAdjacentNodeEdges(numVertCells, i, numHorCells, j, 1); cells.push_back(Map::Cell(pos, type, edges)); } diff --git a/pathfinder.cpp b/pathfinder.cpp index 7db4c59..fbe8f41 100644 --- a/pathfinder.cpp +++ b/pathfinder.cpp @@ -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> &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 Pathfinder::findPath(vector &cells, int source, int dest, int unitType){ int size = cells.size(); - u32 distances[size]; - vector paths[size]; - paths[source].push_back(source); + u32 distances[size]; + vector paths[size]; + paths[source].push_back(source); + vector> 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 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]; } } diff --git a/pathfinder.h b/pathfinder.h index de76f0b..a91d64b 100644 --- a/pathfinder.h +++ b/pathfinder.h @@ -8,17 +8,18 @@ #include namespace battleship{ - class Pathfinder{ - public: - static Pathfinder* getSingleton(); - std::vector findPath(std::vector&, 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 findPath(std::vector&, 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>&, vb01::u32[]); - vb01::u32 impassibleNodeVal; - }; + vb01::u32 impassibleNodeVal; + }; } #endif diff --git a/pathfinderTest.cpp b/pathfinderTest.cpp index a1f7779..ab46c25 100644 --- a/pathfinderTest.cpp +++ b/pathfinderTest.cpp @@ -1,6 +1,5 @@ #include "pathfinderTest.h" #include "pathfinder.h" -#include "map.h" #include @@ -10,35 +9,71 @@ namespace battleship{ using namespace std; using namespace vb01; + vector PathfinderTest::generateCellGraph(int numCellsOnSide){ + vector cells; + + for(int i = 0; i < numCellsOnSide; i++) + for(int j = 0; j < numCellsOnSide; j++){ + vector 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 &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 cells = vector{ + cells = vector{ Map::Cell(Vector3::VEC_ZERO, Map::Cell::Type::LAND, vector{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(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(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(0, 3, 3), Map::Edge(1, 3, 6)}), - Map::Cell(Vector3::VEC_ZERO, Map::Cell::Type::LAND, vector{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(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(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(0, 6, 6)}) }; - int size = cells.size(); const u16 INF = u16(0 - 1); pathfinder->setImpassibleNodeVal(INF); - vector path = pathfinder->findPath(cells, 0, size - 1); + + vector path = pathfinder->findPath(cells, 0, cells.size() - 1); CPPUNIT_ASSERT(path == vector({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(){} } diff --git a/pathfinderTest.h b/pathfinderTest.h index 2cc4f09..7a35ee1 100644 --- a/pathfinderTest.h +++ b/pathfinderTest.h @@ -4,22 +4,30 @@ #include #include +#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 cells; + + std::vector generateCellGraph(int); + int calcPathLength(std::vector&); + }; } #endif