Skip to content

Commit 9b2597e

Browse files
committed
Update README and clean up tests a little
1 parent 68e59b6 commit 9b2597e

File tree

2 files changed

+314
-21
lines changed

2 files changed

+314
-21
lines changed

README.md

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
astar-algorithm-cpp
2-
===================
1+
## astar-algorithm
32

43
[![Build Status](https://travis-ci.org/justinhj/astar-algorithm-cpp.svg?branch=master)](https://travis-ci.org/justinhj/astar-algorithm-cpp) [![Join the chat at https://gitter.im/astar-algorithm-cpp/community](https://badges.gitter.im/astar-algorithm-cpp/community.svg)](https://gitter.im/astar-algorithm-cpp/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
54

6-
Summary
7-
-------
5+
### Summary
86

9-
This code is an efficient implementation in C++ and C# of the A* algorithm, designed to be used from high performance realtime applications (video games) and with an optional fast memory allocation scheme.
7+
This code is an efficient implementation in C++ and C# of the A* algorithm, designed to be used from high performance realtime applications (video games) and with an optional fast memory allocation scheme.
108

11-
It accompanies this A* tutorial: http://www.heyes-jones.com/astar.html
9+
It accompanies this A* tutorial:
10+
https://www.heyes-jones.com/astar.php
1211

1312
The A* algorithm was described in the paper https://ieeexplore.ieee.org/document/4082128 by Hart, Nillson and Raphael.
13+
1414
Sadly Nils Nillson passed away in 2019, his work is much appreciated.
1515

1616
Contributions:
@@ -20,20 +20,17 @@ Contributions:
2020
* @Rasoul for submitting the path to Bucharest. Sample from Artificial Intelligence: A Modern Approach
2121
* @sergiosota For fixing a number of issues related to memory management
2222

23-
License
24-
=======
23+
### License
2524

2625
This software is released under the MIT License, see license.txt
2726

28-
Commercial Use
29-
==============
27+
### Commercial Use
3028

3129
This software has been used in AAA video games and is well tested in the wild. Please let me know if you use this code in your games, studies or hobby projects.
3230

3331
If you feel the need to pay money for this code, it is not required by the license, but you could contribute to Unicef, a charity which helps children worldwide, http://www.unicef.org/ that would be awesome.
3432

35-
Projects using this code
36-
========================
33+
### Projects using this code
3734

3835
If you wish to be added to the list of known products/educational projects using the code please contact me.
3936

@@ -44,13 +41,11 @@ If you wish to be added to the list of known products/educational projects using
4441
* Lighthouses AI contest https://github.com/marcan/lighthouses_aicontest
4542
* Self-Driving Car Engineer Nanodegree Program https://github.com/vanAken/CarND-Path-Planning-Project
4643

47-
Compilation
48-
===========
44+
### Compilation
4945

5046
Enter the cpp folder and run make
5147

52-
Introduction
53-
============
48+
#### Introduction
5449

5550
This implementation is intended to be simple to read yet fairly
5651
efficient. To build it you can compile, with any recent C++ compiler,
@@ -62,7 +57,7 @@ For 8-puzzle solver
6257
* stlastar.h
6358
* optionally fsa.h
6459

65-
Command line
60+
#### Command line
6661

6762
8puzzle with no arguments runs with one of the boards in the cpp file, you can
6863
select the one you want changing the conditional compiliation instructions. Or if you
@@ -91,11 +86,11 @@ I'm going to leave the deprecation warnings in so that it still works cleanly wi
9186
TODO Make a non-deprecated compliant version using compiler checking
9287

9388
Compiled with:
94-
Apple LLVM version 6.0 (clang-600.0.51) (based on LLVM 3.5svn)
9589

96-
Please let me know if it doesn't work for you and I will try to help. I cannot help if you are using
97-
an old compiler such as Turbo C++, since I update the code to meet Ansi Standard C++ as required.
90+
Apple clang version 12.0.0 (clang-1200.0.32.28)
91+
Target: x86_64-apple-darwin19.6.0
9892

93+
Please let me know if it does not compile on a particular platform by opening an issue.
9994

10095
Cheers!
10196

cpp/tests.cpp

Lines changed: 299 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,308 @@
55
#include <assert.h>
66
#include "stlastar.h"
77

8-
// TODO this test suite is a placeholder. Should include some tests of stlastar.h functionality
8+
const int MAP_WIDTH = 20;
9+
const int MAP_HEIGHT = 20;
10+
11+
int world_map[ MAP_WIDTH * MAP_HEIGHT ] =
12+
{
13+
14+
// 0001020304050607080910111213141516171819
15+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 00
16+
1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,1, // 01
17+
1,9,9,1,1,9,9,9,1,9,1,9,1,9,1,9,9,9,1,1, // 02
18+
1,9,9,1,1,9,9,9,1,9,1,9,1,9,1,9,9,9,1,1, // 03
19+
1,9,1,9,1,9,9,9,1,9,1,9,1,1,1,1,9,9,1,1, // 04
20+
1,9,1,1,9,1,1,1,1,9,1,1,1,1,9,1,1,1,1,1, // 05
21+
1,9,9,9,9,1,1,1,1,1,1,9,9,9,9,1,1,1,1,1, // 06
22+
1,9,9,9,9,9,9,9,9,1,1,1,9,9,9,9,9,9,9,1, // 07
23+
1,9,1,1,1,1,1,1,1,1,1,9,1,1,1,1,1,1,1,1, // 08
24+
1,9,1,9,9,9,9,9,9,9,1,1,9,9,9,9,9,9,9,1, // 09
25+
1,9,1,1,1,1,9,1,1,9,1,1,1,1,1,1,1,1,1,1, // 10
26+
1,9,9,9,9,9,1,9,1,9,1,9,9,9,9,9,1,1,1,1, // 11
27+
1,9,1,9,1,9,9,9,1,9,1,9,1,9,1,9,9,9,1,1, // 12
28+
1,9,1,9,1,9,9,9,1,9,1,9,1,9,1,9,9,9,1,1, // 13
29+
1,9,1,1,1,1,9,9,1,9,1,9,1,1,1,1,9,9,1,1, // 14
30+
1,9,1,1,9,1,1,1,1,9,1,1,1,1,9,1,1,1,1,1, // 15
31+
1,9,9,9,9,1,1,1,1,1,1,9,9,9,9,1,1,1,1,1, // 16
32+
1,1,9,9,9,9,9,9,9,1,1,1,9,9,9,1,9,9,9,9, // 17
33+
1,9,1,1,1,1,1,1,1,1,1,9,1,1,1,1,1,1,1,1, // 18
34+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 19
35+
36+
};
37+
38+
39+
// map helper functions
40+
41+
int GetMap( int x, int y )
42+
{
43+
if( x < 0 ||
44+
x >= MAP_WIDTH ||
45+
y < 0 ||
46+
y >= MAP_HEIGHT
47+
)
48+
{
49+
return 9;
50+
}
51+
52+
return world_map[(y*MAP_WIDTH)+x];
53+
}
54+
55+
56+
57+
// Definitions
58+
59+
class MapSearchNode
60+
{
61+
public:
62+
int x; // the (x,y) positions of the node
63+
int y;
64+
65+
MapSearchNode() { x = y = 0; }
66+
MapSearchNode( int px, int py ) { x=px; y=py; }
67+
68+
float GoalDistanceEstimate( MapSearchNode &nodeGoal );
69+
bool IsGoal( MapSearchNode &nodeGoal );
70+
bool GetSuccessors( AStarSearch<MapSearchNode> *astarsearch, MapSearchNode *parent_node );
71+
float GetCost( MapSearchNode &successor );
72+
bool IsSameState( MapSearchNode &rhs );
73+
74+
void PrintNodeInfo();
75+
76+
77+
};
78+
79+
bool MapSearchNode::IsSameState( MapSearchNode &rhs )
80+
{
81+
82+
// same state in a maze search is simply when (x,y) are the same
83+
if( (x == rhs.x) &&
84+
(y == rhs.y) )
85+
{
86+
return true;
87+
}
88+
else
89+
{
90+
return false;
91+
}
92+
93+
}
94+
95+
void MapSearchNode::PrintNodeInfo()
96+
{
97+
char str[100];
98+
sprintf( str, "Node position : (%d,%d)\n", x,y );
99+
100+
cout << str;
101+
}
102+
103+
// Here's the heuristic function that estimates the distance from a Node
104+
// to the Goal.
105+
106+
float MapSearchNode::GoalDistanceEstimate( MapSearchNode &nodeGoal )
107+
{
108+
return abs(x - nodeGoal.x) + abs(y - nodeGoal.y);
109+
}
110+
111+
bool MapSearchNode::IsGoal( MapSearchNode &nodeGoal )
112+
{
113+
114+
if( (x == nodeGoal.x) &&
115+
(y == nodeGoal.y) )
116+
{
117+
return true;
118+
}
119+
120+
return false;
121+
}
122+
123+
// This generates the successors to the given Node. It uses a helper function called
124+
// AddSuccessor to give the successors to the AStar class. The A* specific initialisation
125+
// is done for each node internally, so here you just set the state information that
126+
// is specific to the application
127+
bool MapSearchNode::GetSuccessors( AStarSearch<MapSearchNode> *astarsearch, MapSearchNode *parent_node )
128+
{
129+
130+
int parent_x = -1;
131+
int parent_y = -1;
132+
133+
if( parent_node )
134+
{
135+
parent_x = parent_node->x;
136+
parent_y = parent_node->y;
137+
}
138+
139+
140+
MapSearchNode NewNode;
141+
142+
// push each possible move except allowing the search to go backwards
143+
144+
if( (GetMap( x-1, y ) < 9)
145+
&& !((parent_x == x-1) && (parent_y == y))
146+
)
147+
{
148+
NewNode = MapSearchNode( x-1, y );
149+
astarsearch->AddSuccessor( NewNode );
150+
}
151+
152+
if( (GetMap( x, y-1 ) < 9)
153+
&& !((parent_x == x) && (parent_y == y-1))
154+
)
155+
{
156+
NewNode = MapSearchNode( x, y-1 );
157+
astarsearch->AddSuccessor( NewNode );
158+
}
159+
160+
if( (GetMap( x+1, y ) < 9)
161+
&& !((parent_x == x+1) && (parent_y == y))
162+
)
163+
{
164+
NewNode = MapSearchNode( x+1, y );
165+
astarsearch->AddSuccessor( NewNode );
166+
}
167+
168+
169+
if( (GetMap( x, y+1 ) < 9)
170+
&& !((parent_x == x) && (parent_y == y+1))
171+
)
172+
{
173+
NewNode = MapSearchNode( x, y+1 );
174+
astarsearch->AddSuccessor( NewNode );
175+
}
176+
177+
return true;
178+
}
179+
180+
// given this node, what does it cost to move to successor. In the case
181+
// of our map the answer is the map terrain value at this node since that is
182+
// conceptually where we're moving
183+
184+
float MapSearchNode::GetCost( MapSearchNode &successor )
185+
{
186+
return (float) GetMap( x, y );
187+
188+
}
9189

10190
int main(int argc, char *argv[]) {
11191

192+
AStarSearch<MapSearchNode> astarsearch;
193+
194+
unsigned int SearchCount = 0;
195+
196+
const unsigned int NumSearches = 1;
197+
198+
while(SearchCount < NumSearches)
199+
{
200+
201+
// Create a start state
202+
MapSearchNode nodeStart;
203+
nodeStart.x = 0;
204+
nodeStart.y = 0;
205+
206+
// Define the goal state
207+
MapSearchNode nodeEnd;
208+
nodeEnd.x = 3;
209+
nodeEnd.y = 3;
210+
211+
// Set Start and goal states
212+
213+
astarsearch.SetStartAndGoalStates( nodeStart, nodeEnd );
214+
215+
unsigned int SearchState;
216+
unsigned int SearchSteps = 0;
217+
218+
do
219+
{
220+
SearchState = astarsearch.SearchStep();
221+
222+
SearchSteps++;
223+
224+
#if DEBUG_LISTS
225+
226+
cout << "Steps:" << SearchSteps << "\n";
227+
228+
int len = 0;
229+
230+
cout << "Open:\n";
231+
MapSearchNode *p = astarsearch.GetOpenListStart();
232+
while( p )
233+
{
234+
len++;
235+
#if !DEBUG_LIST_LENGTHS_ONLY
236+
((MapSearchNode *)p)->PrintNodeInfo();
237+
#endif
238+
p = astarsearch.GetOpenListNext();
239+
240+
}
241+
242+
cout << "Open list has " << len << " nodes\n";
243+
244+
len = 0;
245+
246+
cout << "Closed:\n";
247+
p = astarsearch.GetClosedListStart();
248+
while( p )
249+
{
250+
len++;
251+
#if !DEBUG_LIST_LENGTHS_ONLY
252+
p->PrintNodeInfo();
253+
#endif
254+
p = astarsearch.GetClosedListNext();
255+
}
256+
257+
cout << "Closed list has " << len << " nodes\n";
258+
#endif
259+
260+
}
261+
while( SearchState == AStarSearch<MapSearchNode>::SEARCH_STATE_SEARCHING );
262+
263+
if( SearchState == AStarSearch<MapSearchNode>::SEARCH_STATE_SUCCEEDED )
264+
{
265+
cout << "Search found goal state\n";
266+
267+
MapSearchNode *node = astarsearch.GetSolutionStart();
268+
269+
#if DISPLAY_SOLUTION
270+
cout << "Displaying solution\n";
271+
#endif
272+
int steps = 0;
273+
274+
node->PrintNodeInfo();
275+
for( ;; )
276+
{
277+
node = astarsearch.GetSolutionNext();
278+
279+
if( !node )
280+
{
281+
break;
282+
}
283+
284+
node->PrintNodeInfo();
285+
steps ++;
286+
287+
};
288+
289+
cout << "Solution steps " << steps << endl;
290+
291+
// Once you're done with the solution you can free the nodes up
292+
astarsearch.FreeSolutionNodes();
293+
294+
295+
}
296+
else if( SearchState == AStarSearch<MapSearchNode>::SEARCH_STATE_FAILED )
297+
{
298+
cout << "Search terminated. Did not find goal state\n";
299+
300+
}
301+
302+
// Display the number of loops the search went through
303+
cout << "SearchSteps : " << SearchSteps << "\n";
304+
305+
SearchCount ++;
306+
307+
astarsearch.EnsureMemoryFreed();
308+
}
309+
12310
assert(true && "failed to be true");
13311

14312
printf("Tests succeeded\n");

0 commit comments

Comments
 (0)