Skip to content

Commit 9585071

Browse files
committed
Breadth first search.
1 parent 011a321 commit 9585071

File tree

3 files changed

+97
-69
lines changed

3 files changed

+97
-69
lines changed

game/game.cpp

Lines changed: 89 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -787,8 +787,7 @@ void CGame::GraphReset()
787787
{
788788
m_eGraphStep = GRAPHSTEP_PUSHTOSTACK;
789789
m_aiNodeStack.clear();
790-
m_iTestNode = ~0;
791-
m_iTestEdge = ~0;
790+
m_aiPathStack.clear();
792791

793792
m_Graph = CGraph();
794793

@@ -822,66 +821,66 @@ void CGame::GraphStep()
822821
if (m_eGraphStep == GRAPHSTEP_PUSHTOSTACK)
823822
{
824823
m_aiNodeStack.push_back(0);
825-
m_eGraphStep = GRAPHSTEP_MARKSEEN;
824+
m_Graph.GetNode(m_aiNodeStack[0])->seen = true;
825+
m_eGraphStep = GRAPHSTEP_PUSHNEIGHBORS;
826826
}
827-
else if (m_eGraphStep == GRAPHSTEP_MARKSEEN)
827+
else if (m_eGraphStep == GRAPHSTEP_PUSHNEIGHBORS)
828828
{
829-
m_Graph.GetNode(m_aiNodeStack.back())->seen = true;
829+
CGraph::CNode* current_node = m_Graph.GetNode(m_aiNodeStack.front());
830830

831-
m_iTestEdge = 0;
831+
size_t i;
832+
for (i = 0; i < current_node->edges.size(); i++)
833+
{
834+
edge_t edge = current_node->edges[i];
832835

833-
m_eGraphStep = GRAPHSTEP_FOLLOWEDGES;
834-
}
835-
else if (m_eGraphStep == GRAPHSTEP_FOLLOWEDGES)
836-
{
837-
CGraph::CNode* current_node = m_Graph.GetNode(m_aiNodeStack.back());
836+
node_t test_node = m_Graph.FollowEdge(m_aiNodeStack.front(), edge);
838837

839-
if ((size_t)m_iTestEdge >= current_node->edges.size())
840-
{
841-
// We've run out of edges. There are no unseen nodes! We should go back.
842-
m_eGraphStep = GRAPHSTEP_POPNODE;
843-
return;
844-
}
838+
if (m_Graph.GetNode(test_node) == m_pTargetNode)
839+
{
840+
// We found it! Stash our data for the reconstruct step.
841+
m_pTargetNode->path_from = m_aiNodeStack.front();
842+
m_aiNodeStack.push_back(test_node);
845843

846-
edge_t edge = current_node->edges[m_iTestEdge];
844+
m_eGraphStep = GRAPHSTEP_RECONSTRUCT;
845+
return;
846+
}
847847

848-
m_iTestNode = m_Graph.FollowEdge(m_aiNodeStack.back(), edge);
848+
if (m_Graph.GetNode(test_node)->seen)
849+
continue;
849850

850-
// Next time we'll test the next edge.
851-
m_iTestEdge++;
851+
// We haven't seen this node. Push it to the stack.
852+
m_aiNodeStack.push_back(test_node);
853+
m_Graph.GetNode(test_node)->path_from = m_aiNodeStack.front();
854+
}
852855

853-
m_eGraphStep = GRAPHSTEP_TESTS;
856+
m_eGraphStep = GRAPHSTEP_MARKSEEN;
854857
}
855-
else if (m_eGraphStep == GRAPHSTEP_TESTS)
858+
else if (m_eGraphStep == GRAPHSTEP_MARKSEEN)
856859
{
857-
if (m_Graph.GetNode(m_iTestNode) == m_pTargetNode)
858-
{
859-
// We're done!
860-
m_aiNodeStack.push_back(m_iTestNode);
861-
return;
862-
}
860+
// Technically we only need to mark the ones that were just added as seen but this is just sample code.
861+
// See below for the actual code where they're only added when seen.
862+
for (size_t i = 0; i < m_aiNodeStack.size(); i++)
863+
m_Graph.GetNode(m_aiNodeStack[i])->seen = true;
863864

864-
if (m_Graph.GetNode(m_iTestNode)->seen)
865-
{
866-
// We've already seen this node. Pick another.
867-
m_eGraphStep = GRAPHSTEP_FOLLOWEDGES;
868-
return;
869-
}
870-
871-
m_eGraphStep = GRAPHSTEP_PUSHNODE;
865+
m_eGraphStep = GRAPHSTEP_POPFRONT;
872866
}
873-
else if (m_eGraphStep == GRAPHSTEP_PUSHNODE)
867+
else if (m_eGraphStep == GRAPHSTEP_POPFRONT)
874868
{
875-
m_aiNodeStack.push_back(m_iTestNode);
869+
m_aiNodeStack.pop_front();
876870

877-
m_eGraphStep = GRAPHSTEP_MARKSEEN;
871+
m_eGraphStep = GRAPHSTEP_PUSHNEIGHBORS;
878872
}
879-
else if (m_eGraphStep == GRAPHSTEP_POPNODE)
873+
else if (m_eGraphStep == GRAPHSTEP_RECONSTRUCT)
880874
{
881-
// This is not the node we're looking for.
882-
m_aiNodeStack.pop_back();
875+
node_t current_node = m_aiNodeStack.back();
883876

884-
m_eGraphStep = GRAPHSTEP_MARKSEEN;
877+
m_aiPathStack.push_back(current_node);
878+
879+
while (m_Graph.GetNode(current_node)->path_from != ~0)
880+
{
881+
current_node = m_Graph.GetNode(current_node)->path_from;
882+
m_aiPathStack.push_back(current_node);
883+
}
885884
}
886885
}
887886

@@ -890,40 +889,47 @@ void CGame::GraphComplete()
890889
GraphReset();
891890

892891
m_aiNodeStack.push_back(0);
892+
m_Graph.GetNode(m_aiNodeStack.back())->seen = true;
893893

894894
while (true)
895895
{
896-
m_Graph.GetNode(m_aiNodeStack.back())->seen = true;
897-
898-
CGraph::CNode* current_node = m_Graph.GetNode(m_aiNodeStack.back());
896+
CGraph::CNode* current_node = m_Graph.GetNode(m_aiNodeStack.front());
899897

900898
size_t i;
901899
for (i = 0; i < current_node->edges.size(); i++)
902900
{
903901
edge_t edge = current_node->edges[i];
904902

905-
node_t test_node = m_Graph.FollowEdge(m_aiNodeStack.back(), edge);
903+
node_t test_node = m_Graph.FollowEdge(m_aiNodeStack.front(), edge);
906904
if (m_Graph.GetNode(test_node) == m_pTargetNode)
907905
{
908906
// We're done!
909-
m_aiNodeStack.push_back(test_node);
907+
m_pTargetNode->path_from = m_aiNodeStack.front();
908+
909+
node_t current_node = test_node;
910+
911+
m_aiPathStack.push_back(current_node);
912+
913+
// Now we reconstruct the path.
914+
while (m_Graph.GetNode(current_node)->path_from != ~0)
915+
{
916+
current_node = m_Graph.GetNode(current_node)->path_from;
917+
m_aiPathStack.push_back(current_node);
918+
}
919+
910920
return;
911921
}
912922

913923
if (m_Graph.GetNode(test_node)->seen)
914-
// We've already seen this node. Pick another.
915924
continue;
916925

917926
// We haven't seen this node. Push it to the stack.
918927
m_aiNodeStack.push_back(test_node);
919-
920-
// Break out of this edges loop to go back to the beginning of the algorithm.
921-
break;
928+
m_Graph.GetNode(test_node)->seen = true;
929+
m_Graph.GetNode(test_node)->path_from = m_aiNodeStack.front();
922930
}
923931

924-
if (i == current_node->edges.size())
925-
// We explored every edge and they were all unseen. This must be a dead end.
926-
m_aiNodeStack.pop_back();
932+
m_aiNodeStack.pop_front();
927933
}
928934
}
929935

@@ -936,10 +942,8 @@ void CGame::GraphDraw()
936942
CGraph::CNode* node = m_Graph.GetNode(i);
937943

938944
{
939-
if (m_aiNodeStack.size() && m_aiNodeStack.back() == i)
945+
if (m_aiNodeStack.size() && m_aiNodeStack.front() == i)
940946
c.SetUniform("vecColor", Color(0, 255, 0, 255));
941-
else if (i == m_iTestNode)
942-
c.SetUniform("vecColor", Color(255, 255, 0, 255));
943947
else if (node == m_pTargetNode)
944948
c.SetUniform("vecColor", Color(255, 120, 0, 255));
945949
else
@@ -975,15 +979,15 @@ void CGame::GraphDraw()
975979
CGraph::CNode* node2 = m_Graph.GetNode(edge->second);
976980

977981
bool in_path = false;
978-
for (int j = 0; j < ((int)m_aiNodeStack.size())-1; j++)
982+
for (int j = 0; j < ((int)m_aiPathStack.size())-1; j++)
979983
{
980-
if (m_aiNodeStack[j] == edge->first && m_aiNodeStack[j+1] == edge->second)
984+
if (m_aiPathStack[j] == edge->first && m_aiPathStack[j+1] == edge->second)
981985
{
982986
in_path = true;
983987
break;
984988
}
985989

986-
if (m_aiNodeStack[j] == edge->second && m_aiNodeStack[j+1] == edge->first)
990+
if (m_aiPathStack[j] == edge->second && m_aiPathStack[j+1] == edge->first)
987991
{
988992
in_path = true;
989993
break;
@@ -999,5 +1003,28 @@ void CGame::GraphDraw()
9991003
c.Vertex(node1->debug_position + Vector(0, 0.1f, 0));
10001004
c.Vertex(node2->debug_position + Vector(0, 0.1f, 0));
10011005
c.EndRender();
1006+
1007+
Vector path_start, path_end;
1008+
bool show_path = false;
1009+
1010+
if (node1->path_from == edge->second)
1011+
{
1012+
path_start = node1->debug_position;
1013+
path_end = node2->debug_position;
1014+
show_path = true;
1015+
}
1016+
else if (node2->path_from == edge->first)
1017+
{
1018+
path_start = node2->debug_position;
1019+
path_end = node1->debug_position;
1020+
show_path = true;
1021+
}
1022+
1023+
if (show_path)
1024+
{
1025+
float lerp = fmod(GetTime(), 1);
1026+
Vector position = path_start * (1-lerp) + path_end * lerp;
1027+
c.RenderBox(position - Vector(0.2f, 0.2f, 0.2f), position + Vector(0.2f, 0.2f, 0.2f));
1028+
}
10021029
}
10031030
}

game/game.h

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON A
1818
#pragma once
1919

2020
#include <vector>
21+
#include <deque>
2122

2223
#include <common/common.h>
2324

@@ -119,17 +120,15 @@ class CGame : public CApplication
119120
typedef enum
120121
{
121122
GRAPHSTEP_PUSHTOSTACK,
123+
GRAPHSTEP_PUSHNEIGHBORS,
122124
GRAPHSTEP_MARKSEEN,
123-
GRAPHSTEP_FOLLOWEDGES,
124-
GRAPHSTEP_TESTS,
125-
GRAPHSTEP_PUSHNODE,
126-
GRAPHSTEP_POPNODE,
125+
GRAPHSTEP_POPFRONT,
126+
GRAPHSTEP_RECONSTRUCT,
127127
} graph_step_t;
128128

129129
graph_step_t m_eGraphStep;
130-
std::vector<node_t> m_aiNodeStack;
131-
node_t m_iTestNode;
132-
node_t m_iTestEdge;
130+
std::deque<node_t> m_aiNodeStack;
131+
std::vector<node_t> m_aiPathStack;
133132

134133
CGraph m_Graph;
135134
CGraph::CNode* m_pTargetNode;

math/graph.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@ class CGraph
2323
CNode()
2424
{
2525
seen = false;
26+
path_from = ~0;
2627
}
2728

2829
std::vector<edge_t> edges;
2930

3031
bool seen;
32+
node_t path_from;
3133

3234
Vector debug_position;
3335
};

0 commit comments

Comments
 (0)