(svn r13460) [NoAI] -Add [Library]: added graph.aystar, an A* implementation (Yexo) noai
authortruebrain
Tue, 10 Jun 2008 23:30:02 +0000
branchnoai
changeset 10909 3c573e607b60
parent 10908 429195fd03f2
child 10910 85f71706f496
(svn r13460) [NoAI] -Add [Library]: added graph.aystar, an A* implementation (Yexo)
bin/ai/library/graph/aystar/library.nut
bin/ai/library/graph/aystar/main.nut
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/ai/library/graph/aystar/library.nut	Tue Jun 10 23:30:02 2008 +0000
@@ -0,0 +1,12 @@
+/* $Id$ */
+
+class AyStar extends AILibrary {
+	function GetAuthor()      { return "OpenTTD NoAI Developers Team"; }
+	function GetName()        { return "AyStar"; }
+	function GetDescription() { return "An implementation of AyStar"; }
+	function GetVersion()     { return 1; }
+	function GetDate()        { return "2008-06-11"; }
+	function CreateInstance() { return "AyStar"; }
+}
+
+RegisterLibrary(AyStar());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/ai/library/graph/aystar/main.nut	Tue Jun 10 23:30:02 2008 +0000
@@ -0,0 +1,96 @@
+/* $Id$ */
+
+/* We need a Queue */
+import("queue.binary_heap", "Queue", 1);
+
+/**
+ * An AyStar implementation.
+ *  It solves graphs by finding the fastest route from one point to the other.
+ */
+class AyStar
+{
+	/**
+	 * Find a single path between sources and goals with the lowest cost.
+	 * @param sources The source tiles.
+	 * @param goals The target tiles.
+	 * @param cost_callback A function that returns the cost of a path. It
+	 *  should accept 2 parameters, old_path and new_tile. old_path is an
+	 *  instance of AyStar.Path, and new_tile is the new tile that is added to
+	 *  that path. It should return the cost of the path including new_tile.
+	 * @param estimate_callback A function that returns an estimate from a tile
+	 *  to the goal tile. It should accept two parameters, tile and goal_tiles.
+	 *  It should return an estimate to the cost from the lowest cost between
+	 *  tile and any tile out of goal_tiles. Note that this estimate is not
+	 *  allowed to be higher than the real cost between tile and any of
+	 *  goal_tiles. A lower value is fine, however the closer it is to the real
+	 *  value, the better the performance.
+	 * @param neighbours_callback A function that returns all neighbouring tiles
+	 *  from a given tile. It should accept two parameters, current_path and tile,
+	 *  and return an array containing all neighbouring tiles.
+	 * @return A route to from an element of sources to an element of goals or
+	 *  null if there is no route.
+	 */
+	function FindPath(sources, goals, cost_callback, estimate_callback, neighbours_callback);
+}
+
+function AyStar::FindPath(sources, goals, cost_callback, estimate_callback, neighbours_callback)
+{
+	local closed = AIList();
+	local open = Queue();
+	/* Create the initial open list */
+	foreach (tile in sources) {
+		local new_path = AyStar.Path(null, tile, cost_callback);
+		open.Insert(new_path, new_path.GetCost() + estimate_callback(tile, goals));
+	}
+	while (open.Count() > 0) {
+		/* Get the path with the best score so far */
+		local path = open.Pop();
+		local cur_tile = path.GetTile();
+		/* Make sure we didn't already passed it */
+		if (closed.HasItem(cur_tile)) continue;
+		/* Check if we found the end */
+		foreach (tile in goals) {
+			if (cur_tile == tile) return path;
+		}
+		closed.AddItem(cur_tile, 0);
+		/* Scan all neighbours */
+		local neighbours = neighbours_callback(path, cur_tile);
+		foreach (tile in neighbours) {
+			if (closed.HasItem(tile)) continue;
+			/* Calculate the new paths and add them to the open list */
+			local new_path = AyStar.Path(path, tile, cost_callback);
+			open.Insert(new_path, new_path.GetCost() + estimate_callback(tile, goals));
+		}
+	}
+
+	return null;
+}
+
+class AyStar.Path
+{
+	_prev = null;
+	_tile = null;
+	_cost = null;
+
+	constructor(old_path, new_tile, cost_callback)
+	{
+		this._prev = old_path;
+		this._tile = new_tile;
+		this._cost = cost_callback(old_path, new_tile);
+	};
+
+	/**
+	 * Return the tile where this (partial-)path ends.
+	 */
+	function GetTile() { return this._tile; }
+
+	/**
+	 * Return an instance of this class leading to the previous tile.
+	 */
+	function GetParent() { return this._prev; }
+
+	/**
+	 * Return the cost of this (partial-)path from the beginning up to this tile.
+	 */
+	function GetCost() { return this._cost; }
+}