Header | {z88dk}/include/algorithm.h |
---|---|
Source | {z88dk}/libsrc/algorithm |
Include | #include <algorithm.h> |
Linking | -lalgorithm |
Compile | from {z88dk}/libsrc : make algorithm.lib ; make install |
Comments | none |
A collection of algorithms of general interest across z80 platforms.
The A* search algorithm is a pathfinding algorithm that searches for the lowest cost path between the start node and the end node. It is a best-first search algorithm, meaning it pursues paths of lowest cost first. Although designed with pathfinding problems in mind, the A* algorithm can be used as a search-based solver for other types of problems cast as a pathfinding exercise.
This implementation of A* uses the heap from the Abstract Data Types library as a priority queue. This means your program must also be linked with -ladt during compilation. Each path is described by a single struct astar_path, a 7-byte block which contains a node, a pointer to a prefix path and a cost. These blocks are dynamically allocated by the library functions by calling the user-supplied functions u_malloc() and u_free() as usual. See the library dynamic memory allocation discussion for details.
The nodes of the problem are represented by 16-bit unsigned integers. To use A* you must first specify the start and end nodes by initializing two global variables:
uint astar_startNode; // start node uint astar_destNode; // end node
This implementation keeps track of all paths being investigated in a priority queue, which is implemented by the heap data type from the Abstract Data Types library. The heap data type requires an array to be supplied in which to maintain the queue of size equal to the maximum number of pending paths that can be investigated. It also requires an unsigned integer variable to hold the number of paths currently in the queue and another to indicate the maximum size of the queue. All of these variables must be declared globally in the program. astar_queue must be initialized to point at the array and astar_queueSize must be initialized to hold the size of the array in words.
void **astar_queue; // address of an array of void* that will hold the queue uint astar_queueSize; // maximum number of pending paths in the queue uint astar_queueN; // current number of pending paths in the queue
Before the problem begins, all nodes should be marked as “open”. A* will request that nodes be “closed” as they are visited by the search algorithm. This prevents the algorithm from going in circles while searching for the solution path.
A* will call functions supplied by the program that provide information on the connectivity of nodes and the cost of moving between pairs of nodes. The functions should have the following prototypes:
void [[__FASTCALL__]] astar_TestAndClose(uint node); // Mark the node as 'closed' and return carry flag set // if the node was already closed previously. C functions // should make use of the special z88dk keywords return_c() // and return_nc() to exit with known carry flag state. void astar_Successor(uint *node, uint *cost); // This function enumerates all the neighbours of node, one // after the other on successive calls. With node not -1, a // new start node is indicated. If node is -1, the next // neighbour of the last valid node supplied should be returned. // This function indicates to the algorithm the connectivity // of the map. // // If node is not -1, write into //node// its first neighbour // and into //cost// the cost of moving from that node to the // neighbour. // // If node is -1, write the next neighbour into //node// and the // cost of moving from the last valid node to this neighbour // into //cost//. // // Return with carry flag set when there are no more neighbours // and reset if the neighbour returned is valid. C functions // should use the z88dk keywords return_c() and return_c() // to exit with known carry flag state. uint [[__FASTCALL__]] astar_DestCost(uint node) // (optional) Estimate the cost from the node indicated to // the destination node. These nodes may be widely separated // so a cartesian distance metric is probably simplest. // // This function is only called by astar_EstimateBestPath(). // If astar_EstimateBestPath() is not used, this function need // not be defined.
Do not use the function names listed above. Instead the following function pointers should be globally declared and initialized to point at the relevant functions:
void *astar_TestAndClose; // void (*astar_TestAndClose)(uint node) void *astar_Successor; // void (*astar_Successor)(uint *node, uint *cost) void *astar_DestCost; // uint (*astar_DestCost)(uint node)
With the above initialization completed, a call to astar_Search() is made to determine the path of least cost between the start and end nodes. There are three possible outcomes:
1. astar_Search() Uses IX
Find the path of lowest cost between the start node and the end node. There are three possible outcomes:
struct astar_path *astar_Search(void);
2. astar_SearchResume() Uses IX
Resume a search previously initiated by a call to astar_Search() or astar_SearchResume().
struct astar_path *astar_SearchResume(struct astar_path *p); // p = path to begin investigation with; returned by a previous call to astar_Search() or astar_SearchResume() // if 0, further paths to investigate are retrieved from the priority queue.
3. astar_EstimateBestPath()
not implemented yet
struct astar_path *astar_EstimateBestPath(struct astar_path *p); // p =
4. astar_PathLength()
Return the number of nodes in the path.
uint astar_PathLength(struct astar_path *p); // p = a path as returned by astar_Search()
5. astar_WalkPath()
Write at most n nodes from the path p into the supplied array node_arr. Return a pointer inside node_arr that points at the first node of the path written. The carry flag is set if not all nodes of the path could be written into the array.
uint *astar_WalkPath(struct astar_path *p, uint *node_arr, uint n); // p = path whose nodes are to be enumerated // node_arr = an array of unsigned integers into which the nodes of the path will be written // n = maximum size of the array
6. astar_DeletePath()
Deallocate memory associated with the path.
void astar_DeletePath(struct astar_path *p); // p = path to delete
7. astar_CleanUp
Delete the path p and all pending paths in the priority queue. A call to this function completely deallocates all memory associated with A*.
void astar_CleanUp(struct astar_path *p); // p = path to delete, 0 if none