Changeset - r10696:8dfe83e30d01
[Not reviewed]
master
! ! !
truebrain - 16 years ago 2009-01-12 17:11:45
truebrain@openttd.org
(svn r15027) -Merge: tomatos and bananas left to be, here is NoAI for all to see.
NoAI is an API (a framework) to build your own AIs in. See:
http://wiki.openttd.org/wiki/index.php/AI:Main_Page
With many thanks to:
- glx and Rubidium for their syncing, feedback and hard work
- Yexo for his feedback, patches, and AIs which tested the system very deep
- Morloth for his feedback and patches
- TJIP for hosting a challenge which kept NoAI on track
- All AI authors for testing our AI API, and all other people who helped in one way or another
-Remove: all old AIs and their cheats/hacks
18 files changed:
0 comments (0 inline, 0 general)
Makefile.bundle.in
Show inline comments
 
@@ -39,6 +39,7 @@ bundle: all
 
	$(Q)mkdir -p "$(BUNDLE_DIR)/scenario"
 
	$(Q)mkdir -p "$(BUNDLE_DIR)/scenario/heightmap"
 
	$(Q)mkdir -p "$(BUNDLE_DIR)/media"
 
	$(Q)mkdir -p "$(BUNDLE_DIR)/ai"
 
	$(Q)mkdir -p "$(BUNDLE_DIR)/scripts"
 
	$(Q)mkdir -p "$(TTD_DIR)"
 
	$(Q)mkdir -p "$(DATA_DIR)"
 
@@ -75,6 +76,10 @@ ifdef MENU_DIR
 
	$(Q)cp "$(ROOT_DIR)/media/openttd.desktop" "$(BUNDLE_DIR)/media/"
 
	$(Q)cat "$(ROOT_DIR)/media/openttd.desktop" | sed s/=openttd/=$(BINARY_NAME)/g > "$(ROOT_DIR)/media/openttd.desktop.install"
 
endif
 
ifeq ($(shell if test -n "`ls -l \"$(BIN_DIR)/ai/\"* 2>/dev/null`"; then echo 1; fi), 1)
 
	$(Q)cp -R "$(BIN_DIR)/ai/"*               "$(BUNDLE_DIR)/ai/"
 
	$(Q)find $(BUNDLE_DIR)/ai/ -depth -iname '*.svn' -exec rm -Rf {} \; || find $(BUNDLE_DIR)/ai/ -d -iname '*.svn' -exec rm -Rf {} \;
 
endif
 
ifeq ($(shell if test -n "`ls -l \"$(BIN_DIR)/scenario/\"*.scn 2> /dev/null`"; then echo 1; fi), 1)
 
	$(Q)cp "$(BIN_DIR)/scenario/"*.scn        "$(BUNDLE_DIR)/scenario/"
 
endif
Makefile.in
Show inline comments
 
@@ -141,6 +141,9 @@ run-gdb: all
 
run-prof: all
 
	$(Q)cd !!BIN_DIR!! && ./!!TTD!! $(OPENTTD_ARGS) && gprof !!TTD!! | less
 

	
 
regression: all
 
	$(Q)cd !!BIN_DIR!! && sh ai/regression/run.sh
 

	
 
%.o:
 
	@for dir in $(SRC_DIRS); do \
 
		$(MAKE) -C $$dir $(@:src/%=%); \
Makefile.src.in
Show inline comments
 
@@ -15,6 +15,7 @@ LANG_DIR     = !!LANG_DIR!!
 
SRC_OBJS_DIR = !!SRC_OBJS_DIR!!
 
LANG_OBJS_DIR= !!LANG_OBJS_DIR!!
 
SRC_DIR      = !!SRC_DIR!!
 
SCRIPT_SRC_DIR=!!SCRIPT_SRC_DIR!!
 
MEDIA_DIR    = !!MEDIA_DIR!!
 
TTD          = !!TTD!!
 
STRGEN       = !!STRGEN!!
 
@@ -48,7 +49,7 @@ RES      := $(shell mkdir -p $(BIN_DIR) 
 

	
 
# Make sure endian_target.h is reasable as if it was in the src/ dir
 
CFLAGS += -I $(SRC_OBJS_DIR) -I $(LANG_OBJS_DIR)
 
CFLAGS_MAKEDEP += -I $(SRC_OBJS_DIR) -I $(LANG_OBJS_DIR)
 
CFLAGS_MAKEDEP += -I $(SRC_OBJS_DIR) -I $(LANG_OBJS_DIR) -I $(SCRIPT_SRC_DIR)
 

	
 
ENDIAN_TARGETS := endian_target.h $(ENDIAN_CHECK)
 

	
 
@@ -216,10 +217,10 @@ endif
 

	
 
endif
 

	
 
# Avoid problems with deps if a .h/.hpp file is deleted without the deps
 
# Avoid problems with deps if a .h/.hpp/.hpp.sq file is deleted without the deps
 
#  being updated. Now the Makefile continues, the deps are recreated
 
#  and all will be fine.
 
%.h %.hpp:
 
%.h %.hpp %.hpp.sq:
 
	@true
 

	
 

	
bin/ai/library/graph/aystar/library.nut
Show inline comments
 
new file 100644
 
/* $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 4; }
 
	function GetDate()        { return "2008-06-11"; }
 
	function CreateInstance() { return "AyStar"; }
 
}
 

	
 
RegisterLibrary(AyStar());
bin/ai/library/graph/aystar/main.nut
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/**
 
 * An AyStar implementation.
 
 *  It solves graphs by finding the fastest route from one point to the other.
 
 */
 
class AyStar
 
{
 
	_queue_class = import("queue.binary_heap", "", 1);
 
	_cost_callback = null;
 
	_estimate_callback = null;
 
	_neighbours_callback = null;
 
	_check_direction_callback = null;
 
	_cost_callback_param = null;
 
	_estimate_callback_param = null;
 
	_neighbours_callback_param = null;
 
	_check_direction_callback_param = null;
 
	_open = null;
 
	_closed = null;
 
	_goals = null;
 

	
 
	/**
 
	 * @param cost_callback A function that returns the cost of a path. It
 
	 *  should accept four parameters, old_path, new_tile, new_direction and
 
	 *  cost_callback_param. old_path is an instance of AyStar.Path, and
 
	 *  new_node is the new node that is added to that path. It should return
 
	 *  the cost of the path including new_node.
 
	 * @param estimate_callback A function that returns an estimate from a node
 
	 *  to the goal node. It should accept four parameters, tile, direction,
 
	 *  goal_nodes and estimate_callback_param. It should return an estimate to
 
	 *  the cost from the lowest cost between node and any node out of goal_nodes.
 
	 *  Note that this estimate is not allowed to be higher than the real cost
 
	 *  between node and any of goal_nodes. 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 nodes
 
	 *  from a given node. It should accept three parameters, current_path, node
 
	 *  and neighbours_callback_param. It should return an array containing all
 
	 *  neighbouring nodes, which are an array in the form [tile, direction].
 
	 * @param check_direction_callback A function that returns either false or
 
	 *  true. It should accept four parameters, tile, existing_direction,
 
	 *  new_direction and check_direction_callback_param. It should check
 
	 *  if both directions can go together on a single tile.
 
	 * @param cost_callback_param This parameters will be passed to cost_callback
 
	 *  as fourth parameter. Useful to send is an instance of an object.
 
	 * @param estimate_callback_param This parameters will be passed to
 
	 *  estimate_callback as fourth parameter. Useful to send is an instance of an
 
	 *  object.
 
	 * @param neighbours_callback_param This parameters will be passed to
 
	 *  neighbours_callback as third parameter. Useful to send is an instance of
 
	 *  an object.
 
	 * @param check_direction_callback_param This parameters will be passed to
 
	 *  check_direction_callback as fourth parameter. Useful to send is an
 
	 *  instance of an object.
 
	 */
 
	constructor(cost_callback, estimate_callback, neighbours_callback, check_direction_callback, cost_callback_param = null,
 
	            estimate_callback_param = null, neighbours_callback_param = null, check_direction_callback_param = null)
 
	{
 
		if (typeof(cost_callback) != "function") throw("'cost_callback' has to be a function-pointer.");
 
		if (typeof(estimate_callback) != "function") throw("'estimate_callback' has to be a function-pointer.");
 
		if (typeof(neighbours_callback) != "function") throw("'neighbours_callback' has to be a function-pointer.");
 
		if (typeof(check_direction_callback) != "function") throw("'check_direction_callback' has to be a function-pointer.");
 

	
 
		this._cost_callback = cost_callback;
 
		this._estimate_callback = estimate_callback;
 
		this._neighbours_callback = neighbours_callback;
 
		this._check_direction_callback = check_direction_callback;
 
		this._cost_callback_param = cost_callback_param;
 
		this._estimate_callback_param = estimate_callback_param;
 
		this._neighbours_callback_param = neighbours_callback_param;
 
		this._check_direction_callback_param = check_direction_callback_param;
 
	}
 

	
 
	/**
 
	 * Initialize a path search between sources and goals.
 
	 * @param sources The source nodes. This can an array of either [tile, direction]-pairs or AyStar.Path-instances.
 
	 * @param goals The target tiles. This can be an array of either tiles or [tile, next_tile]-pairs.
 
	 * @param ignored_tiles An array of tiles that cannot occur in the final path.
 
	 */
 
	function InitializePath(sources, goals, ignored_tiles = []);
 

	
 
	/**
 
	 * Try to find the path as indicated with InitializePath with the lowest cost.
 
	 * @param iterations After how many iterations it should abort for a moment.
 
	 *  This value should either be -1 for infinite, or > 0. Any other value
 
	 *  aborts immediatly and will never find a path.
 
	 * @return A route if one was found, or false if the amount of iterations was
 
	 *  reached, or null if no path was found.
 
	 *  You can call this function over and over as long as it returns false,
 
	 *  which is an indication it is not yet done looking for a route.
 
	 */
 
	function FindPath(iterations);
 
};
 

	
 
function AyStar::InitializePath(sources, goals, ignored_tiles = [])
 
{
 
	if (typeof(sources) != "array" || sources.len() == 0) throw("sources has be a non-empty array.");
 
	if (typeof(goals) != "array" || goals.len() == 0) throw("goals has be a non-empty array.");
 

	
 
	this._open = this._queue_class();
 
	this._closed = AIList();
 

	
 
	foreach (node in sources) {
 
		if (typeof(node) == "array") {
 
			if (node[1] <= 0) throw("directional value should never be zero or negative.");
 

	
 
			local new_path = this.Path(null, node[0], node[1], this._cost_callback, this._cost_callback_param);
 
			this._open.Insert(new_path, new_path.GetCost() + this._estimate_callback(node[0], node[1], goals, this._estimate_callback_param));
 
		} else {
 
			this._open.Insert(node, node.GetCost());
 
		}
 
	}
 

	
 
	this._goals = goals;
 

	
 
	foreach (tile in ignored_tiles) {
 
		this._closed.AddItem(tile, ~0);
 
	}
 
}
 

	
 
function AyStar::FindPath(iterations)
 
{
 
	if (this._open == null) throw("can't execute over an uninitialized path");
 

	
 
	while (this._open.Count() > 0 && (iterations == -1 || iterations-- > 0)) {
 
		/* Get the path with the best score so far */
 
		local path = this._open.Pop();
 
		local cur_tile = path.GetTile();
 
		/* Make sure we didn't already passed it */
 
		if (this._closed.HasItem(cur_tile)) {
 
			/* If the direction is already on the list, skip this entry */
 
			if ((this._closed.GetValue(cur_tile) & path.GetDirection()) != 0) continue;
 

	
 
			/* Scan the path for a possible collision */
 
			local scan_path = path.GetParent();
 

	
 
			local mismatch = false;
 
			while (scan_path != null) {
 
				if (scan_path.GetTile() == cur_tile) {
 
					if (!this._check_direction_callback(cur_tile, scan_path.GetDirection(), path.GetDirection(), this._check_direction_callback_param)) {
 
						mismatch = true;
 
						break;
 
					}
 
				}
 
				scan_path = scan_path.GetParent();
 
			}
 
			if (mismatch) continue;
 

	
 
			/* Add the new direction */
 
			this._closed.SetValue(cur_tile, this._closed.GetValue(cur_tile) | path.GetDirection());
 
		} else {
 
			/* New entry, make sure we don't check it again */
 
			this._closed.AddItem(cur_tile, path.GetDirection());
 
		}
 
		/* Check if we found the end */
 
		foreach (goal in this._goals) {
 
			if (typeof(goal) == "array") {
 
				if (cur_tile == goal[0]) {
 
					local neighbours = this._neighbours_callback(path, cur_tile, this._neighbours_callback_param);
 
					foreach (node in neighbours) {
 
						if (node[0] == goal[1]) {
 
							this._CleanPath();
 
							return path;
 
						}
 
					}
 
					continue;
 
				}
 
			} else {
 
				if (cur_tile == goal) {
 
					this._CleanPath();
 
					return path;
 
				}
 
			}
 
		}
 
		/* Scan all neighbours */
 
		local neighbours = this._neighbours_callback(path, cur_tile, this._neighbours_callback_param);
 
		foreach (node in neighbours) {
 
			if (node[1] <= 0) throw("directional value should never be zero or negative.");
 

	
 
			if ((this._closed.GetValue(node[0]) & node[1]) != 0) continue;
 
			/* Calculate the new paths and add them to the open list */
 
			local new_path = this.Path(path, node[0], node[1], this._cost_callback, this._cost_callback_param);
 
			this._open.Insert(new_path, new_path.GetCost() + this._estimate_callback(node[0], node[1], this._goals, this._estimate_callback_param));
 
		}
 
	}
 

	
 
	if (this._open.Count() > 0) return false;
 
	this._CleanPath();
 
	return null;
 
}
 

	
 
function AyStar::_CleanPath()
 
{
 
	this._closed = null;
 
	this._open = null;
 
	this._goals = null;
 
}
 

	
 
/**
 
 * The path of the AyStar algorithm.
 
 *  It is reversed, that is, the first entry is more close to the goal-nodes
 
 *  than his GetParent(). You can walk this list to find the whole path.
 
 *  The last entry has a GetParent() of null.
 
 */
 
class AyStar.Path
 
{
 
	_prev = null;
 
	_tile = null;
 
	_direction = null;
 
	_cost = null;
 

	
 
	constructor(old_path, new_tile, new_direction, cost_callback, cost_callback_param)
 
	{
 
		this._prev = old_path;
 
		this._tile = new_tile;
 
		this._direction = new_direction;
 
		this._cost = cost_callback(old_path, new_tile, new_direction, cost_callback_param);
 
	};
 

	
 
	/**
 
	 * Return the tile where this (partial-)path ends.
 
	 */
 
	function GetTile() { return this._tile; }
 

	
 
	/**
 
	 * Return the direction from which we entered the tile in this (partial-)path.
 
	 */
 
	function GetDirection() { return this._direction; }
 

	
 
	/**
 
	 * Return an instance of this class leading to the previous node.
 
	 */
 
	function GetParent() { return this._prev; }
 

	
 
	/**
 
	 * Return the cost of this (partial-)path from the beginning up to this node.
 
	 */
 
	function GetCost() { return this._cost; }
 
};
bin/ai/library/pathfinder/rail/library.nut
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
class Rail extends AILibrary {
 
	function GetAuthor()      { return "OpenTTD NoAI Developers Team"; }
 
	function GetName()        { return "Rail"; }
 
	function GetDescription() { return "An implementation of a rail pathfinder"; }
 
	function GetVersion()     { return 1; }
 
	function GetDate()        { return "2008-09-22"; }
 
	function CreateInstance() { return "Rail"; }
 
}
 

	
 
RegisterLibrary(Rail());
bin/ai/library/pathfinder/rail/main.nut
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/**
 
 * A Rail Pathfinder.
 
 */
 
class Rail
 
{
 
	_aystar_class = import("graph.aystar", "", 4);
 
	_max_cost = null;              ///< The maximum cost for a route.
 
	_cost_tile = null;             ///< The cost for a single tile.
 
	_cost_diagonal_tile = null;    ///< The cost for a diagonal tile.
 
	_cost_turn = null;             ///< The cost that is added to _cost_tile if the direction changes.
 
	_cost_slope = null;            ///< The extra cost if a rail tile is sloped.
 
	_cost_bridge_per_tile = null;  ///< The cost per tile of a new bridge, this is added to _cost_tile.
 
	_cost_tunnel_per_tile = null;  ///< The cost per tile of a new tunnel, this is added to _cost_tile.
 
	_cost_coast = null;            ///< The extra cost for a coast tile.
 
	_pathfinder = null;            ///< A reference to the used AyStar object.
 
	_max_bridge_length = null;     ///< The maximum length of a bridge that will be build.
 
	_max_tunnel_length = null;     ///< The maximum length of a tunnel that will be build.
 

	
 
	cost = null;                   ///< Used to change the costs.
 
	_running = null;
 
	_goals = null;
 

	
 
	constructor()
 
	{
 
		this._max_cost = 10000000;
 
		this._cost_tile = 100;
 
		this._cost_diagonal_tile = 70;
 
		this._cost_turn = 50;
 
		this._cost_slope = 100;
 
		this._cost_bridge_per_tile = 150;
 
		this._cost_tunnel_per_tile = 120;
 
		this._cost_coast = 20;
 
		this._max_bridge_length = 6;
 
		this._max_tunnel_length = 6;
 
		this._pathfinder = this._aystar_class(this._Cost, this._Estimate, this._Neighbours, this._CheckDirection, this, this, this, this);
 

	
 
		this.cost = this.Cost(this);
 
		this._running = false;
 
	}
 

	
 
	/**
 
	 * Initialize a path search between sources and goals.
 
	 * @param sources The source tiles.
 
	 * @param goals The target tiles.
 
	 * @param ignored_tiles An array of tiles that cannot occur in the final path.
 
	 * @see AyStar::InitializePath()
 
	 */
 
	function InitializePath(sources, goals, ignored_tiles = []) {
 
		local nsources = [];
 

	
 
		foreach (node in sources) {
 
			local path = this._pathfinder.Path(null, node[1], 0xFF, this._Cost, this);
 
			path = this._pathfinder.Path(path, node[0], 0xFF, this._Cost, this);
 
			nsources.push(path);
 
		}
 
		this._goals = goals;
 
		this._pathfinder.InitializePath(nsources, goals, ignored_tiles);
 
	}
 

	
 
	/**
 
	 * Try to find the path as indicated with InitializePath with the lowest cost.
 
	 * @param iterations After how many iterations it should abort for a moment.
 
	 *  This value should either be -1 for infinite, or > 0. Any other value
 
	 *  aborts immediatly and will never find a path.
 
	 * @return A route if one was found, or false if the amount of iterations was
 
	 *  reached, or null if no path was found.
 
	 *  You can call this function over and over as long as it returns false,
 
	 *  which is an indication it is not yet done looking for a route.
 
	 * @see AyStar::FindPath()
 
	 */
 
	function FindPath(iterations);
 
};
 

	
 
class Rail.Cost
 
{
 
	_main = null;
 

	
 
	function _set(idx, val)
 
	{
 
		if (this._main._running) throw("You are not allowed to change parameters of a running pathfinder.");
 

	
 
		switch (idx) {
 
			case "max_cost":          this._main._max_cost = val; break;
 
			case "tile":              this._main._cost_tile = val; break;
 
			case "diagonal_tile":     this._cost_diagonal_tile = val; break;
 
			case "turn":              this._main._cost_turn = val; break;
 
			case "slope":             this._main._cost_slope = val; break;
 
			case "bridge_per_tile":   this._main._cost_bridge_per_tile = val; break;
 
			case "tunnel_per_tile":   this._main._cost_tunnel_per_tile = val; break;
 
			case "coast":             this._main._cost_coast = val; break;
 
			case "max_bridge_length": this._main._max_bridge_length = val; break;
 
			case "max_tunnel_length": this._main._max_tunnel_length = val; break;
 
			default: throw("the index '" + idx + "' does not exist");
 
		}
 

	
 
		return val;
 
	}
 

	
 
	function _get(idx)
 
	{
 
		switch (idx) {
 
			case "max_cost":          return this._main._max_cost;
 
			case "tile":              return this._main._cost_tile;
 
			case "diagonal_tile":     return this._cost_diagonal_tile;
 
			case "turn":              return this._main._cost_turn;
 
			case "slope":             return this._main._cost_slope;
 
			case "bridge_per_tile":   return this._main._cost_bridge_per_tile;
 
			case "tunnel_per_tile":   return this._main._cost_tunnel_per_tile;
 
			case "coast":             return this._main._cost_coast;
 
			case "max_bridge_length": return this._main._max_bridge_length;
 
			case "max_tunnel_length": return this._main._max_tunnel_length;
 
			default: throw("the index '" + idx + "' does not exist");
 
		}
 
	}
 

	
 
	constructor(main)
 
	{
 
		this._main = main;
 
	}
 
};
 

	
 
function Rail::FindPath(iterations)
 
{
 
	local test_mode = AITestMode();
 
	local ret = this._pathfinder.FindPath(iterations);
 
	this._running = (ret == false) ? true : false;
 
	if (!this._running && ret != null) {
 
		foreach (goal in this._goals) {
 
			if (goal[0] == ret.GetTile()) {
 
				return this._pathfinder.Path(ret, goal[1], 0, this._Cost, this);
 
			}
 
		}
 
	}
 
	return ret;
 
}
 

	
 
function Rail::_GetBridgeNumSlopes(end_a, end_b)
 
{
 
	local slopes = 0;
 
	local direction = (end_b - end_a) / AIMap.DistanceManhattan(end_a, end_b);
 
	local slope = AITile.GetSlope(end_a);
 
	if (!((slope == AITile.SLOPE_NE && direction == 1) || (slope == AITile.SLOPE_SE && direction == -AIMap.GetMapSizeX()) ||
 
		(slope == AITile.SLOPE_SW && direction == -1) || (slope == AITile.SLOPE_NW && direction == AIMap.GetMapSizeX()) ||
 
		 slope == AITile.SLOPE_N || slope == AITile.SLOPE_E || slope == AITile.SLOPE_S || slope == AITile.SLOPE_W)) {
 
		slopes++;
 
	}
 

	
 
	local slope = AITile.GetSlope(end_b);
 
	direction = -direction;
 
	if (!((slope == AITile.SLOPE_NE && direction == 1) || (slope == AITile.SLOPE_SE && direction == -AIMap.GetMapSizeX()) ||
 
		(slope == AITile.SLOPE_SW && direction == -1) || (slope == AITile.SLOPE_NW && direction == AIMap.GetMapSizeX()) ||
 
		 slope == AITile.SLOPE_N || slope == AITile.SLOPE_E || slope == AITile.SLOPE_S || slope == AITile.SLOPE_W)) {
 
		slopes++;
 
	}
 
	return slopes;
 
}
 

	
 
function Rail::_nonzero(a, b)
 
{
 
	return a != 0 ? a : b;
 
}
 

	
 
function Rail::_Cost(path, new_tile, new_direction, self)
 
{
 
	/* path == null means this is the first node of a path, so the cost is 0. */
 
	if (path == null) return 0;
 

	
 
	local prev_tile = path.GetTile();
 

	
 
	/* If the new tile is a bridge / tunnel tile, check whether we came from the other
 
	 *  end of the bridge / tunnel or if we just entered the bridge / tunnel. */
 
	if (AIBridge.IsBridgeTile(new_tile)) {
 
		if (AIBridge.GetOtherBridgeEnd(new_tile) != prev_tile) {
 
			local cost = path.GetCost() + self._cost_tile;
 
			if (path.GetParent() != null && path.GetParent().GetTile() - prev_tile != prev_tile - new_tile) cost += self._cost_turn;
 
			return cost;
 
		}
 
		return path.GetCost() + AIMap.DistanceManhattan(new_tile, prev_tile) * self._cost_tile + self._GetBridgeNumSlopes(new_tile, prev_tile) * self._cost_slope;
 
	}
 
	if (AITunnel.IsTunnelTile(new_tile)) {
 
		if (AITunnel.GetOtherTunnelEnd(new_tile) != prev_tile) {
 
			local cost = path.GetCost() + self._cost_tile;
 
			if (path.GetParent() != null && path.GetParent().GetTile() - prev_tile != prev_tile - new_tile) cost += self._cost_turn;
 
			return cost;
 
		}
 
		return path.GetCost() + AIMap.DistanceManhattan(new_tile, prev_tile) * self._cost_tile;
 
	}
 

	
 
	/* If the two tiles are more then 1 tile apart, the pathfinder wants a bridge or tunnel
 
	 *  to be build. It isn't an existing bridge / tunnel, as that case is already handled. */
 
	if (AIMap.DistanceManhattan(new_tile, prev_tile) > 1) {
 
		/* Check if we should build a bridge or a tunnel. */
 
		local cost = path.GetCost();
 
		if (AITunnel.GetOtherTunnelEnd(new_tile) == prev_tile) {
 
			cost += AIMap.DistanceManhattan(new_tile, prev_tile) * (self._cost_tile + self._cost_tunnel_per_tile);
 
		} else {
 
			cost += AIMap.DistanceManhattan(new_tile, prev_tile) * (self._cost_tile + self._cost_bridge_per_tile) + self._GetBridgeNumSlopes(new_tile, prev_tile) * self._cost_slope;
 
		}
 
		if (path.GetParent() != null && path.GetParent().GetParent() != null &&
 
				path.GetParent().GetParent().GetTile() - path.GetParent().GetTile() != max(AIMap.GetTileX(prev_tile) - AIMap.GetTileX(new_tile), AIMap.GetTileY(prev_tile) - AIMap.GetTileY(new_tile)) / AIMap.DistanceManhattan(new_tile, prev_tile)) {
 
			cost += self._cost_turn;
 
		}
 
		return cost;
 
	}
 

	
 
	/* Check for a turn. We do this by substracting the TileID of the current
 
	 *  node from the TileID of the previous node and comparing that to the
 
	 *  difference between the tile before the previous node and the node before
 
	 *  that. */
 
	local cost = self._cost_tile;
 
	if (path.GetParent() != null && AIMap.DistanceManhattan(path.GetParent().GetTile(), prev_tile) == 1 && path.GetParent().GetTile() - prev_tile != prev_tile - new_tile) cost = self._cost_diagonal_tile;
 
	if (path.GetParent() != null && path.GetParent().GetParent() != null &&
 
			AIMap.DistanceManhattan(new_tile, path.GetParent().GetParent().GetTile()) == 3 &&
 
			path.GetParent().GetParent().GetTile() - path.GetParent().GetTile() != prev_tile - new_tile) {
 
		cost += self._cost_turn;
 
	}
 

	
 
	/* Check if the new tile is a coast tile. */
 
	if (AITile.IsCoastTile(new_tile)) {
 
		cost += self._cost_coast;
 
	}
 

	
 
	/* Check if the last tile was sloped. */
 
	if (path.GetParent() != null && !AIBridge.IsBridgeTile(prev_tile) && !AITunnel.IsTunnelTile(prev_tile) &&
 
			self._IsSlopedRail(path.GetParent().GetTile(), prev_tile, new_tile)) {
 
		cost += self._cost_slope;
 
	}
 

	
 
	/* We don't use already existing rail, so the following code is unused. It
 
	 *  assigns if no rail exists along the route. */
 
	/*
 
	if (path.GetParent() != null && !AIRail.AreTilesConnected(path.GetParent().GetTile(), prev_tile, new_tile)) {
 
		cost += self._cost_no_existing_rail;
 
	}
 
	*/
 

	
 
	return path.GetCost() + cost;
 
}
 

	
 
function Rail::_Estimate(cur_tile, cur_direction, goal_tiles, self)
 
{
 
	local min_cost = self._max_cost;
 
	/* As estimate we multiply the lowest possible cost for a single tile with
 
	 *  with the minimum number of tiles we need to traverse. */
 
	foreach (tile in goal_tiles) {
 
		local dx = abs(AIMap.GetTileX(cur_tile) - AIMap.GetTileX(tile[0]));
 
		local dy = abs(AIMap.GetTileY(cur_tile) - AIMap.GetTileY(tile[0]));
 
		min_cost = min(min_cost, min(dx, dy) * self._cost_diagonal_tile * 2 + (max(dx, dy) - min(dx, dy)) * self._cost_tile);
 
	}
 
	return min_cost;
 
}
 

	
 
function Rail::_Neighbours(path, cur_node, self)
 
{
 
	if (AITile.HasTransportType(cur_node, AITile.TRANSPORT_RAIL)) return [];
 
	/* self._max_cost is the maximum path cost, if we go over it, the path isn't valid. */
 
	if (path.GetCost() >= self._max_cost) return [];
 
	local tiles = [];
 
	local offsets = [AIMap.GetTileIndex(0, 1), AIMap.GetTileIndex(0, -1),
 
	                 AIMap.GetTileIndex(1, 0), AIMap.GetTileIndex(-1, 0)];
 

	
 
	/* Check if the current tile is part of a bridge or tunnel. */
 
	if (AIBridge.IsBridgeTile(cur_node) || AITunnel.IsTunnelTile(cur_node)) {
 
		/* We don't use existing rails, so neither existing bridges / tunnels. */
 
	} else if (path.GetParent() != null && AIMap.DistanceManhattan(cur_node, path.GetParent().GetTile()) > 1) {
 
		local other_end = path.GetParent().GetTile();
 
		local next_tile = cur_node + (cur_node - other_end) / AIMap.DistanceManhattan(cur_node, other_end);
 
		foreach (offset in offsets) {
 
			if (AIRail.BuildRail(cur_node, next_tile, next_tile + offset)) {
 
				tiles.push([next_tile, self._GetDirection(other_end, cur_node, next_tile, true)]);
 
			}
 
		}
 
	} else {
 
		/* Check all tiles adjacent to the current tile. */
 
		foreach (offset in offsets) {
 
			local next_tile = cur_node + offset;
 
			/* Don't turn back */
 
			if (path.GetParent() != null && next_tile == path.GetParent().GetTile()) continue;
 
			/* Disallow 90 degree turns */
 
			if (path.GetParent() != null && path.GetParent().GetParent() != null &&
 
				next_tile - cur_node == path.GetParent().GetParent().GetTile() - path.GetParent().GetTile()) continue;
 
			/* We add them to the to the neighbours-list if we can build a rail to
 
			 *  them and no rail exists there. */
 
			if ((path.GetParent() == null || AIRail.BuildRail(path.GetParent().GetTile(), cur_node, next_tile))) {
 
				if (path.GetParent() != null) {
 
					tiles.push([next_tile, self._GetDirection(path.GetParent().GetTile(), cur_node, next_tile, false)]);
 
				} else {
 
					tiles.push([next_tile, self._GetDirection(null, cur_node, next_tile, false)]);
 
				}
 
			}
 
		}
 
		if (path.GetParent() != null && path.GetParent().GetParent() != null) {
 
			local bridges = self._GetTunnelsBridges(path.GetParent().GetTile(), cur_node, self._GetDirection(path.GetParent().GetParent().GetTile(), path.GetParent().GetTile(), cur_node, true));
 
			foreach (tile in bridges) {
 
				tiles.push(tile);
 
			}
 
		}
 
	}
 
	return tiles;
 
}
 

	
 
function Rail::_CheckDirection(tile, existing_direction, new_direction, self)
 
{
 
	return false;
 
}
 

	
 
function Rail::_dir(from, to)
 
{
 
	if (from - to == 1) return 0;
 
	if (from - to == -1) return 1;
 
	if (from - to == AIMap.GetMapSizeX()) return 2;
 
	if (from - to == -AIMap.GetMapSizeX()) return 3;
 
	throw("Shouldn't come here in _dir");
 
}
 

	
 
function Rail::_GetDirection(pre_from, from, to, is_bridge)
 
{
 
	if (is_bridge) {
 
		if (from - to == 1) return 1;
 
		if (from - to == -1) return 2;
 
		if (from - to == AIMap.GetMapSizeX()) return 4;
 
		if (from - to == -AIMap.GetMapSizeX()) return 8;
 
	}
 
	return 1 << (4 + (pre_from == null ? 0 : 4 * this._dir(pre_from, from)) + this._dir(from, to));
 
}
 

	
 
/**
 
 * Get a list of all bridges and tunnels that can be build from the
 
 *  current tile. Bridges will only be build starting on non-flat tiles
 
 *  for performance reasons. Tunnels will only be build if no terraforming
 
 *  is needed on both ends.
 
 */
 
function Rail::_GetTunnelsBridges(last_node, cur_node, bridge_dir)
 
{
 
	local slope = AITile.GetSlope(cur_node);
 
	if (slope == AITile.SLOPE_FLAT && AITile.IsBuildable(cur_node + (cur_node - last_node))) return [];
 
	local tiles = [];
 

	
 
	for (local i = 2; i < this._max_bridge_length; i++) {
 
		local bridge_list = AIBridgeList_Length(i + 1);
 
		local target = cur_node + i * (cur_node - last_node);
 
		if (!bridge_list.IsEmpty() && AIBridge.BuildBridge(AIVehicle.VEHICLE_RAIL, bridge_list.Begin(), cur_node, target)) {
 
			tiles.push([target, bridge_dir]);
 
		}
 
	}
 

	
 
	if (slope != AITile.SLOPE_SW && slope != AITile.SLOPE_NW && slope != AITile.SLOPE_SE && slope != AITile.SLOPE_NE) return tiles;
 
	local other_tunnel_end = AITunnel.GetOtherTunnelEnd(cur_node);
 
	if (!AIMap.IsValidTile(other_tunnel_end)) return tiles;
 

	
 
	local tunnel_length = AIMap.DistanceManhattan(cur_node, other_tunnel_end);
 
	local prev_tile = cur_node + (cur_node - other_tunnel_end) / tunnel_length;
 
	if (AITunnel.GetOtherTunnelEnd(other_tunnel_end) == cur_node && tunnel_length >= 2 &&
 
			prev_tile == last_node && tunnel_length < _max_tunnel_length && AITunnel.BuildTunnel(AIVehicle.VEHICLE_RAIL, cur_node)) {
 
		tiles.push([other_tunnel_end, bridge_dir]);
 
	}
 
	return tiles;
 
}
 

	
 
function Rail::_IsSlopedRail(start, middle, end)
 
{
 
	local NW = 0; // Set to true if we want to build a rail to / from the north-west
 
	local NE = 0; // Set to true if we want to build a rail to / from the north-east
 
	local SW = 0; // Set to true if we want to build a rail to / from the south-west
 
	local SE = 0; // Set to true if we want to build a rail to / from the south-east
 

	
 
	if (middle - AIMap.GetMapSizeX() == start || middle - AIMap.GetMapSizeX() == end) NW = 1;
 
	if (middle - 1 == start || middle - 1 == end) NE = 1;
 
	if (middle + AIMap.GetMapSizeX() == start || middle + AIMap.GetMapSizeX() == end) SE = 1;
 
	if (middle + 1 == start || middle + 1 == end) SW = 1;
 

	
 
	/* If there is a turn in the current tile, it can't be sloped. */
 
	if ((NW || SE) && (NE || SW)) return false;
 

	
 
	local slope = AITile.GetSlope(middle);
 
	/* A rail on a steep slope is always sloped. */
 
	if (AITile.IsSteepSlope(slope)) return true;
 

	
 
	/* If only one corner is raised, the rail is sloped. */
 
	if (slope == AITile.SLOPE_N || slope == AITile.SLOPE_W) return true;
 
	if (slope == AITile.SLOPE_S || slope == AITile.SLOPE_E) return true;
 

	
 
	if (NW && (slope == AITile.SLOPE_NW || slope == AITile.SLOPE_SE)) return true;
 
	if (NE && (slope == AITile.SLOPE_NE || slope == AITile.SLOPE_SW)) return true;
 

	
 
	return false;
 
}
bin/ai/library/pathfinder/road/library.nut
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
class Road extends AILibrary {
 
	function GetAuthor()      { return "OpenTTD NoAI Developers Team"; }
 
	function GetName()        { return "Road"; }
 
	function GetDescription() { return "An implementation of a road pathfinder"; }
 
	function GetVersion()     { return 3; }
 
	function GetDate()        { return "2008-06-18"; }
 
	function CreateInstance() { return "Road"; }
 
}
 

	
 
RegisterLibrary(Road());
bin/ai/library/pathfinder/road/main.nut
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/**
 
 * A Road Pathfinder.
 
 *  This road pathfinder tries to find a buildable / existing route for
 
 *  road vehicles. You can changes the costs below using for example
 
 *  roadpf.cost.turn = 30. Note that it's not allowed to change the cost
 
 *  between consecutive calls to FindPath. You can change the cost before
 
 *  the first call to FindPath and after FindPath has returned an actual
 
 *  route. To use only existing roads, set cost.no_existing_road to
 
 *  cost.max_cost.
 
 */
 
class Road
 
{
 
	_aystar_class = import("graph.aystar", "", 4);
 
	_max_cost = null;              ///< The maximum cost for a route.
 
	_cost_tile = null;             ///< The cost for a single tile.
 
	_cost_no_existing_road = null; ///< The cost that is added to _cost_tile if no road exists yet.
 
	_cost_turn = null;             ///< The cost that is added to _cost_tile if the direction changes.
 
	_cost_slope = null;            ///< The extra cost if a road tile is sloped.
 
	_cost_bridge_per_tile = null;  ///< The cost per tile of a new bridge, this is added to _cost_tile.
 
	_cost_tunnel_per_tile = null;  ///< The cost per tile of a new tunnel, this is added to _cost_tile.
 
	_cost_coast = null;            ///< The extra cost for a coast tile.
 
	_pathfinder = null;            ///< A reference to the used AyStar object.
 
	_max_bridge_length = null;     ///< The maximum length of a bridge that will be build.
 
	_max_tunnel_length = null;     ///< The maximum length of a tunnel that will be build.
 

	
 
	cost = null;                   ///< Used to change the costs.
 
	_running = null;
 

	
 
	constructor()
 
	{
 
		this._max_cost = 10000000;
 
		this._cost_tile = 100;
 
		this._cost_no_existing_road = 40;
 
		this._cost_turn = 100;
 
		this._cost_slope = 200;
 
		this._cost_bridge_per_tile = 150;
 
		this._cost_tunnel_per_tile = 120;
 
		this._cost_coast = 20;
 
		this._max_bridge_length = 10;
 
		this._max_tunnel_length = 20;
 
		this._pathfinder = this._aystar_class(this._Cost, this._Estimate, this._Neighbours, this._CheckDirection, this, this, this, this);
 

	
 
		this.cost = this.Cost(this);
 
		this._running = false;
 
	}
 

	
 
	/**
 
	 * Initialize a path search between sources and goals.
 
	 * @param sources The source tiles.
 
	 * @param goals The target tiles.
 
	 * @see AyStar::InitializePath()
 
	 */
 
	function InitializePath(sources, goals) {
 
		local nsources = [];
 

	
 
		foreach (node in sources) {
 
			nsources.push([node, 0xFF]);
 
		}
 
		this._pathfinder.InitializePath(nsources, goals);
 
	}
 

	
 
	/**
 
	 * Try to find the path as indicated with InitializePath with the lowest cost.
 
	 * @param iterations After how many iterations it should abort for a moment.
 
	 *  This value should either be -1 for infinite, or > 0. Any other value
 
	 *  aborts immediatly and will never find a path.
 
	 * @return A route if one was found, or false if the amount of iterations was
 
	 *  reached, or null if no path was found.
 
	 *  You can call this function over and over as long as it returns false,
 
	 *  which is an indication it is not yet done looking for a route.
 
	 * @see AyStar::FindPath()
 
	 */
 
	function FindPath(iterations);
 
};
 

	
 
class Road.Cost
 
{
 
	_main = null;
 

	
 
	function _set(idx, val)
 
	{
 
		if (this._main._running) throw("You are not allowed to change parameters of a running pathfinder.");
 

	
 
		switch (idx) {
 
			case "max_cost":          this._main._max_cost = val; break;
 
			case "tile":              this._main._cost_tile = val; break;
 
			case "no_existing_road":  this._main._cost_no_existing_road = val; break;
 
			case "turn":              this._main._cost_turn = val; break;
 
			case "slope":             this._main._cost_slope = val; break;
 
			case "bridge_per_tile":   this._main._cost_bridge_per_tile = val; break;
 
			case "tunnel_per_tile":   this._main._cost_tunnel_per_tile = val; break;
 
			case "coast":             this._main._cost_coast = val; break;
 
			case "max_bridge_length": this._main._max_bridge_length = val; break;
 
			case "max_tunnel_length": this._main._max_tunnel_length = val; break;
 
			default: throw("the index '" + idx + "' does not exist");
 
		}
 

	
 
		return val;
 
	}
 

	
 
	function _get(idx)
 
	{
 
		switch (idx) {
 
			case "max_cost":          return this._main._max_cost;
 
			case "tile":              return this._main._cost_tile;
 
			case "no_existing_road":  return this._main._cost_no_existing_road;
 
			case "turn":              return this._main._cost_turn;
 
			case "slope":             return this._main._cost_slope;
 
			case "bridge_per_tile":   return this._main._cost_bridge_per_tile;
 
			case "tunnel_per_tile":   return this._main._cost_tunnel_per_tile;
 
			case "coast":             return this._main._cost_coast;
 
			case "max_bridge_length": return this._main._max_bridge_length;
 
			case "max_tunnel_length": return this._main._max_tunnel_length;
 
			default: throw("the index '" + idx + "' does not exist");
 
		}
 
	}
 

	
 
	constructor(main)
 
	{
 
		this._main = main;
 
	}
 
};
 

	
 
function Road::FindPath(iterations)
 
{
 
	local test_mode = AITestMode();
 
	local ret = this._pathfinder.FindPath(iterations);
 
	this._running = (ret == false) ? true : false;
 
	return ret;
 
}
 

	
 
function Road::_GetBridgeNumSlopes(end_a, end_b)
 
{
 
	local slopes = 0;
 
	local direction = (end_b - end_a) / AIMap.DistanceManhattan(end_a, end_b);
 
	local slope = AITile.GetSlope(end_a);
 
	if (!((slope == AITile.SLOPE_NE && direction == 1) || (slope == AITile.SLOPE_SE && direction == -AIMap.GetMapSizeX()) ||
 
		(slope == AITile.SLOPE_SW && direction == -1) || (slope == AITile.SLOPE_NW && direction == AIMap.GetMapSizeX()) ||
 
		 slope == AITile.SLOPE_N || slope == AITile.SLOPE_E || slope == AITile.SLOPE_S || slope == AITile.SLOPE_W)) {
 
		slopes++;
 
	}
 

	
 
	local slope = AITile.GetSlope(end_b);
 
	direction = -direction;
 
	if (!((slope == AITile.SLOPE_NE && direction == 1) || (slope == AITile.SLOPE_SE && direction == -AIMap.GetMapSizeX()) ||
 
		(slope == AITile.SLOPE_SW && direction == -1) || (slope == AITile.SLOPE_NW && direction == AIMap.GetMapSizeX()) ||
 
		 slope == AITile.SLOPE_N || slope == AITile.SLOPE_E || slope == AITile.SLOPE_S || slope == AITile.SLOPE_W)) {
 
		slopes++;
 
	}
 
	return slopes;
 
}
 

	
 
function Road::_Cost(path, new_tile, new_direction, self)
 
{
 
	/* path == null means this is the first node of a path, so the cost is 0. */
 
	if (path == null) return 0;
 

	
 
	local prev_tile = path.GetTile();
 

	
 
	/* If the new tile is a bridge / tunnel tile, check whether we came from the other
 
	 * end of the bridge / tunnel or if we just entered the bridge / tunnel. */
 
	if (AIBridge.IsBridgeTile(new_tile)) {
 
		if (AIBridge.GetOtherBridgeEnd(new_tile) != prev_tile) return path.GetCost() + self._cost_tile;
 
		return path.GetCost() + AIMap.DistanceManhattan(new_tile, prev_tile) * self._cost_tile + self._GetBridgeNumSlopes(new_tile, prev_tile) * self._cost_slope;
 
	}
 
	if (AITunnel.IsTunnelTile(new_tile)) {
 
		if (AITunnel.GetOtherTunnelEnd(new_tile) != prev_tile) return path.GetCost() + self._cost_tile;
 
		return path.GetCost() + AIMap.DistanceManhattan(new_tile, prev_tile) * self._cost_tile;
 
	}
 

	
 
	/* If the two tiles are more then 1 tile apart, the pathfinder wants a bridge or tunnel
 
	 * to be build. It isn't an existing bridge / tunnel, as that case is already handled. */
 
	if (AIMap.DistanceManhattan(new_tile, prev_tile) > 1) {
 
		/* Check if we should build a bridge or a tunnel. */
 
		if (AITunnel.GetOtherTunnelEnd(new_tile) == prev_tile) {
 
			return path.GetCost() + AIMap.DistanceManhattan(new_tile, prev_tile) * (self._cost_tile + self._cost_tunnel_per_tile);
 
		} else {
 
			return path.GetCost() + AIMap.DistanceManhattan(new_tile, prev_tile) * (self._cost_tile + self._cost_bridge_per_tile) + self._GetBridgeNumSlopes(new_tile, prev_tile) * self._cost_slope;
 
		}
 
	}
 

	
 
	/* Check for a turn. We do this by substracting the TileID of the current node from
 
	 * the TileID of the previous node and comparing that to the difference between the
 
	 * previous node and the node before that. */
 
	local cost = self._cost_tile;
 
	if (path.GetParent() != null && (prev_tile - path.GetParent().GetTile()) != (new_tile - prev_tile) &&
 
		AIMap.DistanceManhattan(path.GetParent().GetTile(), prev_tile) == 1) {
 
		cost += self._cost_turn;
 
	}
 

	
 
	/* Check if the new tile is a coast tile. */
 
	if (AITile.IsCoastTile(new_tile)) {
 
		cost += self._cost_coast;
 
	}
 

	
 
	/* Check if the last tile was sloped. */
 
	if (path.GetParent() != null && !AIBridge.IsBridgeTile(prev_tile) && !AITunnel.IsTunnelTile(prev_tile) &&
 
	    self._IsSlopedRoad(path.GetParent().GetTile(), prev_tile, new_tile)) {
 
		cost += self._cost_slope;
 
	}
 

	
 
	if (!AIRoad.AreRoadTilesConnected(prev_tile, new_tile)) {
 
		cost += self._cost_no_existing_road;
 
	}
 

	
 
	return path.GetCost() + cost;
 
}
 

	
 
function Road::_Estimate(cur_tile, cur_direction, goal_tiles, self)
 
{
 
	local min_cost = self._max_cost;
 
	/* As estimate we multiply the lowest possible cost for a single tile with
 
	 * with the minimum number of tiles we need to traverse. */
 
	foreach (tile in goal_tiles) {
 
		min_cost = min(AIMap.DistanceManhattan(cur_tile, tile) * self._cost_tile, min_cost);
 
	}
 
	return min_cost;
 
}
 

	
 
function Road::_Neighbours(path, cur_node, self)
 
{
 
	/* self._max_cost is the maximum path cost, if we go over it, the path isn't valid. */
 
	if (path.GetCost() >= self._max_cost) return [];
 
	local tiles = [];
 

	
 
	/* Check if the current tile is part of a bridge or tunnel. */
 
	if ((AIBridge.IsBridgeTile(cur_node) || AITunnel.IsTunnelTile(cur_node)) &&
 
	     AITile.HasTransportType(cur_node, AITile.TRANSPORT_ROAD)) {
 
		local other_end = AIBridge.IsBridgeTile(cur_node) ? AIBridge.GetOtherBridgeEnd(cur_node) : AITunnel.GetOtherTunnelEnd(cur_node);
 
		local next_tile = cur_node + (cur_node - other_end) / AIMap.DistanceManhattan(cur_node, other_end);
 
		if (AIRoad.AreRoadTilesConnected(cur_node, next_tile) || AITile.IsBuildable(next_tile) || AIRoad.IsRoadTile(next_tile)) {
 
			tiles.push([next_tile, self._GetDirection(cur_node, next_tile, false)]);
 
		}
 
		/* The other end of the bridge / tunnel is a neighbour. */
 
		tiles.push([other_end, self._GetDirection(next_tile, cur_node, true) << 4]);
 
	} else if (path.GetParent() != null && AIMap.DistanceManhattan(cur_node, path.GetParent().GetTile()) > 1) {
 
		local other_end = path.GetParent().GetTile();
 
		local next_tile = cur_node + (cur_node - other_end) / AIMap.DistanceManhattan(cur_node, other_end);
 
		if (AIRoad.AreRoadTilesConnected(cur_node, next_tile) || AIRoad.BuildRoad(cur_node, next_tile)) {
 
			tiles.push([next_tile, self._GetDirection(cur_node, next_tile, false)]);
 
		}
 
	} else {
 
		local offsets = [AIMap.GetTileIndex(0, 1), AIMap.GetTileIndex(0, -1),
 
		                 AIMap.GetTileIndex(1, 0), AIMap.GetTileIndex(-1, 0)];
 
		/* Check all tiles adjacent to the current tile. */
 
		foreach (offset in offsets) {
 
			local next_tile = cur_node + offset;
 
			/* We add them to the to the neighbours-list if one of the following applies:
 
			 * 1) There already is a connections between the current tile and the next tile.
 
			 * 2) We can build a road to the next tile.
 
			 * 3) The next tile is the entrance of a tunnel / bridge in the correct direction. */
 
			if (AIRoad.AreRoadTilesConnected(cur_node, next_tile)) {
 
				tiles.push([next_tile, self._GetDirection(cur_node, next_tile, false)]);
 
			} else if ((AITile.IsBuildable(next_tile) || AIRoad.IsRoadTile(next_tile)) &&
 
					(path.GetParent() == null || AIRoad.CanBuildConnectedRoadPartsHere(cur_node, path.GetParent().GetTile(), next_tile)) &&
 
					AIRoad.BuildRoad(cur_node, next_tile)) {
 
				tiles.push([next_tile, self._GetDirection(cur_node, next_tile, false)]);
 
			} else if (self._CheckTunnelBridge(cur_node, next_tile)) {
 
				tiles.push([next_tile, self._GetDirection(cur_node, next_tile, false)]);
 
			}
 
		}
 
		if (path.GetParent() != null) {
 
			local bridges = self._GetTunnelsBridges(path.GetParent().GetTile(), cur_node, self._GetDirection(path.GetParent().GetTile(), cur_node, true) << 4);
 
			foreach (tile in bridges) {
 
				tiles.push(tile);
 
			}
 
		}
 
	}
 
	return tiles;
 
}
 

	
 
function Road::_CheckDirection(tile, existing_direction, new_direction, self)
 
{
 
	return false;
 
}
 

	
 
function Road::_GetDirection(from, to, is_bridge)
 
{
 
	if (!is_bridge && AITile.GetSlope(to) == AITile.SLOPE_FLAT) return 0xFF;
 
	if (from - to == 1) return 1;
 
	if (from - to == -1) return 2;
 
	if (from - to == AIMap.GetMapSizeX()) return 4;
 
	if (from - to == -AIMap.GetMapSizeX()) return 8;
 
}
 

	
 
/**
 
 * Get a list of all bridges and tunnels that can be build from the
 
 * current tile. Bridges will only be build starting on non-flat tiles
 
 * for performance reasons. Tunnels will only be build if no terraforming
 
 * is needed on both ends.
 
 */
 
function Road::_GetTunnelsBridges(last_node, cur_node, bridge_dir)
 
{
 
	local slope = AITile.GetSlope(cur_node);
 
	if (slope == AITile.SLOPE_FLAT) return [];
 
	local tiles = [];
 

	
 
	for (local i = 2; i < this._max_bridge_length; i++) {
 
		local bridge_list = AIBridgeList_Length(i + 1);
 
		local target = cur_node + i * (cur_node - last_node);
 
		if (!bridge_list.IsEmpty() && AIBridge.BuildBridge(AIVehicle.VEHICLE_ROAD, bridge_list.Begin(), cur_node, target)) {
 
			tiles.push([target, bridge_dir]);
 
		}
 
	}
 

	
 
	if (slope != AITile.SLOPE_SW && slope != AITile.SLOPE_NW && slope != AITile.SLOPE_SE && slope != AITile.SLOPE_NE) return tiles;
 
	local other_tunnel_end = AITunnel.GetOtherTunnelEnd(cur_node);
 
	if (!AIMap.IsValidTile(other_tunnel_end)) return tiles;
 

	
 
	local tunnel_length = AIMap.DistanceManhattan(cur_node, other_tunnel_end);
 
	local prev_tile = cur_node + (cur_node - other_tunnel_end) / tunnel_length;
 
	if (AITunnel.GetOtherTunnelEnd(other_tunnel_end) == cur_node && tunnel_length >= 2 &&
 
			prev_tile == last_node && tunnel_length < _max_tunnel_length && AITunnel.BuildTunnel(AIVehicle.VEHICLE_ROAD, cur_node)) {
 
		tiles.push([other_tunnel_end, bridge_dir]);
 
	}
 
	return tiles;
 
}
 

	
 
function Road::_IsSlopedRoad(start, middle, end)
 
{
 
	local NW = 0; //Set to true if we want to build a road to / from the north-west
 
	local NE = 0; //Set to true if we want to build a road to / from the north-east
 
	local SW = 0; //Set to true if we want to build a road to / from the south-west
 
	local SE = 0; //Set to true if we want to build a road to / from the south-east
 

	
 
	if (middle - AIMap.GetMapSizeX() == start || middle - AIMap.GetMapSizeX() == end) NW = 1;
 
	if (middle - 1 == start || middle - 1 == end) NE = 1;
 
	if (middle + AIMap.GetMapSizeX() == start || middle + AIMap.GetMapSizeX() == end) SE = 1;
 
	if (middle + 1 == start || middle + 1 == end) SW = 1;
 

	
 
	/* If there is a turn in the current tile, it can't be sloped. */
 
	if ((NW || SE) && (NE || SW)) return false;
 

	
 
	local slope = AITile.GetSlope(middle);
 
	/* A road on a steep slope is always sloped. */
 
	if (AITile.IsSteepSlope(slope)) return true;
 

	
 
	/* If only one corner is raised, the road is sloped. */
 
	if (slope == AITile.SLOPE_N || slope == AITile.SLOPE_W) return true;
 
	if (slope == AITile.SLOPE_S || slope == AITile.SLOPE_E) return true;
 

	
 
	if (NW && (slope == AITile.SLOPE_NW || slope == AITile.SLOPE_SE)) return true;
 
	if (NE && (slope == AITile.SLOPE_NE || slope == AITile.SLOPE_SW)) return true;
 

	
 
	return false;
 
}
 

	
 
function Road::_CheckTunnelBridge(current_tile, new_tile)
 
{
 
	if (!AIBridge.IsBridgeTile(new_tile) && !AITunnel.IsTunnelTile(new_tile)) return false;
 
	local dir = new_tile - current_tile;
 
	local other_end = AIBridge.IsBridgeTile(new_tile) ? AIBridge.GetOtherBridgeEnd(new_tile) : AITunnel.GetOtherTunnelEnd(new_tile);
 
	local dir2 = other_end - new_tile;
 
	if ((dir < 0 && dir2 > 0) || (dir > 0 && dir2 < 0)) return false;
 
	dir = abs(dir);
 
	dir2 = abs(dir2);
 
	if ((dir >= AIMap.GetMapSizeX() && dir2 < AIMap.GetMapSizeX()) ||
 
	    (dir < AIMap.GetMapSizeX() && dir2 >= AIMap.GetMapSizeX())) return false;
 

	
 
	return true;
 
}
bin/ai/library/queue/binary_heap/library.nut
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
class BinaryHeap extends AILibrary {
 
	function GetAuthor()      { return "OpenTTD NoAI Developers Team"; }
 
	function GetName()        { return "Binary Heap"; }
 
	function GetDescription() { return "An implementation of a Binary Heap"; }
 
	function GetVersion()     { return 1; }
 
	function GetDate()        { return "2008-06-10"; }
 
	function CreateInstance() { return "BinaryHeap"; }
 
}
 

	
 
RegisterLibrary(BinaryHeap());
bin/ai/library/queue/binary_heap/main.nut
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/**
 
 * Binary Heap.
 
 *  Peek and Pop always return the current lowest value in the list.
 
 *  Sort is done on insertion and on deletion.
 
 */
 
class BinaryHeap
 
{
 
	_queue = null;
 
	_count = 0;
 

	
 
	constructor()
 
	{
 
		_queue = [];
 
	}
 

	
 
	/**
 
	 * Insert a new entry in the list.
 
	 *  The complexity of this operation is O(ln n).
 
	 * @param item The item to add to the list.
 
	 * @param priority The priority this item has.
 
	 */
 
	function Insert(item, priority);
 

	
 
	/**
 
	 * Pop the first entry of the list.
 
	 *  This is always the item with the lowest priority.
 
	 *  The complexity of this operation is O(ln n).
 
	 * @return The item of the entry with the lowest priority.
 
	 */
 
	function Pop();
 

	
 
	/**
 
	 * Peek the first entry of the list.
 
	 *  This is always the item with the lowest priority.
 
	 *  The complexity of this operation is O(1).
 
	 * @return The item of the entry with the lowest priority.
 
	 */
 
	function Peek();
 

	
 
	/**
 
	 * Get the amount of current items in the list.
 
	 *  The complexity of this operation is O(1).
 
	 * @return The amount of items currently in the list.
 
	 */
 
	function Count();
 

	
 
	/**
 
	 * Check if an item exists in the list.
 
	 *  The complexity of this operation is O(n).
 
	 * @param item The item to check for.
 
	 * @return True if the item is already in the list.
 
	 */
 
	function Exists(item);
 
};
 

	
 
function BinaryHeap::Insert(item, priority)
 
{
 
	/* Append dummy entry */
 
	_queue.append(0);
 
	_count++;
 

	
 
	local hole;
 
	/* Find the point of insertion */
 
	for (hole = _count - 1; hole > 0 && priority <= _queue[hole / 2][1]; hole /= 2)
 
		_queue[hole] = _queue[hole / 2];
 
	/* Insert new pair */
 
	_queue[hole] = [item, priority];
 

	
 
	return true;
 
}
 

	
 
function BinaryHeap::Pop()
 
{
 
	if (_count == 0) return null;
 

	
 
	local node = _queue[0];
 
	/* Remove the item from the list by putting the last value on top */
 
	_queue[0] = _queue[_count - 1];
 
	_queue.pop();
 
	_count--;
 
	/* Bubble down the last value to correct the tree again */
 
	_BubbleDown();
 

	
 
	return node[0];
 
}
 

	
 
function BinaryHeap::Peek()
 
{
 
	if (_count == 0) return null;
 

	
 
	return _queue[0][0];
 
}
 

	
 
function BinaryHeap::Count()
 
{
 
	return _count;
 
}
 

	
 
function BinaryHeap::Exists(item)
 
{
 
	/* Brute-force find the item (there is no faster way, as we don't have the priority number) */
 
	foreach (node in _queue) {
 
		if (node[0] == item) return true;
 
	}
 

	
 
	return false;
 
}
 

	
 

	
 

	
 
function BinaryHeap::_BubbleDown()
 
{
 
	if (_count == 0) return;
 

	
 
	local hole = 1;
 
	local tmp = _queue[0];
 

	
 
	/* Start switching parent and child until the tree is restored */
 
	while (hole * 2 < _count + 1) {
 
		local child = hole * 2;
 
		if (child != _count && _queue[child][1] <= _queue[child - 1][1]) child++;
 
		if (_queue[child - 1][1] > tmp[1]) break;
 

	
 
		_queue[hole - 1] = _queue[child - 1];
 
		hole = child;
 
	}
 
	/* The top value is now at his new place */
 
	_queue[hole - 1] = tmp;
 
}
bin/ai/library/queue/fibonacci_heap/library.nut
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
class FibonacciHeap extends AILibrary {
 
	function GetAuthor()      { return "OpenTTD NoAI Developers Team"; }
 
	function GetName()        { return "Fibonacci Heap"; }
 
	function GetDescription() { return "An implementation of a Fibonacci Heap"; }
 
	function GetVersion()     { return 1; }
 
	function GetDate()        { return "2008-08-22"; }
 
	function CreateInstance() { return "FibonacciHeap"; }
 
}
 

	
 
RegisterLibrary(FibonacciHeap());
bin/ai/library/queue/fibonacci_heap/main.nut
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/**
 
 * Fibonacci heap.
 
 *  This heap is heavily optimized for the Insert and Pop functions.
 
 *  Peek and Pop always return the current lowest value in the list.
 
 *  Insert is implemented as a lazy insert, as it will simply add the new
 
 *  node to the root list. Sort is done on every Pop operation.
 
 */
 
class FibonacciHeap {
 
	_min = null;
 
	_min_index = 0;
 
	_min_priority = 0;
 
	_count = 0;
 
	_root_list = null;
 

	
 
	/**
 
	 * Create a new fibonacci heap.
 
	 * http://en.wikipedia.org/wiki/Fibonacci_heap
 
	 */
 
	constructor() {
 
		_count = 0;
 
		_min = Node();
 
		_min.priority = 0x7FFFFFFF;
 
		_min_index = 0;
 
		_min_priority = 0x7FFFFFFF;
 
		_root_list = [];
 
	}
 

	
 
	/**
 
	 * Insert a new entry in the heap.
 
	 *  The complexity of this operation is O(1).
 
	 * @param item The item to add to the list.
 
	 * @param priority The priority this item has.
 
	 */
 
	function Insert(item, priority);
 

	
 
	/**
 
	 * Pop the first entry of the list.
 
	 *  This is always the item with the lowest priority.
 
	 *  The complexity of this operation is O(ln n).
 
	 * @return The item of the entry with the lowest priority.
 
	 */
 
	function Pop();
 

	
 
	/**
 
	 * Peek the first entry of the list.
 
	 *  This is always the item with the lowest priority.
 
	 *  The complexity of this operation is O(1).
 
	 * @return The item of the entry with the lowest priority.
 
	 */
 
	function Peek();
 

	
 
	/**
 
	 * Get the amount of current items in the list.
 
	 *  The complexity of this operation is O(1).
 
	 * @return The amount of items currently in the list.
 
	 */
 
	function Count();
 

	
 
	/**
 
	 * Check if an item exists in the list.
 
	 *  The complexity of this operation is O(n).
 
	 * @param item The item to check for.
 
	 * @return True if the item is already in the list.
 
	 */
 
	function Exists(item);
 
};
 

	
 
function FibonacciHeap::Insert(item, priority) {
 
	/* Create a new node instance to add to the heap. */
 
	local node = Node();
 
	/* Changing params is faster than using constructor values */
 
	node.item = item;
 
	node.priority = priority;
 

	
 
	/* Update the reference to the minimum node if this node has a
 
	 * smaller priority. */
 
	if (_min_priority > priority) {
 
		_min = node;
 
		_min_index = _root_list.len();
 
		_min_priority = priority;
 
	}
 

	
 
	_root_list.append(node);
 
	_count++;
 
}
 

	
 
function FibonacciHeap::Pop() {
 

	
 
	if (_count == 0) return null;
 

	
 
	/* Bring variables from the class scope to this scope explicitly to
 
	 * optimize variable lookups by Squirrel. */
 
	local z = _min;
 
	local tmp_root_list = _root_list;
 

	
 
	/* If there are any children, bring them all to the root level. */
 
	tmp_root_list.extend(z.child);
 

	
 
	/* Remove the minimum node from the rootList. */
 
	tmp_root_list.remove(_min_index);
 
	local root_cache = {};
 

	
 
	/* Now we decrease the number of nodes on the root level by
 
	 * merging nodes which have the same degree. The node with
 
	 * the lowest priority value will become the parent. */
 
	foreach(x in tmp_root_list) {
 
		local y;
 

	
 
		/* See if we encountered a node with the same degree already. */
 
		while (y = root_cache.rawdelete(x.degree)) {
 
			/* Check the priorities. */
 
			if (x.priority > y.priority) {
 
				local tmp = x;
 
				x = y;
 
				y = tmp;
 
			}
 

	
 
			/* Make y a child of x. */
 
			x.child.append(y);
 
			x.degree++;
 
		}
 

	
 
		root_cache[x.degree] <- x;
 
	}
 

	
 
	/* The root_cache contains all the nodes which will form the
 
	 *  new rootList. We reset the priority to the maximum number
 
	 *  for a 32 signed integer to find a new minumum. */
 
	tmp_root_list.resize(root_cache.len());
 
	local i = 0;
 
	local tmp_min_priority = 0x7FFFFFFF;
 

	
 
	/* Now we need to find the new minimum among the root nodes. */
 
	foreach (val in root_cache) {
 
		if (val.priority < tmp_min_priority) {
 
			_min = val;
 
			_min_index = i;
 
			tmp_min_priority = val.priority;
 
		}
 

	
 
		tmp_root_list[i++] = val;
 
	}
 

	
 
	/* Update global variables. */
 
	_min_priority = tmp_min_priority;
 

	
 
	_count--;
 
	return z.item;
 
}
 

	
 
function FibonacciHeap::Peek() {
 
	if (_count == 0) return null;
 
	return _min.item;
 
}
 

	
 
function FibonacciHeap::Count() {
 
	return _count;
 
}
 

	
 
function FibonacciHeap::Exists(item) {
 
	return ExistsIn(_root_list, item);
 
}
 

	
 
/**
 
 * Auxilary function to search through the whole heap.
 
 * @param list The list of nodes to look through.
 
 * @param item The item to search for.
 
 * @return True if the item is found, false otherwise.
 
 */
 
function FibonacciHeap::ExistsIn(list, item) {
 

	
 
	foreach (val in list) {
 
		if (val.item == item) {
 
			return true;
 
		}
 

	
 
		foreach (c in val.child) {
 
			if (ExistsIn(c, item)) {
 
				return true;
 
			}
 
		}
 
	}
 

	
 
	/* No luck, item doesn't exists in the tree rooted under list. */
 
	return false;
 
}
 

	
 
/**
 
 * Basic class the fibonacci heap is composed of.
 
 */
 
class FibonacciHeap.Node {
 
	degree = null;
 
	child = null;
 

	
 
	item = null;
 
	priority = null;
 

	
 
	constructor() {
 
		child = [];
 
		degree = 0;
 
	}
 
};
bin/ai/library/queue/priority_queue/library.nut
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
class PriorityQueue extends AILibrary {
 
	function GetAuthor()      { return "OpenTTD NoAI Developers Team"; }
 
	function GetName()        { return "Priority Queue"; }
 
	function GetDescription() { return "An implementation of a Priority Queue"; }
 
	function GetVersion()     { return 2; }
 
	function GetDate()        { return "2008-06-10"; }
 
	function CreateInstance() { return "PriorityQueue"; }
 
}
 

	
 
RegisterLibrary(PriorityQueue());
bin/ai/library/queue/priority_queue/main.nut
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/**
 
 * Priority Queue.
 
 *  Peek and Pop always return the current lowest value in the list.
 
 *  Sort is done on insertion only.
 
 */
 
class PriorityQueue
 
{
 
	_queue = null;
 
	_count = 0;
 

	
 
	constructor()
 
	{
 
		_count = 0;
 
		_queue = [];
 
	}
 

	
 
	/**
 
	 * Insert a new entry in the list.
 
	 *  The complexity of this operation is O(n).
 
	 * @param item The item to add to the list.
 
	 * @param priority The priority this item has.
 
	 */
 
	function Insert(item, priority);
 

	
 
	/**
 
	 * Pop the first entry of the list.
 
	 *  This is always the item with the lowest priority.
 
	 *  The complexity of this operation is O(1).
 
	 * @return The item of the entry with the lowest priority.
 
	 */
 
	function Pop();
 

	
 
	/**
 
	 * Peek the first entry of the list.
 
	 *  This is always the item with the lowest priority.
 
	 *  The complexity of this operation is O(1).
 
	 * @return The item of the entry with the lowest priority.
 
	 */
 
	function Peek();
 

	
 
	/**
 
	 * Get the amount of current items in the list.
 
	 *  The complexity of this operation is O(1).
 
	 * @return The amount of items currently in the list.
 
	 */
 
	function Count();
 

	
 
	/**
 
	 * Check if an item exists in the list.
 
	 *  The complexity of this operation is O(n).
 
	 * @param item The item to check for.
 
	 * @return True if the item is already in the list.
 
	 */
 
	function Exists(item);
 
};
 

	
 
function PriorityQueue::Insert(item, priority)
 
{
 
	/* Append dummy entry */
 
	_queue.append(0);
 
	_count++;
 

	
 
	local i;
 
	/* Find the point of insertion */
 
	for (i = _count - 2; i >= 0; i--) {
 
		if (priority > _queue[i][1]) {
 
			/* All items bigger move one place to the right */
 
			_queue[i + 1] = _queue[i];
 
		} else if (item == _queue[i][0]) {
 
			/* Same item, ignore insertion */
 
			return false;
 
		} else {
 
			/* Found place to insert at */
 
			break;
 
		}
 
	}
 
	/* Insert new pair */
 
	_queue[i + 1] = [item, priority];
 

	
 
	return true;
 
}
 

	
 
function PriorityQueue::Pop()
 
{
 
	if (_count == 0) return null;
 

	
 
	local node = _queue.pop();
 
	_count--;
 

	
 
	return node[0];
 
}
 

	
 
function PriorityQueue::Peek()
 
{
 
	if (_count == 0) return null;
 

	
 
	return _queue[_count - 1][0];
 
}
 

	
 
function PriorityQueue::Count()
 
{
 
	return _count;
 
}
 

	
 
function PriorityQueue::Exists(item)
 
{
 
	/* Brute-force find the item (there is no faster way, as we don't have the priority number) */
 
	foreach (node in _queue) {
 
		if (node[0] == item) return true;
 
	}
 

	
 
	return false;
 
}
bin/ai/regression/completeness.sh
Show inline comments
 
new file 100644
 
#!/bin/sh
 

	
 
if ! [ -f ai/regression/regression.nut ]; then
 
	echo "Make sure you are in the root of OpenTTD before starting this script."
 
	exit 1
 
fi
 

	
 
cat ai/regression/regression.nut | tr ';' '\n' | awk '
 
/^function/ {
 
	for (local in locals) {
 
		delete locals[local]
 
	}
 
	if (match($0, "function Regression::Start") || match($0, "function Regression::Stop")) next
 
	locals["this"] = "AIControllerSquirrel"
 
}
 

	
 
/local/ {
 
	gsub(".*local", "local")
 
	if (match($4, "^AI")) {
 
		sub("\\(.*", "", $4)
 
		locals[$2] = $4
 
	}
 
}
 

	
 
/Valuate/ {
 
	gsub(".*Valuate\\(", "")
 
	gsub("\\).*", "")
 
	gsub(",.*", "")
 
	gsub("\\.", "::")
 
	print $0
 
}
 

	
 
/\./ {
 
	for (local in locals) {
 
		if (match($0, local ".")) {
 
			fname = substr($0, index($0, local "."))
 
			sub("\\(.*", "", fname)
 
			sub("\\.", "::", fname)
 
			sub(local, locals[local], fname)
 
			print fname
 
			if (match(locals[local], "List")) {
 
				sub(locals[local], "AIAbstractList", fname)
 
				print fname
 
			}
 
		}
 
	}
 
	# We want to remove everything before the FIRST occurence of AI.
 
	# If we do not remove any other occurences of AI from the string
 
	# we will remove everything before the LAST occurence of AI, so
 
	# do some little magic to make it work the way we want.
 
	sub("AI", "AXXXXY")
 
	gsub("AI", "AXXXXX")
 
	sub(".*AXXXXY", "AI")
 
	if (match($0, "^AI") && match($0, ".")) {
 
		sub("\\(.*", "", $0)
 
		sub("\\.", "::", $0)
 
		print $0
 
	}
 
}
 
' | sed 's/	//g' | sort | uniq > tmp.in_regression
 

	
 
grep 'DefSQ.*Method' ../src/ai/api/*.hpp.sq | grep -v 'AIError::' | grep -v 'AIAbstractList::Valuate' | grep -v '::GetClassName' | sed 's/^[^,]*, &//g;s/,[^,]*//g' | sort > tmp.in_api
 

	
 
diff -u tmp.in_regression tmp.in_api | grep -v '^+++' | grep '^+' | sed 's/^+//'
 

	
 
rm -f tmp.in_regression tmp.in_api
 

	
bin/ai/regression/regression.cfg
Show inline comments
 
new file 100644
 
[misc]
 
display_opt = SHOW_TOWN_NAMES|SHOW_STATION_NAMES|SHOW_SIGNS|WAYPOINTS
 
language = english.lng
 

	
 
[gui]
 
autosave = off
 

	
 
[game_creation]
 
town_name = english
 

	
 
[ai_players]
 
none =
 
regression =
 

	
 
[vehicle]
 
road_side = right
 
plane_speed = 2
bin/ai/regression/regression.nut
Show inline comments
 
new file 100644
 
import("queue.priority_queue", "PQ", 2);
 
import("queue.binary_heap", "BH", 1);
 
import("queue.fibonacci_heap", "FH", 1);
 
import("graph.aystar", "AS", 4);
 
import("pathfinder.road", "RPF", 3);
 

	
 
class Regression extends AIController {
 
	function Start();
 
};
 

	
 

	
 

	
 
function Regression::TestInit()
 
{
 
	print("");
 
	print("--TestInit--");
 
	print(" TickTest: " + this.GetTick());
 
	this.Sleep(1);
 
	print(" TickTest: " + this.GetTick());
 
	print(" SetCommandDelay: " + AIController.SetCommandDelay(1));
 
	print(" IsValid(vehicle.plane_speed): " + AIGameSettings.IsValid("vehicle.plane_speed"));
 
	print(" vehicle.plane_speed: " + AIGameSettings.GetValue("vehicle.plane_speed"));
 
	require("require.nut");
 
	print(" min(6, 3): " + min(6, 3));
 
	print(" min(3, 6): " + min(3, 6));
 
	print(" max(6, 3): " + max(6, 3));
 
	print(" max(3, 6): " + max(3, 6));
 

	
 
	print(" AIList Consistency Tests");
 
	print("");
 
	print(" Value Descending");
 
	local list = AIList();
 
	list.AddItem( 5, 10);
 
	list.AddItem(10, 10);
 
	list.AddItem(15, 20);
 
	list.AddItem(20, 20);
 
	list.AddItem(25, 30);
 
	list.AddItem(30, 30);
 
	list.AddItem(35, 40);
 
	list.AddItem(40, 40);
 

	
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		list.RemoveItem(i - 10);
 
		list.RemoveItem(i - 5);
 
		list.RemoveItem(i);
 
		print("   " + i);
 
	}
 

	
 
	list.AddItem(10, 10);
 
	list.AddItem(20, 20);
 
	list.AddItem(30, 30);
 
	list.AddItem(40, 40);
 

	
 
	print("");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		list.SetValue(i, 2);
 
		print("   " + i);
 
	}
 
	print("");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("   " + i);
 
	}
 

	
 
	list = AIList();
 
	list.Sort(AIAbstractList.SORT_BY_VALUE, true);
 
	print("");
 
	print(" Value Ascending");
 
	list.AddItem( 5, 10);
 
	list.AddItem(10, 10);
 
	list.AddItem(15, 20);
 
	list.AddItem(20, 20);
 
	list.AddItem(25, 30);
 
	list.AddItem(30, 30);
 
	list.AddItem(35, 40);
 
	list.AddItem(40, 40);
 

	
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		list.RemoveItem(i + 10);
 
		list.RemoveItem(i + 5);
 
		list.RemoveItem(i);
 
		print("   " + i);
 
	}
 

	
 
	list.AddItem(10, 10);
 
	list.AddItem(20, 20);
 
	list.AddItem(30, 30);
 
	list.AddItem(40, 40);
 

	
 
	print("");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		list.SetValue(i, 50);
 
		print("   " + i);
 
	}
 
	print("");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("   " + i);
 
	}
 

	
 
	list = AIList();
 
	list.Sort(AIAbstractList.SORT_BY_ITEM, false);
 
	print("");
 
	print(" Item Descending");
 
	list.AddItem( 5, 10);
 
	list.AddItem(10, 10);
 
	list.AddItem(15, 20);
 
	list.AddItem(20, 20);
 
	list.AddItem(25, 30);
 
	list.AddItem(30, 30);
 
	list.AddItem(35, 40);
 
	list.AddItem(40, 40);
 

	
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		list.RemoveItem(i - 10);
 
		list.RemoveItem(i - 5);
 
		list.RemoveItem(i);
 
		print("   " + i);
 
	}
 

	
 
	list.AddItem(10, 10);
 
	list.AddItem(20, 20);
 
	list.AddItem(30, 30);
 
	list.AddItem(40, 40);
 

	
 
	print("");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		list.SetValue(i, 2);
 
		print("   " + i);
 
	}
 
	print("");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("   " + i);
 
	}
 

	
 
	list = AIList();
 
	list.Sort(AIAbstractList.SORT_BY_ITEM, true);
 
	print("");
 
	print(" Item Ascending");
 
	list.AddItem( 5, 10);
 
	list.AddItem(10, 10);
 
	list.AddItem(15, 20);
 
	list.AddItem(20, 20);
 
	list.AddItem(25, 30);
 
	list.AddItem(30, 30);
 
	list.AddItem(35, 40);
 
	list.AddItem(40, 40);
 

	
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		list.RemoveItem(i + 10);
 
		list.RemoveItem(i + 5);
 
		list.RemoveItem(i);
 
		print("   " + i);
 
	}
 

	
 
	list.AddItem(10, 10);
 
	list.AddItem(20, 20);
 
	list.AddItem(30, 30);
 
	list.AddItem(40, 40);
 

	
 
	print("");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		list.SetValue(i, 50);
 
		print("   " + i);
 
	}
 
	print("");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("   " + i);
 
	}
 

	
 
	list.Clear();
 
	foreach (idx, val in list) {
 
		print("   " + idx);
 
	}
 
}
 

	
 
function Regression::Std()
 
{
 
	print("");
 
	print("--Std--");
 
	print(" abs(-21): " + abs(-21));
 
	print(" abs( 21): " + abs(21));
 
}
 

	
 
function Regression::Base()
 
{
 
	print("");
 
	print("--AIBase--");
 
	print("  Rand():       " + AIBase.Rand());
 
	print("  Rand():       " + AIBase.Rand());
 
	print("  Rand():       " + AIBase.Rand());
 
	print("  RandRange(0): " + AIBase.RandRange(0));
 
	print("  RandRange(0): " + AIBase.RandRange(0));
 
	print("  RandRange(0): " + AIBase.RandRange(0));
 
	print("  RandRange(1): " + AIBase.RandRange(1));
 
	print("  RandRange(1): " + AIBase.RandRange(1));
 
	print("  RandRange(1): " + AIBase.RandRange(1));
 
	print("  RandRange(2): " + AIBase.RandRange(2));
 
	print("  RandRange(2): " + AIBase.RandRange(2));
 
	print("  RandRange(2): " + AIBase.RandRange(2));
 
	print("  RandRange(9): " + AIBase.RandRange(9));
 
	print("  RandRange(9): " + AIBase.RandRange(9));
 
	print("  RandRange(9): " + AIBase.RandRange(9));
 
	print("  Chance(1, 2): " + AIBase.Chance(1, 2));
 
	print("  Chance(1, 2): " + AIBase.Chance(1, 2));
 
	print("  Chance(1, 2): " + AIBase.Chance(1, 2));
 

	
 
	AIRoad.SetCurrentRoadType(AIRoad.ROADTYPE_ROAD);
 
}
 

	
 
function Regression::Airport()
 
{
 
	print("");
 
	print("--AIAirport--");
 

	
 
	print("  IsHangarTile():       " + AIAirport.IsHangarTile(32116));
 
	print("  IsAirportTile():      " + AIAirport.IsAirportTile(32116));
 
	print("  GetHangarOfAirport(): " + AIAirport.GetHangarOfAirport(32116));
 
	print("  GetAirportType():     " + AIAirport.GetAirportType(32116));
 

	
 
	for (local i = -1; i < 10; i++) {
 
		print("  IsValidAirportType(" + i + "):       " + AIAirport.IsValidAirportType(i));
 
		print("  AirportAvailable(" + i + "):         " + AIAirport.AirportAvailable(i));
 
		print("  GetAirportWidth(" + i + "):          " + AIAirport.GetAirportWidth(i));
 
		print("  GetAirportHeight(" + i + "):         " + AIAirport.GetAirportHeight(i));
 
		print("  GetAirportCoverageRadius(" + i + "): " + AIAirport.GetAirportCoverageRadius(i));
 
	}
 

	
 
	print("  GetBankBalance():     " + AICompany.GetBankBalance(AICompany.MY_COMPANY));
 
	print("  BuildAirport():       " + AIAirport.BuildAirport(32116, 0, true));
 
	print("  IsHangarTile():       " + AIAirport.IsHangarTile(32116));
 
	print("  IsAirportTile():      " + AIAirport.IsAirportTile(32116));
 
	print("  GetAirportType():     " + AIAirport.GetAirportType(32119));
 
	print("  GetHangarOfAirport(): " + AIAirport.GetHangarOfAirport(32116));
 
	print("  IsHangarTile():       " + AIAirport.IsHangarTile(32119));
 
	print("  IsAirportTile():      " + AIAirport.IsAirportTile(32119));
 
	print("  GetAirportType():     " + AIAirport.GetAirportType(32119));
 
	print("  GetBankBalance():     " + AICompany.GetBankBalance(AICompany.MY_COMPANY));
 

	
 
	print("  RemoveAirport():      " + AIAirport.RemoveAirport(32118));
 
	print("  IsHangarTile():       " + AIAirport.IsHangarTile(32119));
 
	print("  IsAirportTile():      " + AIAirport.IsAirportTile(32119));
 
	print("  GetBankBalance():     " + AICompany.GetBankBalance(AICompany.MY_COMPANY));
 
	print("  BuildAirport():       " + AIAirport.BuildAirport(32116, 0, true));
 
}
 

	
 
function Regression::Bridge()
 
{
 
	local j = 0;
 

	
 
	print("");
 
	print("--Bridge--");
 
	for (local i = -1; i < 14; i++) {
 
		if (AIBridge.IsValidBridge(i)) j++;
 
		print("  Bridge " + i);
 
		print("    IsValidBridge():    " + AIBridge.IsValidBridge(i));
 
		print("    GetName():          " + AIBridge.GetName(i));
 
		print("    GetMaxSpeed():      " + AIBridge.GetMaxSpeed(i));
 
		print("    GetPrice():         " + AIBridge.GetPrice(i, 5));
 
		print("    GetMaxLength():     " + AIBridge.GetMaxLength(i));
 
		print("    GetMinLength():     " + AIBridge.GetMinLength(i));
 
		print("    GetYearAvailable(): " + AIBridge.GetYearAvailable(i));
 
	}
 
	print("  Valid Bridges:        " + j);
 

	
 
	print("  IsBridgeTile():       " + AIBridge.IsBridgeTile(33160));
 
	print("  RemoveBridge():       " + AIBridge.RemoveBridge(33155));
 
	print("  GetLastErrorString(): " + AIError.GetLastErrorString());
 
	print("  GetOtherBridgeEnd():  " + AIBridge.GetOtherBridgeEnd(33160));
 
	print("  BuildBridge():        " + AIBridge.BuildBridge(AIVehicle.VEHICLE_ROAD, 5, 33160, 33155));
 
	print("  IsBridgeTile():       " + AIBridge.IsBridgeTile(33160));
 
	print("  IsBridgeTile():       " + AIBridge.IsBridgeTile(33155));
 
	print("  GetOtherBridgeEnd():  " + AIBridge.GetOtherBridgeEnd(33160));
 
	print("  BuildBridge():        " + AIBridge.BuildBridge(AIVehicle.VEHICLE_ROAD, 5, 33160, 33155));
 
	print("  GetLastErrorString(): " + AIError.GetLastErrorString());
 
	print("  RemoveBridge():       " + AIBridge.RemoveBridge(33155));
 
	print("  IsBridgeTile():       " + AIBridge.IsBridgeTile(33160));
 
}
 

	
 
function Regression::BridgeList()
 
{
 
	local list = AIBridgeList();
 

	
 
	print("");
 
	print("--BridgeList--");
 
	print("  Count():             " + list.Count());
 
	list.Valuate(AIBridge.GetMaxSpeed);
 
	print("  MaxSpeed ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIBridge.GetPrice, 5);
 
	print("  Price ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIBridge.GetMaxLength);
 
	print("  MaxLength ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIBridge.GetMinLength);
 
	print("  MinLength ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIBridge.GetYearAvailable);
 
	print("  YearAvailable ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list = AIBridgeList_Length(14);
 

	
 
	print("");
 
	print("--BridgeList_Length--");
 
	print("  Count():             " + list.Count());
 
	list.Valuate(AIBridge.GetMaxSpeed);
 
	print("  MaxSpeed ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIBridge.GetPrice, 14);
 
	print("  Price ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
}
 

	
 
function Regression::Cargo()
 
{
 
	print("");
 
	print("--AICargo--");
 
	for (local i = -1; i < 15; i++) {
 
		print("  Cargo " + i);
 
		print("    IsValidCargo():          " + AICargo.IsValidCargo(i));
 
		print("    GetCargoLabel():         '" + AICargo.GetCargoLabel(i)+ "'");
 
		print("    IsFreight():             " + AICargo.IsFreight(i));
 
		print("    HasCargoClass():         " + AICargo.HasCargoClass(i, AICargo.CC_PASSENGERS));
 
		print("    GetTownEffect():         " + AICargo.GetTownEffect(i));
 
		print("    GetCargoIncome(0, 0):    " + AICargo.GetCargoIncome(i, 0, 0));
 
		print("    GetCargoIncome(10, 10):  " + AICargo.GetCargoIncome(i, 10, 10));
 
		print("    GetCargoIncome(100, 10): " + AICargo.GetCargoIncome(i, 100, 10));
 
		print("    GetCargoIncome(10, 100): " + AICargo.GetCargoIncome(i, 10, 100));
 
	}
 
}
 

	
 
function Regression::CargoList()
 
{
 
	local list = AICargoList();
 

	
 
	print("");
 
	print("--CargoList--");
 
	print("  Count():            " + list.Count());
 
	list.Valuate(AICargo.IsFreight);
 
	print("  IsFreight ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list.Valuate(AICargo.GetCargoIncome, 100, 100);
 
	print("  CargoIncomes(100, 100) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list = AICargoList_IndustryAccepting(8);
 
	print("");
 
	print("--CargoList_IndustryAccepting--");
 
	print("  Count():            " + list.Count());
 
	print("  ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i);
 
	}
 

	
 
	list = AICargoList_IndustryProducing(4);
 
	print("");
 
	print("--CargoList_IndustryProducing--");
 
	print("  Count():            " + list.Count());
 
	print("  ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i);
 
	}
 
}
 

	
 
function Regression::Company()
 
{
 
	print("");
 
	print("--Company--");
 

	
 
	/* Test AIXXXMode() in scopes */
 
	{
 
		local test = AITestMode();
 
		print("  SetName():            " + AICompany.SetName("Regression"));
 
		print("  SetName():            " + AICompany.SetName("Regression"));
 
		{
 
			local exec = AIExecMode();
 
			print("  SetName():            " + AICompany.SetName("Regression"));
 
			print("  SetName():            " + AICompany.SetName("Regression"));
 
			print("  GetLastErrorString(): " + AIError.GetLastErrorString());
 
		}
 
	}
 

	
 
	print("  GetName():                   " + AICompany.GetName(AICompany.MY_COMPANY));
 
	print("  GetPresidentName():          " + AICompany.GetPresidentName(AICompany.MY_COMPANY));
 
	print("  SetPresidentName():          " + AICompany.SetPresidentName("Regression AI"));
 
	print("  GetPresidentName():          " + AICompany.GetPresidentName(AICompany.MY_COMPANY));
 
	print("  GetCompanyValue():           " + AICompany.GetCompanyValue(AICompany.MY_COMPANY));
 
	print("  GetBankBalance():            " + AICompany.GetBankBalance(AICompany.MY_COMPANY));
 
	print("  GetName():                   " + AICompany.GetName(240));
 
	print("  GetLoanAmount():             " + AICompany.GetLoanAmount());
 
	print("  GetMaxLoanAmount():          " + AICompany.GetMaxLoanAmount());
 
	print("  GetLoanInterval():           " + AICompany.GetLoanInterval());
 
	print("  SetLoanAmount(1):            " + AICompany.SetLoanAmount(1));
 
	print("  SetLoanAmount(100):          " + AICompany.SetLoanAmount(100));
 
	print("  SetLoanAmount(10000):        " + AICompany.SetLoanAmount(10000));
 
	print("  GetLastErrorString():        " + AIError.GetLastErrorString());
 
	print("  GetBankBalance():            " + AICompany.GetBankBalance(AICompany.MY_COMPANY));
 
	print("  GetLoanAmount():             " + AICompany.GetLoanAmount());
 
	print("  SetMinimumLoanAmount(31337): " + AICompany.SetMinimumLoanAmount(31337));
 
	print("  GetBankBalance():            " + AICompany.GetBankBalance(AICompany.MY_COMPANY));
 
	print("  GetLoanAmount():             " + AICompany.GetLoanAmount());
 
	print("  SetLoanAmount(10000):        " + AICompany.SetLoanAmount(AICompany.GetMaxLoanAmount()));
 
	print("  GetBankBalance():            " + AICompany.GetBankBalance(AICompany.MY_COMPANY));
 
	print("  GetLoanAmount():             " + AICompany.GetLoanAmount());
 
	print("  GetCompanyHQ():              " + AICompany.GetCompanyHQ(AICompany.MY_COMPANY));
 
	print("  BuildCompanyHQ():            " + AICompany.BuildCompanyHQ(AIMap.GetTileIndex(127, 129)));
 
	print("  GetCompanyHQ():              " + AICompany.GetCompanyHQ(AICompany.MY_COMPANY));
 
	print("  BuildCompanyHQ():            " + AICompany.BuildCompanyHQ(AIMap.GetTileIndex(129, 129)));
 
	print("  GetCompanyHQ():              " + AICompany.GetCompanyHQ(AICompany.MY_COMPANY));
 
	print("  BuildCompanyHQ():            " + AICompany.BuildCompanyHQ(AIMap.GetTileIndex(129, 128)));
 
	print("  GetLastErrorString():        " + AIError.GetLastErrorString());
 
	print("  GetAutoRenewStatus();        " + AICompany.GetAutoRenewStatus(AICompany.MY_COMPANY));
 
	print("  SetAutoRenewStatus(true);    " + AICompany.SetAutoRenewStatus(true));
 
	print("  GetAutoRenewStatus();        " + AICompany.GetAutoRenewStatus(AICompany.MY_COMPANY));
 
	print("  SetAutoRenewStatus(true);    " + AICompany.SetAutoRenewStatus(true));
 
	print("  SetAutoRenewStatus(false);   " + AICompany.SetAutoRenewStatus(false));
 
	print("  GetAutoRenewMonths();        " + AICompany.GetAutoRenewMonths(AICompany.MY_COMPANY));
 
	print("  SetAutoRenewMonths(-12);     " + AICompany.SetAutoRenewMonths(-12));
 
	print("  GetAutoRenewMonths();        " + AICompany.GetAutoRenewMonths(AICompany.MY_COMPANY));
 
	print("  SetAutoRenewMonths(-12);     " + AICompany.SetAutoRenewMonths(-12));
 
	print("  SetAutoRenewMonths(6);       " + AICompany.SetAutoRenewMonths(6));
 
	print("  GetAutoRenewMoney();         " + AICompany.GetAutoRenewMoney(AICompany.MY_COMPANY));
 
	print("  SetAutoRenewMoney(200000);   " + AICompany.SetAutoRenewMoney(200000));
 
	print("  GetAutoRenewMoney();         " + AICompany.GetAutoRenewMoney(AICompany.MY_COMPANY));
 
	print("  SetAutoRenewMoney(200000);   " + AICompany.SetAutoRenewMoney(200000));
 
	print("  SetAutoRenewMoney(100000);   " + AICompany.SetAutoRenewMoney(100000));
 
}
 

	
 
function Regression::Engine()
 
{
 
	local j = 0;
 

	
 
	print("");
 
	print("--Engine--");
 
	for (local i = -1; i < 257; i++) {
 
		if (AIEngine.IsValidEngine(i)) j++;
 
		print("  Engine " + i);
 
		print("    IsValidEngine():    " + AIEngine.IsValidEngine(i));
 
		print("    GetName():          " + AIEngine.GetName(i));
 
		print("    GetCargoType():     " + AIEngine.GetCargoType(i));
 
		print("    CanRefitCargo():    " + AIEngine.CanRefitCargo(i, 1));
 
		print("    GetCapacity():      " + AIEngine.GetCapacity(i));
 
		print("    GetReliability():   " + AIEngine.GetReliability(i));
 
		print("    GetMaxSpeed():      " + AIEngine.GetMaxSpeed(i));
 
		print("    GetPrice():         " + AIEngine.GetPrice(i));
 
		print("    GetMaxAge():        " + AIEngine.GetMaxAge(i));
 
		print("    GetRunningCost():   " + AIEngine.GetRunningCost(i));
 
		print("    GetVehicleType():   " + AIEngine.GetVehicleType(i));
 
		print("    GetRailType():      " + AIEngine.GetRailType(i));
 
		print("    GetRoadType():      " + AIEngine.GetRoadType(i));
 
		print("    GetPlaneType():     " + AIEngine.GetPlaneType(i));
 
	}
 
	print("  Valid Engines:        " + j);
 
}
 

	
 
function Regression::EngineList()
 
{
 
	local list = AIEngineList(AIVehicle.VEHICLE_ROAD);
 

	
 
	print("");
 
	print("--EngineList--");
 
	print("  Count():             " + list.Count());
 
	list.Valuate(AIEngine.GetCargoType);
 
	print("  CargoType ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIEngine.GetCapacity);
 
	print("  Capacity ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIEngine.GetReliability);
 
	print("  Reliability ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIEngine.GetMaxSpeed);
 
	print("  MaxSpeed ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIEngine.GetPrice);
 
	print("  Price ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
}
 

	
 
function cost_callback(old_path, new_tile, new_direction, self) { if (old_path == null) return 0; return old_path.GetCost() + 1; }
 
function estimate_callback(tile, direction, goals, self) { return goals[0] - tile; }
 
function neighbours_callback(path, cur_tile, self) { return [[cur_tile + 1, 1]]; }
 
function check_direction_callback(tile, existing_direction, new_direction, self) { return false; }
 

	
 
function Regression::Graph()
 
{
 
	print("--AyStar--");
 
	print("  Fastest path:");
 
	local as = AS(cost_callback, estimate_callback, neighbours_callback, check_direction_callback);
 

	
 
	local path = false;
 
	as.InitializePath([[1, 1]], [10]);
 
	while (path == false) path = as.FindPath(5);
 

	
 
	while (path != null) {
 
		print("    Tile " + path.GetTile());
 
		path = path.GetParent();
 
	}
 
}
 

	
 
function Regression::Group()
 
{
 
	print ("");
 
	print("--Group--");
 
	print("  SetAutoReplace():         " + AIGroup.SetAutoReplace(AIGroup.ALL_GROUP, 116, 117));
 
	print("  GetEngineReplacement():   " + AIGroup.GetEngineReplacement(AIGroup.ALL_GROUP, 116));
 
	print("  GetNumEngines():          " + AIGroup.GetNumEngines(AIGroup.ALL_GROUP, 116));
 
	print("  AIRoad.BuildRoadDepot():  " + AIRoad.BuildRoadDepot(10000, 10001));
 
	local vehicle = AIVehicle.BuildVehicle(10000, 116);
 
	print("  AIVehicle.BuildVehicle(): " + vehicle);
 
	print("  GetNumEngines():          " + AIGroup.GetNumEngines(AIGroup.ALL_GROUP, 116));
 
	local group = AIGroup.CreateGroup(AIVehicle.VEHICLE_ROAD);
 
	print("  CreateGroup():            " + group);
 
	print("  MoveVehicle():            " + AIGroup.MoveVehicle(group, vehicle));
 
	print("  GetNumEngines():          " + AIGroup.GetNumEngines(group, 116));
 
	print("  GetNumEngines():          " + AIGroup.GetNumEngines(AIGroup.ALL_GROUP, 116));
 
	print("  GetNumEngines():          " + AIGroup.GetNumEngines(AIGroup.DEFAULT_GROUP, 116));
 
	print("  GetName():                " + AIGroup.GetName(0));
 
	print("  GetName():                " + AIGroup.GetName(1));
 
	print("  AIVehicle.SellVehicle():  " + AIVehicle.SellVehicle(vehicle));
 
	print("  AITile.DemolishTile():    " + AITile.DemolishTile(10000));
 
	print("  HasWagonRemoval():        " + AIGroup.HasWagonRemoval());
 
	print("  EnableWagonRemoval():     " + AIGroup.EnableWagonRemoval(true));
 
	print("  HasWagonRemoval():        " + AIGroup.HasWagonRemoval());
 
	print("  EnableWagonRemoval():     " + AIGroup.EnableWagonRemoval(false));
 
	print("  EnableWagonRemoval():     " + AIGroup.EnableWagonRemoval(false));
 
	print("  HasWagonRemoval():        " + AIGroup.HasWagonRemoval());
 
}
 

	
 
function Regression::Industry()
 
{
 
	local j = 0;
 

	
 
	print("");
 
	print("--Industry--");
 
	print("  GetMaxIndustryID():  " + AIIndustry.GetMaxIndustryID());
 
	print("  GetIndustryCount():  " + AIIndustry.GetIndustryCount());
 
	for (local i = -1; i < AIIndustry.GetMaxIndustryID() + 1; i++) {
 
		if (AIIndustry.IsValidIndustry(i)) j++;
 
		print("  Industry " + i);
 
		print("    IsValidIndustry(): " + AIIndustry.IsValidIndustry(i));
 
		print("    GetName():         " + AIIndustry.GetName(i));
 
		print("    GetLocation():     " + AIIndustry.GetLocation(i));
 
		print("    GetProduction():   " + AIIndustry.GetProduction(i, 1));
 
		print("    IsCargoAccepted(): " + AIIndustry.IsCargoAccepted(i, 1));
 

	
 
		local cargo_list = AICargoList();
 
		for (local j = cargo_list.Begin(); cargo_list.HasNext(); j = cargo_list.Next()) {
 
			if (AIIndustry.GetProduction(i, j) > 0) {
 
				print("	   GetLastMonthProduction():  " + AIIndustry.GetLastMonthProduction(i, j));
 
				print("	   GetLastMonthTransported(): " + AIIndustry.GetLastMonthTransported(i, j));
 
				print("	   GetStockpiledCargo():      " + AIIndustry.GetStockpiledCargo(i, j));
 
			}
 
		}
 
	}
 
	print("  Valid Industries:    " + j);
 
	print("  GetIndustryCount():  " + AIIndustry.GetIndustryCount());
 
}
 

	
 
function Regression::IndustryList()
 
{
 
	local list = AIIndustryList();
 

	
 
	print("");
 
	print("--IndustryList--");
 
	print("  Count():             " + list.Count());
 
	list.Valuate(AIIndustry.GetLocation);
 
	print("  Location ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIIndustry.GetDistanceManhattanToTile, 30000);
 
	print("  DistanceManhattanToTile(30000) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIIndustry.GetDistanceSquareToTile, 30000);
 
	print("  DistanceSquareToTile(30000) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIIndustry.GetAmountOfStationsAround);
 
	print("  GetAmountOfStationsAround(30000) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIIndustry.IsCargoAccepted, 1);
 
	print("  CargoAccepted(1) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIIndustry.GetProduction, 1);
 
	list.KeepAboveValue(50);
 
	print("  KeepAboveValue(50): done");
 
	print("  Count():             " + list.Count());
 
	print("  Production ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list = AIIndustryList_CargoAccepting(1);
 
	print("--IndustryList_CargoAccepting--");
 
	print("  Count():             " + list.Count());
 
	list.Valuate(AIIndustry.GetLocation);
 
	print("  Location ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list = AIIndustryList_CargoProducing(1);
 
	print("--IndustryList_CargoProducing--");
 
	print("  Count():             " + list.Count());
 
	list.Valuate(AIIndustry.GetLocation);
 
	print("  Location ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
}
 

	
 
function Regression::IndustryTypeList()
 
{
 
	local list = AIIndustryTypeList();
 

	
 
	print("");
 
	print("--IndustryTypeList--");
 
	print("  Count():             " + list.Count());
 
	list.Valuate(AIIndustry.GetLocation);
 
	print("  Location ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    Id:                      " + i);
 
		print("    IsRawIndustry():         " + AIIndustryType.IsRawIndustry(i));
 
		print("    ProductionCanIncrease(): " + AIIndustryType.ProductionCanIncrease(i));
 
		print("    GetConstructionCost():   " + AIIndustryType.GetConstructionCost(i));
 
		print("    GetName():               " + AIIndustryType.GetName(i));
 
		print("    CanBuildIndustry():      " + AIIndustryType.CanBuildIndustry(i));
 
		print("    CanProspectIndustry():   " + AIIndustryType.CanProspectIndustry(i));
 
	}
 
}
 

	
 
function CustomValuator(list_id)
 
{
 
	return list_id * 4343;
 
}
 

	
 
function Regression::List()
 
{
 
	local list = AIList();
 

	
 
	print("");
 
	print("--List--");
 

	
 
	print("  IsEmpty():     " + list.IsEmpty());
 
	list.AddItem(1, 1);
 
	list.AddItem(2, 2);
 
	for (local i = 1000; i < 1100; i++) {
 
		list.AddItem(i, i);
 
	}
 
	list.RemoveItem(1050);
 
	list.RemoveItem(1150);
 
	list.ChangeItem(1051, 12);
 
	print("  Count():       " + list.Count());
 
	print("  HasItem(1050): " + list.HasItem(1050));
 
	print("  HasItem(1051): " + list.HasItem(1051));
 
	print("  IsEmpty():     " + list.IsEmpty());
 
	list.Sort(AIAbstractList.SORT_BY_ITEM, true);
 
	print("  List Dump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(CustomValuator);
 
	print("  Custom ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(function (a) { return a * 42; });
 
	print("  Custom ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIBase.RandItem);
 
	print("  Randomize ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list.KeepTop(10);
 
	print("  KeepTop(10):");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.KeepBottom(8);
 
	print("  KeepBottom(8):");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.RemoveBottom(2);
 
	print("  RemoveBottom(2):");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.RemoveTop(2);
 
	print("  RemoveTop(2):");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	local list2 = AIList();
 
	list2.AddItem(1003, 0);
 
	list2.AddItem(1004, 0);
 
	list.RemoveList(list2);
 
	print("  RemoveList({1003, 1004}):");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list2.AddItem(1005, 0);
 
	list.KeepList(list2);
 
	print("  KeepList({1003, 1004, 1005}):");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list2.Clear();
 
	for (local i = 4000; i < 4003; i++) {
 
		list2.AddItem(i, i * 2);
 
	}
 
	list2.AddItem(1005, 1005);
 
	list.AddList(list2);
 
	print("  AddList({1005, 4000, 4001, 4002}):");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list[4000] = 50;
 
	list[4006] = 12;
 

	
 
	print("  foreach():");
 
	foreach (idx, val in list) {
 
		print("    " + idx + " => " + val);
 
	}
 
	print("  []:");
 
	print("    4000 => " + list[4000]);
 

	
 
	list.Clear();
 
	print("  IsEmpty():     " + list.IsEmpty());
 
}
 

	
 
function Regression::Map()
 
{
 
	print("");
 
	print("--Map--");
 
	print("  GetMapSize():     " + AIMap.GetMapSize());
 
	print("  GetMapSizeX():    " + AIMap.GetMapSizeX());
 
	print("  GetMapSizeY():    " + AIMap.GetMapSizeY());
 
	print("  GetTileX(123):    " + AIMap.GetTileX(123));
 
	print("  GetTileY(123):    " + AIMap.GetTileY(123));
 
	print("  GetTileIndex():   " + AIMap.GetTileIndex(123, 0));
 
	print("  GetTileIndex():   " + AIMap.GetTileIndex(0, 123));
 
	print("  GetTileIndex():   " + AIMap.GetTileIndex(0, 0));
 
	print("  GetTileIndex():   " + AIMap.GetTileIndex(-1, -1));
 
	print("  GetTileIndex():   " + AIMap.GetTileIndex(10000, 10000));
 
	print("  IsValidTile(123): " + AIMap.IsValidTile(123));
 
	print("  GetTileX(124):    " + AIMap.GetTileX(124));
 
	print("  GetTileY(124):    " + AIMap.GetTileY(124));
 
	print("  IsValidTile(124): " + AIMap.IsValidTile(124));
 
	print("  IsValidTile(0):   " + AIMap.IsValidTile(0));
 
	print("  IsValidTile(-1):  " + AIMap.IsValidTile(-1));
 
	print("  IsValidTile():    " + AIMap.IsValidTile(AIMap.GetMapSize()));
 
	print("  IsValidTile():    " + AIMap.IsValidTile(AIMap.GetMapSize() - AIMap.GetMapSizeX() - 2));
 
	print("  DemolishTile():   " + AITile.DemolishTile(19592));
 
	print("  DemolishTile():   " + AITile.DemolishTile(19335));
 
	print("  Distance");
 
	print("    DistanceManhattan(): " + AIMap.DistanceManhattan(1, 10000));
 
	print("    DistanceMax():       " + AIMap.DistanceMax(1, 10000));
 
	print("    DistanceSquare():    " + AIMap.DistanceSquare(1, 10000));
 
	print("    DistanceFromEdge():  " + AIMap.DistanceFromEdge(10000));
 
}
 

	
 
function Regression::Marine()
 
{
 
	print("");
 
	print("--AIMarine--");
 

	
 
	print("  IsWaterDepotTile():   " + AIMarine.IsWaterDepotTile(32116));
 
	print("  IsDockTile():         " + AIMarine.IsDockTile(32116));
 
	print("  IsBuoyTile():         " + AIMarine.IsBuoyTile(32116));
 
	print("  IsLockTile():         " + AIMarine.IsLockTile(32116));
 
	print("  IsCanalTile():        " + AIMarine.IsCanalTile(32116));
 

	
 
	print("  GetBankBalance():     " + AICompany.GetBankBalance(AICompany.MY_COMPANY));
 
	print("  BuildWaterDepot():    " + AIMarine.BuildWaterDepot(28479, false));
 
	print("  BuildDock():          " + AIMarine.BuildDock(29253, true));
 
	print("  BuildBuoy():          " + AIMarine.BuildBuoy(28481));
 
	print("  BuildLock():          " + AIMarine.BuildLock(28487));
 
	print("  HasTransportType():   " + AITile.HasTransportType(32127, AITile.TRANSPORT_WATER));
 
	print("  BuildCanal():         " + AIMarine.BuildCanal(32127));
 
	print("  HasTransportType():   " + AITile.HasTransportType(32127, AITile.TRANSPORT_WATER));
 
	print("  IsWaterDepotTile():   " + AIMarine.IsWaterDepotTile(28479));
 
	print("  IsDockTile():         " + AIMarine.IsDockTile(29253));
 
	print("  IsBuoyTile():         " + AIMarine.IsBuoyTile(28481));
 
	print("  IsLockTile():         " + AIMarine.IsLockTile(28487));
 
	print("  IsCanalTile():        " + AIMarine.IsCanalTile(32127));
 
	print("  GetBankBalance():     " + AICompany.GetBankBalance(AICompany.MY_COMPANY));
 

	
 
	print("  RemoveWaterDepot():   " + AIMarine.RemoveWaterDepot(28479));
 
	print("  RemoveDock():         " + AIMarine.RemoveDock(29253));
 
	print("  RemoveBuoy():         " + AIMarine.RemoveBuoy(28481));
 
	print("  RemoveLock():         " + AIMarine.RemoveLock(28487));
 
	print("  RemoveCanal():        " + AIMarine.RemoveCanal(32127));
 
	print("  IsWaterDepotTile():   " + AIMarine.IsWaterDepotTile(28479));
 
	print("  IsDockTile():         " + AIMarine.IsDockTile(29253));
 
	print("  IsBuoyTile():         " + AIMarine.IsBuoyTile(28481));
 
	print("  IsLockTile():         " + AIMarine.IsLockTile(28487));
 
	print("  IsCanalTile():        " + AIMarine.IsCanalTile(32127));
 
	print("  GetBankBalance():     " + AICompany.GetBankBalance(AICompany.MY_COMPANY));
 

	
 
	print("  BuildWaterDepot():    " + AIMarine.BuildWaterDepot(28479, false));
 
	print("  BuildDock():          " + AIMarine.BuildDock(29253, true));
 
}
 

	
 
function Regression::Order()
 
{
 
	print("");
 
	print("--Order--");
 
	print("  GetOrderCount():       " + AIOrder.GetOrderCount(12));
 
	print("  GetOrderDestination(): " + AIOrder.GetOrderDestination(12, 1));
 
	print("  AreOrderFlagsValid():  " + AIOrder.AreOrderFlagsValid(33416, AIOrder.AIOF_TRANSFER));
 
	print("  IsValidVehicleOrder(): " + AIOrder.IsValidVehicleOrder(12, 1));
 
	print("  GetOrderFlags():       " + AIOrder.GetOrderFlags(12, 1));
 
	print("  AppendOrder():         " + AIOrder.AppendOrder(12, 33416, AIOrder.AIOF_TRANSFER));
 
	print("  InsertOrder():         " + AIOrder.InsertOrder(12, 0, 33416, AIOrder.AIOF_TRANSFER));
 
	print("  GetOrderCount():       " + AIOrder.GetOrderCount(12));
 
	print("  IsValidVehicleOrder(): " + AIOrder.IsValidVehicleOrder(12, 1));
 
	print("  RemoveOrder():         " + AIOrder.RemoveOrder(12, 0));
 
	print("  ChangeOrder():         " + AIOrder.ChangeOrder(12, 0, AIOrder.AIOF_FULL_LOAD));
 
	print("  GetOrderDestination(): " + AIOrder.GetOrderDestination(12, 0));
 
	print("  CopyOrders():          " + AIOrder.CopyOrders(12, 1));
 
	print("  CopyOrders():          " + AIOrder.CopyOrders(13, 12));
 
	print("  ShareOrders():         " + AIOrder.ShareOrders(13, 1));
 
	print("  ShareOrders():         " + AIOrder.ShareOrders(13, 12));
 
	print("  UnshareOrders():       " + AIOrder.UnshareOrders(13));
 
	print("  AppendOrder():         " + AIOrder.AppendOrder(12, 33421, AIOrder.AIOF_NONE));
 

	
 
	local list = AIStationList_Vehicle(12);
 

	
 
	print("");
 
	print("--StationList_Vehicle--");
 
	print("  Count():             " + list.Count());
 
	list.Valuate(AIStation.GetLocation);
 
	print("  Location ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIStation.GetCargoWaiting, 0);
 
	print("  CargoWaiting(0) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIStation.GetCargoWaiting, 1);
 
	print("  CargoWaiting(1) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIStation.GetCargoRating, 1);
 
	print("  CargoRating(1) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIStation.GetDistanceManhattanToTile, 30000);
 
	print("  DistanceManhattanToTile(30000) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIStation.GetDistanceSquareToTile, 30000);
 
	print("  DistanceSquareToTile(30000) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIStation.IsWithinTownInfluence, 0);
 
	print("  IsWithinTownInfluence(0) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list = AIVehicleList_Station(3);
 

	
 
	print("");
 
	print("--VehicleList_Station--");
 
	print("  Count():             " + list.Count());
 
	list.Valuate(AIVehicle.GetLocation);
 
	print("  Location ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	print("  foreach():");
 
	foreach (idx, val in list) {
 
		print("    " + idx + " => " + val);
 
	}
 
}
 

	
 
function Regression::Pathfinder()
 
{
 
	print("");
 
	print("--PathFinder--");
 
	print("  Road Between Towns:");
 

	
 
	local pathfinder = RPF();
 

	
 
	local path = false;
 
	pathfinder.InitializePath([AITown.GetLocation(0)], [AITown.GetLocation(1)]);
 
	while (path == false) path = pathfinder.FindPath(1000);
 

	
 
	while (path != null) {
 
		print("    Tile " + path.GetTile());
 
		path = path.GetParent();
 
	}
 
}
 

	
 
function Regression::QueueTest(queue)
 
{
 
	print("  Count(): " + queue.Count());
 
	print("  Peek():  " + queue.Peek());
 
	print("  Pop():   " + queue.Pop());
 
	queue.Insert(6, 20);
 
	queue.Insert(7, 40);
 
	queue.Insert(2, 10);
 
	queue.Insert(5, 15);
 
	queue.Insert(8, 60);
 
	queue.Insert(1,  5);
 
	queue.Insert(3, 10);
 
	queue.Insert(9, 90);
 
	queue.Insert(4, 10);
 
	print("  Count(): " + queue.Count());
 
	print("  Peek():  " + queue.Peek());
 
	for (local i = 4; i > 0; i--) {
 
		print("  Pop():   " + queue.Pop());
 
	}
 
	queue.Insert(1, 5);
 
	queue.Insert(10, 100);
 
	for (local i = queue.Count(); i > 0; i--) {
 
		print("  Pop():   " + queue.Pop());
 
	}
 
	print("  Peek():  " + queue.Peek());
 
	print("  Pop():   " + queue.Pop());
 
	print("  Count(): " + queue.Count());
 
}
 

	
 
function Regression::Queues()
 
{
 
	print("");
 
	print("--PriorityQueue--");
 
	QueueTest(PQ());
 
	print("");
 
	print("--BinaryHeap--");
 
	QueueTest(BH());
 
	print("");
 
	print("--FibonacciHeap--");
 
	QueueTest(FH());
 
}
 

	
 
function Regression::RailTypeList()
 
{
 
	local list = AIRailTypeList();
 

	
 
	print("");
 
	print("--RailTypeList--");
 
	print("  Count():             " + list.Count());
 
	print("  ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    RailType:                " + i);
 
		print("    IsRailTypeAvailable():   " + AIRail.IsRailTypeAvailable(i));
 
	}
 
}
 

	
 
function Regression::Rail()
 
{
 
	AIRail.SetCurrentRailType(0);
 

	
 
	print("");
 
	print("--Rail--");
 
	print("    IsRailTile():                  " + AIRail.IsRailTile(10002));
 
	print("    BuildRailTrack():              " + AIRail.BuildRailTrack(10002, AIRail.RAILTRACK_NW_SE));
 
	print("    BuildSignal():                 " + AIRail.BuildSignal(10002, 10258, AIRail.SIGNALTYPE_PBS));
 
	print("    RemoveRailTrack():             " + AIRail.RemoveRailTrack(10002, AIRail.RAILTRACK_NW_NE));
 
	print("    RemoveRailTrack():             " + AIRail.RemoveRailTrack(10002, AIRail.RAILTRACK_NW_SE));
 
	print("    BuildRail():                   " + AIRail.BuildRail(10002, 10003, 10006));
 
	print("    HasTransportType():            " + AITile.HasTransportType(10005, AITile.TRANSPORT_RAIL));
 
	print("    HasTransportType():            " + AITile.HasTransportType(10006, AITile.TRANSPORT_RAIL));
 
	print("    RemoveRail():                  " + AIRail.RemoveRail(10005, 10004, 10001));
 

	
 
	print("  Depot");
 
	print("    IsRailTile():                  " + AIRail.IsRailTile(33411));
 
	print("    BuildRailDepot():              " + AIRail.BuildRailDepot(0, 1));
 
	print("    BuildRailDepot():              " + AIRail.BuildRailDepot(33411, 33411));
 
	print("    BuildRailDepot():              " + AIRail.BuildRailDepot(33411, 33414));
 
	print("    BuildRailDepot():              " + AIRail.BuildRailDepot(33411, 33412));
 
	print("    GetRailDepotFrontTile():       " + AIRail.GetRailDepotFrontTile(33411));
 
	print("    IsBuildable():                 " + AITile.IsBuildable(33411));
 
	local list = AIDepotList(AITile.TRANSPORT_RAIL);
 
	print("    DepotList");
 
	print("      Count():                     " + list.Count());
 
	list.Valuate(AITile.GetDistanceManhattanToTile, 0);
 
	print("      Depot distance from (0,0) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("        " + i + " => " + list.GetValue(i));
 
	}
 
	print("    RemoveDepot():                 " + AITile.DemolishTile(33411));
 

	
 
	print("  Station");
 
	print("    BuildRailStation():            " + AIRail.BuildRailStation(0, AIRail.RAILTRACK_NE_SW, 1, 1, false));
 
	print("    BuildRailStation():            " + AIRail.BuildRailStation(7958, AIRail.RAILTRACK_NE_SW, 4, 5, false));
 
	print("    IsRailStationTile():           " + AIRail.IsRailStationTile(7957));
 
	print("    IsRailStationTile():           " + AIRail.IsRailStationTile(7958));
 
	print("    IsRailStationTile():           " + AIRail.IsRailStationTile(7959));
 
	print("    RemoveRailStationTileRect():   " + AIRail.RemoveRailStationTileRect(7959, 7959));
 
	print("    IsRailStationTile():           " + AIRail.IsRailStationTile(7957));
 
	print("    IsRailStationTile():           " + AIRail.IsRailStationTile(7958));
 
	print("    IsRailStationTile():           " + AIRail.IsRailStationTile(7959));
 
	print("    DemolishTile():                " + AITile.DemolishTile(7960));
 
	print("    IsRailStationTile():           " + AIRail.IsRailStationTile(7957));
 
	print("    IsRailStationTile():           " + AIRail.IsRailStationTile(7958));
 
	print("    IsRailStationTile():           " + AIRail.IsRailStationTile(7959));
 
}
 

	
 
function Regression::Road()
 
{
 
	print("");
 
	print("--Road--");
 
	print("  Road");
 
	print("    IsRoadTile():                  " + AIRoad.IsRoadTile(33411));
 
	print("    BuildRoad():                   " + AIRoad.BuildRoad(0, 1));
 
	print("    BuildRoad():                   " + AIRoad.BuildRoad(33411, 33411));
 
	print("    HasTransportType():            " + AITile.HasTransportType(33413, AITile.TRANSPORT_ROAD));
 
	print("    BuildRoad():                   " + AIRoad.BuildRoad(33411, 33414));
 
	print("    HasTransportType():            " + AITile.HasTransportType(33413, AITile.TRANSPORT_ROAD));
 
	print("    AreRoadTilesConnected():       " + AIRoad.AreRoadTilesConnected(33412, 33413));
 
	print("    IsRoadTile():                  " + AIRoad.IsRoadTile(33411));
 
	print("    HasRoadType(Road):             " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_ROAD));
 
	print("    HasRoadType(Tram):             " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_TRAM));
 
	print("    GetNeighbourRoadCount():       " + AIRoad.GetNeighbourRoadCount(33412));
 
	print("    RemoveRoad():                  " + AIRoad.RemoveRoad(33411, 33411));
 
	print("    RemoveRoad():                  " + AIRoad.RemoveRoad(33411, 33412));
 
	print("    RemoveRoad():                  " + AIRoad.RemoveRoad(19590, 19590));
 
	print("    RemoveRoad():                  " + AIRoad.RemoveRoad(33411, 33414));
 
	print("    BuildOneWayRoad():             " + AIRoad.BuildOneWayRoad(33411, 33414));
 
	print("    AreRoadTilesConnected():       " + AIRoad.AreRoadTilesConnected(33412, 33413));
 
	print("    AreRoadTilesConnected():       " + AIRoad.AreRoadTilesConnected(33413, 33412));
 
	print("    BuildOneWayRoad():             " + AIRoad.BuildOneWayRoad(33413, 33412));
 
	print("    AreRoadTilesConnected():       " + AIRoad.AreRoadTilesConnected(33412, 33413));
 
	print("    AreRoadTilesConnected():       " + AIRoad.AreRoadTilesConnected(33413, 33412));
 
	print("    BuildOneWayRoad():             " + AIRoad.BuildOneWayRoad(33412, 33413));
 
	print("    BuildOneWayRoad():             " + AIRoad.BuildOneWayRoad(33413, 33412));
 
	print("    AreRoadTilesConnected():       " + AIRoad.AreRoadTilesConnected(33412, 33413));
 
	print("    AreRoadTilesConnected():       " + AIRoad.AreRoadTilesConnected(33413, 33412));
 
	print("    RemoveRoad():                  " + AIRoad.RemoveRoad(33411, 33412));
 
	print("    IsRoadTypeAvailable(Road):     " + AIRoad.IsRoadTypeAvailable(AIRoad.ROADTYPE_ROAD));
 
	print("    IsRoadTypeAvailable(Tram):     " + AIRoad.IsRoadTypeAvailable(AIRoad.ROADTYPE_TRAM));
 
	print("    SetCurrentRoadType(Tram):      " + AIRoad.SetCurrentRoadType(AIRoad.ROADTYPE_TRAM));
 
	print("    GetCurrentRoadType():          " + AIRoad.GetCurrentRoadType());
 

	
 
	print("  Depot");
 
	print("    IsRoadTile():                  " + AIRoad.IsRoadTile(33411));
 
	print("    BuildRoadDepot():              " + AIRoad.BuildRoadDepot(0, 1));
 
	print("    BuildRoadDepot():              " + AIRoad.BuildRoadDepot(33411, 33411));
 
	print("    BuildRoadDepot():              " + AIRoad.BuildRoadDepot(33411, 33414));
 
	print("    BuildRoadDepot():              " + AIRoad.BuildRoadDepot(33411, 33412));
 
	print("    HasRoadType(Road):             " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_ROAD));
 
	print("    HasRoadType(Tram):             " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_TRAM));
 
	print("    GetLastError():                " + AIError.GetLastError());
 
	print("    GetLastErrorString():          " + AIError.GetLastErrorString());
 
	print("    GetErrorCategory():            " + AIError.GetErrorCategory());
 
	print("    IsRoadTile():                  " + AIRoad.IsRoadTile(33411));
 
	print("    GetRoadDepotFrontTile():       " + AIRoad.GetRoadDepotFrontTile(33411));
 
	print("    IsRoadDepotTile():             " + AIRoad.IsRoadDepotTile(33411));
 
	print("    IsBuildable():                 " + AITile.IsBuildable(33411));
 
	local list = AIDepotList(AITile.TRANSPORT_ROAD);
 
	print("    DepotList");
 
	print("      Count():                     " + list.Count());
 
	list.Valuate(AITile.GetDistanceManhattanToTile, 0);
 
	print("      Depot distance from (0,0) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("        " + i + " => " + list.GetValue(i));
 
	}
 
	print("    RemoveRoadDepot():             " + AIRoad.RemoveRoadDepot(33411));
 
	print("    RemoveRoadDepot():             " + AIRoad.RemoveRoadDepot(33411));
 

	
 
	print("  Station");
 
	print("    IsRoadTile():                  " + AIRoad.IsRoadTile(33411));
 
	print("    BuildRoadStation():            " + AIRoad.BuildRoadStation(0, 1, false, false, true));
 
	print("    BuildRoadStation():            " + AIRoad.BuildRoadStation(33411, 33411, false, false, true));
 
	print("    BuildRoadStation():            " + AIRoad.BuildRoadStation(33411, 33414, false, false, true));
 
	print("    BuildRoadStation():            " + AIRoad.BuildRoadStation(33411, 33412, false, false, true));
 
	print("    IsStationTile():               " + AITile.IsStationTile(33411));
 
	print("    IsStationTile():               " + AITile.IsStationTile(33412));
 
	print("    HasRoadType(Road):             " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_ROAD));
 
	print("    HasRoadType(Tram):             " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_TRAM));
 
	print("    IsRoadTile():                  " + AIRoad.IsRoadTile(33411));
 
	print("    GetDriveThroughBackTile():     " + AIRoad.GetDriveThroughBackTile(33411));
 
	print("    GetRoadStationFrontTile():     " + AIRoad.GetRoadStationFrontTile(33411));
 
	print("    IsRoadStationTile():           " + AIRoad.IsRoadStationTile(33411));
 
	print("    IsDriveThroughRoadStationTile: " + AIRoad.IsDriveThroughRoadStationTile(33411));
 
	print("    RemoveRoadStation():           " + AIRoad.RemoveRoadStation(33411));
 
	print("    RemoveRoadStation():           " + AIRoad.RemoveRoadStation(33411));
 

	
 
	print("  Station Types");
 
	print("    BuildRoadStation(bus):         " + AIRoad.BuildRoadStation(33411, 33410, false, false, true));
 
	print("    BuildRoadStation(truck):       " + AIRoad.BuildRoadStation(33421, 33422, true,  false, true));
 
	print("    BuildRoadStation(truck):       " + AIRoad.BuildRoadStation(33412, 33413, true,  false, true));
 
	print("    BuildRoadStation(bus):         " + AIRoad.BuildRoadStation(33411 + 256, 33411, false, false, true));
 
	print("    BuildRoadStation(truck):       " + AIRoad.BuildRoadStation(33412 + 256, 33412 + 256 + 256, true,  false, true));
 
	print("    BuildRoadStation(bus-drive):   " + AIRoad.BuildRoadStation(33413, 33412, false, true, true));
 
	print("    BuildRoadStation(truck-drive): " + AIRoad.BuildRoadStation(33414, 33413, true,  true, true));
 
	print("    BuildRoadStation(bus-drive):   " + AIRoad.BuildRoadStation(33415, 33414, false, true, true));
 
	print("    BuildRoadStation(truck-drive): " + AIRoad.BuildRoadStation(33416, 33415, true,  true, true));
 
	print("    BuildRoadDepot():              " + AIRoad.BuildRoadDepot(33417, 33418));
 
	print("    GetRoadStationFrontTile():     " + AIRoad.GetRoadStationFrontTile(33411 + 256));
 
	print("    GetRoadStationFrontTile():     " + AIRoad.GetRoadStationFrontTile(33412 + 256));
 
	print("    IsDriveThroughRoadStationTile: " + AIRoad.IsDriveThroughRoadStationTile(33415));
 
	print("    IsBuildable():                 " + AITile.IsBuildable(33415));
 
	print("    GetDriveThroughBackTile():     " + AIRoad.GetDriveThroughBackTile(33415));
 
	print("    GetRoadStationFrontTile():     " + AIRoad.GetRoadStationFrontTile(33415));
 
	print("    IsRoadTile():                  " + AIRoad.IsRoadTile(33415));
 
}
 

	
 
function Regression::Sign()
 
{
 
	local j = 0;
 

	
 
	print("");
 
	print("--Sign--");
 
	print("  BuildSign(33410, 'Some Sign'):       " + AISign.BuildSign(33410, "Some Sign"));
 
	print("  BuildSign(33411, 'Test'):            " + AISign.BuildSign(33411, "Test"));
 
	print("  SetName(1, 'Test2'):                 " + AISign.SetName(1, "Test2"));
 
	local sign_id = AISign.BuildSign(33409, "Some other Sign");
 
	print("  BuildSign(33409, 'Some other Sign'): " + sign_id);
 
	print("  RemoveSign(" + sign_id + "):                       " + AISign.RemoveSign(sign_id));
 
	print("");
 
	print("  GetMaxSignID():    " + AISign.GetMaxSignID());
 
	for (local i = -1; i < AISign.GetMaxSignID() + 1; i++) {
 
		if (AISign.IsValidSign(i)) j++;
 
		print("  Sign " + i);
 
		print("    IsValidSign():   " + AISign.IsValidSign(i));
 
		print("    GetName():       " + AISign.GetName(i));
 
		print("    GetLocation():   " + AISign.GetLocation(i));
 
	}
 
	print("  Valid Signs:       " + j);
 
}
 

	
 
function Regression::Station()
 
{
 
	print("");
 
	print("--Station--");
 
	print("  IsValidStation(0):        " + AIStation.IsValidStation(0));
 
	print("  IsValidStation(1000):     " + AIStation.IsValidStation(1000));
 
	print("  GetName(0):               " + AIStation.GetName(0));
 
	print("  SetName(0):               " + AIStation.SetName(0, "Look, a station"));
 
	print("  GetName(0):               " + AIStation.GetName(0));
 
	print("  GetLocation(1):           " + AIStation.GetLocation(1));
 
	print("  GetLocation(1000):        " + AIStation.GetLocation(1000));
 
	print("  GetStationID(33411):      " + AIStation.GetStationID(33411));
 
	print("  GetStationID(34411):      " + AIStation.GetStationID(34411));
 
	print("  GetCargoWaiting(0, 0):    " + AIStation.GetCargoWaiting(0, 0));
 
	print("  GetCargoWaiting(1000, 0): " + AIStation.GetCargoWaiting(1000, 0));
 
	print("  GetCargoWaiting(0, 1000): " + AIStation.GetCargoWaiting(0, 1000));
 

	
 
	print("  GetStationID(33411):      " + AIStation.GetStationID(33411));
 
	print("  HasRoadType(3, TRAM):     " + AIStation.HasRoadType(3, AIRoad.ROADTYPE_TRAM));
 
	print("  HasRoadType(3, ROAD):     " + AIStation.HasRoadType(3, AIRoad.ROADTYPE_ROAD));
 
	print("  HasRoadType(33411, TRAM): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_TRAM));
 
	print("  HasRoadType(33411, ROAD): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_ROAD));
 
	print("  HasStationType(3, BUS):   " + AIStation.HasStationType(3, AIStation.STATION_BUS_STOP));
 
	print("  HasStationType(3, TRAIN): " + AIStation.HasStationType(3, AIStation.STATION_TRAIN));
 

	
 
	print("  GetCoverageRadius(BUS):   " + AIStation.GetCoverageRadius(AIStation.STATION_BUS_STOP));
 
	print("  GetCoverageRadius(TRUCK): " + AIStation.GetCoverageRadius(AIStation.STATION_TRUCK_STOP));
 
	print("  GetCoverageRadius(TRAIN): " + AIStation.GetCoverageRadius(AIStation.STATION_TRAIN));
 

	
 
	print("  GetNearestTown():         " + AIStation.GetNearestTown(0));
 
	print("  GetNearestTown():         " + AIStation.GetNearestTown(10000));
 
	print("  GetNearestTown():         " + AIStation.GetNearestTown(3));
 

	
 
	local list = AIStationList(AIStation.STATION_BUS_STOP + AIStation.STATION_TRUCK_STOP);
 

	
 
	print("");
 
	print("--StationList--");
 
	print("  Count():             " + list.Count());
 
	list.Valuate(AIStation.GetLocation);
 
	print("  Location ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIStation.GetCargoWaiting, 0);
 
	print("  CargoWaiting(0) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIStation.GetCargoWaiting, 1);
 
	print("  CargoWaiting(1) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
}
 

	
 
function Regression::Tile()
 
{
 
	print("");
 
	print("--Tile--");
 
	print("  HasTreeOnTile():      " + AITile.HasTreeOnTile(33148));
 
	print("  IsFarmTile():         " + AITile.IsFarmTile(32892));
 
	print("  IsRockTile():         " + AITile.IsRockTile(31606));
 
	print("  IsRoughTile():        " + AITile.IsRoughTile(33674));
 
	print("  HasTreeOnTile():      " + AITile.HasTreeOnTile(33404));
 
	print("  IsFarmTile():         " + AITile.IsFarmTile(33404));
 
	print("  IsRockTile():         " + AITile.IsRockTile(33404));
 
	print("  IsRoughTile():        " + AITile.IsRoughTile(33404));
 
	print("  IsSnowTile():         " + AITile.IsSnowTile(33404));
 
	print("  IsDesertTile():       " + AITile.IsDesertTile(33404));
 
	print("  PlantTree():          " + AITile.PlantTree(33404));
 
	print("  HasTreeOnTile():      " + AITile.HasTreeOnTile(33404));
 
	print("  PlantTree():          " + AITile.PlantTree(33404));
 
	print("  HasTreeOnTile():      " + AITile.HasTreeOnTile(33661));
 
	print("  PlantTreeRectangle(): " + AITile.PlantTreeRectangle(33404, 2, 2));
 
	print("  HasTreeOnTile():      " + AITile.HasTreeOnTile(33661));
 
}
 

	
 
function Regression::TileList()
 
{
 
	local list = AITileList();
 

	
 
	print("");
 
	print("--TileList--");
 
	print("  Count():             " + list.Count());
 
	list.AddRectangle(27631 - 256 * 1, 256 * 1 + 27631 + 2);
 
	print("  Count():             " + list.Count());
 

	
 
	list.Valuate(AITile.GetSlope);
 
	print("  Slope():             done");
 
	print("  Count():             " + list.Count());
 
	print("  ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
		print("    " + i + " => " + AITile.GetComplementSlope(list.GetValue(i)));
 
		print("    " + i + " => " + AITile.IsSteepSlope(list.GetValue(i)));
 
		print("    " + i + " => " + AITile.IsHalftileSlope(list.GetValue(i)));
 
	}
 
	list.Clear();
 

	
 
	print("");
 
	print("--TileList--");
 
	print("  Count():             " + list.Count());
 
	list.AddRectangle(41895 - 256 * 2, 256 * 2 + 41895 + 8);
 
	print("  Count():             " + list.Count());
 

	
 
	list.Valuate(AITile.GetHeight);
 
	print("  Height():            done");
 
	print("  Count():             " + list.Count());
 
	print("  ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list.Valuate(AITile.GetSlope);
 
	list.KeepValue(0);
 
	print("  Slope():             done");
 
	print("  KeepValue(0):        done");
 
	print("  Count():             " + list.Count());
 
	print("  ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list.Valuate(AITile.IsBuildable);
 
	list.KeepValue(1);
 
	print("  Buildable():         done");
 
	print("  KeepValue(1):        done");
 
	print("  Count():             " + list.Count());
 

	
 
	list.Valuate(AITile.IsBuildableRectangle, 3, 3);
 
	print("  BuildableRectangle(3, 3) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AITile.GetDistanceManhattanToTile, 30000);
 
	print("  DistanceManhattanToTile(30000) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AITile.GetDistanceSquareToTile, 30000);
 
	print("  DistanceSquareToTile(30000) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AITile.GetOwner);
 
	print("  GetOwner() ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AITile.GetClosestTown);
 
	print("  GetClosestTown() ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list.Valuate(AITile.GetCargoAcceptance, 0, 1, 1, 3);
 
	list.KeepAboveValue(10);
 
	print("  CargoAcceptance():   done");
 
	print("  KeepAboveValue(10):  done");
 
	print("  Count():             " + list.Count());
 
	print("  ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list.Valuate(AIRoad.IsRoadTile);
 
	list.KeepValue(1);
 
	print("  RoadTile():          done");
 
	print("  KeepValue(1):        done");
 
	print("  Count():             " + list.Count());
 
	print("  ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list.Valuate(AIRoad.GetNeighbourRoadCount);
 
	list.KeepValue(1);
 
	print("  NeighbourRoadCount():done");
 
	print("  KeepValue(1):        done");
 
	print("  Count():             " + list.Count());
 
	print("  ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list.AddRectangle(54421 - 256 * 2, 256 * 2 + 54421 + 8);
 
	list.Valuate(AITile.IsWaterTile);
 
	print("  Water():             done");
 
	print("  Count():             " + list.Count());
 
	print("  ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list = AITileList_IndustryAccepting(0, 3);
 
	print("");
 
	print("--TileList_IndustryAccepting--");
 
	print("  Count():             " + list.Count());
 
	list.Valuate(AITile.GetCargoAcceptance, 3, 1, 1, 3);
 
	print("  Location ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list = AITileList_IndustryProducing(1, 3);
 
	print("");
 
	print("--TileList_IndustryProducing--");
 
	print("  Count():             " + list.Count());
 
	list.Valuate(AITile.GetCargoProduction, 7, 1, 1, 3);
 
	print("  Location ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	list = AITileList_StationType(4, AIStation.STATION_BUS_STOP);
 
	print("");
 
	print("--TileList_StationType--");
 
	print("  Count():             " + list.Count());
 
	print("  Location ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
}
 

	
 
function Regression::Town()
 
{
 
	local j = 0;
 

	
 
	print("");
 
	print("--Town--");
 
	print("  GetMaxTownID():    " + AITown.GetMaxTownID());
 
	print("  GetTownCount():    " + AITown.GetTownCount());
 
	for (local i = -1; i < AITown.GetMaxTownID() + 1; i++) {
 
		if (AITown.IsValidTown(i)) j++;
 
		print("  Town " + i);
 
		print("    IsValidTown():   " + AITown.IsValidTown(i));
 
		print("    GetName():       " + AITown.GetName(i));
 
		print("    GetPopulation(): " + AITown.GetPopulation(i));
 
		print("    GetLocation():   " + AITown.GetLocation(i));
 
		print("    GetHouseCount(): " + AITown.GetHouseCount(i));
 
		print("    GetRating():     " + AITown.GetRating(i, AICompany.MY_COMPANY));
 
	}
 
	print("  Valid Towns:       " + j);
 
	print("  GetTownCount():    " + AITown.GetTownCount());
 
}
 

	
 
function Regression::TownList()
 
{
 
	local list = AITownList();
 

	
 
	print("");
 
	print("--TownList--");
 
	print("  Count():             " + list.Count());
 
	list.Valuate(AITown.GetLocation);
 
	print("  Location ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AITown.GetDistanceManhattanToTile, 30000);
 
	print("  DistanceManhattanToTile(30000) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AITown.GetDistanceSquareToTile, 30000);
 
	print("  DistanceSquareToTile(30000) ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AITown.IsWithinTownInfluence, AITown.GetLocation(0));
 
	print("  IsWithinTownInfluence(" + AITown.GetLocation(0) + ") ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AITown.GetAllowedNoise);
 
	print("  GetAllowedNoise() ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AITown.GetPopulation);
 
	list.KeepAboveValue(500);
 
	print("  KeepAboveValue(500): done");
 
	print("  Count():             " + list.Count());
 
	print("  Population ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 

	
 
	print("  HasStatue():                     " + AITown.HasStatue(list.Begin()));
 
	print("  GetRoadReworkDuration():         " + AITown.GetRoadReworkDuration(list.Begin()));
 
	print("  GetExclusiveRightsCompany():     " + AITown.GetExclusiveRightsCompany(list.Begin()));
 
	print("  GetExclusiveRightsDuration():    " + AITown.GetExclusiveRightsDuration(list.Begin()));
 
	print("  IsActionAvailable(BUILD_STATUE): " + AITown.IsActionAvailable(list.Begin(), AITown.TOWN_ACTION_BUILD_STATUE));
 
	print("  PerformTownAction(BUILD_STATUE): " + AITown.PerformTownAction(list.Begin(), AITown.TOWN_ACTION_BUILD_STATUE));
 
	print("  IsActionAvailable(BUILD_STATUE): " + AITown.IsActionAvailable(list.Begin(), AITown.TOWN_ACTION_BUILD_STATUE));
 
	print("  HasStatue():                     " + AITown.HasStatue(list.Begin()));
 
}
 

	
 
function Regression::Tunnel()
 
{
 
	print("");
 
	print("--Tunnel--");
 
	print("  IsTunnelTile():       " + AITunnel.IsTunnelTile(29050));
 
	print("  RemoveTunnel():       " + AITunnel.RemoveTunnel(29050));
 
	print("  GetOtherTunnelEnd():  " + AITunnel.GetOtherTunnelEnd(29050));
 
	print("  BuildTunnel():        " + AITunnel.BuildTunnel(AIVehicle.VEHICLE_ROAD, 29050));
 
	print("  GetOtherTunnelEnd():  " + AITunnel.GetOtherTunnelEnd(29050));
 
	print("  IsTunnelTile():       " + AITunnel.IsTunnelTile(29050));
 
	print("  IsTunnelTile():       " + AITunnel.IsTunnelTile(28026));
 
	print("  RemoveTunnel():       " + AITunnel.RemoveTunnel(29050));
 
	print("  IsTunnelTile():       " + AITunnel.IsTunnelTile(29050));
 

	
 
	print("  --Errors--");
 
	print("  BuildTunnel():        " + AITunnel.BuildTunnel(AIVehicle.VEHICLE_ROAD, 7529));
 
	print("  BuildTunnel():        " + AITunnel.BuildTunnel(AIVehicle.VEHICLE_ROAD, 8043));
 
	print("  GetLastErrorString(): " + AIError.GetLastErrorString());
 
	print("  RemoveTunnel():       " + AITunnel.RemoveTunnel(7529));
 
}
 

	
 
function Regression::Vehicle()
 
{
 
	local accounting = AIAccounting();
 

	
 
	print("");
 
	print("--Vehicle--");
 
	print("  IsValidVehicle(-1):   " + AIVehicle.IsValidVehicle(-1));
 
	print("  IsValidVehicle(0):    " + AIVehicle.IsValidVehicle(0));
 
	print("  IsValidVehicle(12):   " + AIVehicle.IsValidVehicle(12));
 
	print("  ISValidVehicle(9999): " + AIVehicle.IsValidVehicle(9999));
 

	
 
	local bank = AICompany.GetBankBalance(AICompany.MY_COMPANY);
 

	
 
	print("  BuildVehicle():       " + AIVehicle.BuildVehicle(33417, 153));
 
	print("  IsValidVehicle(12):   " + AIVehicle.IsValidVehicle(12));
 
	print("  CloneVehicle():       " + AIVehicle.CloneVehicle(33417, 12, true));
 

	
 
	local bank_after = AICompany.GetBankBalance(AICompany.MY_COMPANY);
 

	
 
	print("  --Accounting--");
 
	print("    GetCosts():         " + accounting.GetCosts());
 
	print("    Should be:          " + (bank - bank_after));
 
	print("    ResetCosts():       " + accounting.ResetCosts());
 

	
 
	bank = AICompany.GetBankBalance(AICompany.MY_COMPANY);
 

	
 
	print("  SellVehicle(13):      " + AIVehicle.SellVehicle(13));
 
	print("  IsInDepot():          " + AIVehicle.IsInDepot(12));
 
	print("  IsStoppedInDepot():   " + AIVehicle.IsStoppedInDepot(12));
 
	print("  StartStopVehicle():   " + AIVehicle.StartStopVehicle(12));
 
	print("  IsInDepot():          " + AIVehicle.IsInDepot(12));
 
	print("  IsStoppedInDepot():   " + AIVehicle.IsStoppedInDepot(12));
 
	print("  SendVehicleToDepot(): " + AIVehicle.SendVehicleToDepot(12));
 
	print("  IsInDepot():          " + AIVehicle.IsInDepot(12));
 
	print("  IsStoppedInDepot():   " + AIVehicle.IsStoppedInDepot(12));
 

	
 
	bank_after = AICompany.GetBankBalance(AICompany.MY_COMPANY);
 

	
 
	print("  --Accounting--");
 
	print("    GetCosts():         " + accounting.GetCosts());
 
	print("    Should be:          " + (bank - bank_after));
 

	
 
	print("  GetName():            " + AIVehicle.GetName(12));
 
	print("  SetName():            " + AIVehicle.SetName(12, "MyVehicleName"));
 
	print("  GetName():            " + AIVehicle.GetName(12));
 
	print("  CloneVehicle():       " + AIVehicle.CloneVehicle(33417, 12, true));
 

	
 
	print("  --VehicleData--");
 
	print("    GetLocation():       " + AIVehicle.GetLocation(12));
 
	print("    GetEngineType():     " + AIVehicle.GetEngineType(12));
 
	print("    GetUnitNumber():     " + AIVehicle.GetUnitNumber(12));
 
	print("    GetAge():            " + AIVehicle.GetAge(12));
 
	print("    GetMaxAge():         " + AIVehicle.GetMaxAge(12));
 
	print("    GetAgeLeft():        " + AIVehicle.GetAgeLeft(12));
 
	print("    GetCurrentSpeed():   " + AIVehicle.GetCurrentSpeed(12));
 
	print("    GetRunningCost():    " + AIVehicle.GetRunningCost(12));
 
	print("    GetProfitThisYear(): " + AIVehicle.GetProfitThisYear(12));
 
	print("    GetProfitLastYear(): " + AIVehicle.GetProfitLastYear(12));
 
	print("    GetCurrentValue():   " + AIVehicle.GetCurrentValue(12));
 
	print("    GetVehicleType():    " + AIVehicle.GetVehicleType(12));
 
	print("    GetRoadType():       " + AIVehicle.GetRoadType(12));
 
	print("    GetCapacity():       " + AIVehicle.GetCapacity(12, 10));
 
	print("    GetCargoLoad():      " + AIVehicle.GetCargoLoad(12, 10));
 
	print("    IsInDepot():         " + AIVehicle.IsInDepot(12));
 
	print("    GetNumWagons():      " + AIVehicle.GetNumWagons(12));
 
	print("    GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(12, 0));
 
	print("    GetWagonAge():       " + AIVehicle.GetWagonAge(12, 0));
 
	print("    GetLength():         " + AIVehicle.GetLength(12));
 

	
 
	print("  GetOwner():           " + AITile.GetOwner(32119));
 
	print("  BuildVehicle():       " + AIVehicle.BuildVehicle(32119, 219));
 
	print("  IsValidVehicle(14):   " + AIVehicle.IsValidVehicle(14));
 
	print("  IsInDepot(14):        " + AIVehicle.IsInDepot(14));
 
	print("  IsStoppedInDepot(14): " + AIVehicle.IsStoppedInDepot(14));
 
	print("  IsValidVehicle(15):   " + AIVehicle.IsValidVehicle(15));
 
	print("  IsInDepot(15):        " + AIVehicle.IsInDepot(15));
 
	print("  IsStoppedInDepot(15): " + AIVehicle.IsStoppedInDepot(15));
 

	
 
	print("  BuildVehicle():       " + AIVehicle.BuildVehicle(28479, 204));
 
	print("  IsValidVehicle(16):   " + AIVehicle.IsValidVehicle(16));
 
	print("  IsInDepot(16):        " + AIVehicle.IsInDepot(16));
 
	print("  IsStoppedInDepot(16): " + AIVehicle.IsStoppedInDepot(16));
 

	
 
	print("  BuildRailDepot():     " + AIRail.BuildRailDepot(10008, 10000));
 
	print("  BuildVehicle():       " + AIVehicle.BuildVehicle(10008, 9));
 
	print("  BuildVehicle():       " + AIVehicle.BuildVehicle(10008, 27));
 
	print("  BuildVehicle():       " + AIVehicle.BuildVehicle(10008, 27));
 
	print("  MoveWagon():          " + AIVehicle.MoveWagon(18, 0, true, 17, 0));
 
	print("  GetNumWagons():       " + AIVehicle.GetNumWagons(17));
 
	print("  GetLength():          " + AIVehicle.GetLength(17));
 
	print("  GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(17, 0));
 
	print("  GetWagonAge():        " + AIVehicle.GetWagonAge(17, 0));
 
	print("  GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(17, 1));
 
	print("  GetWagonAge():        " + AIVehicle.GetWagonAge(17, 1));
 
	print("  GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(17 2));
 
	print("  GetWagonAge():        " + AIVehicle.GetWagonAge(17, 2));
 
	print("  GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(17 3));
 
	print("  GetWagonAge():        " + AIVehicle.GetWagonAge(17, 3));
 

	
 
	print("  --Errors--");
 
	print("    RefitVehicle():        " + AIVehicle.RefitVehicle(12, 0));
 
	print("    GetLastErrorString():  " + AIError.GetLastErrorString());
 
	print("    SellVehicle():         " + AIVehicle.SellVehicle(12));
 
	print("    GetLastErrorString():  " + AIError.GetLastErrorString());
 
	print("    SendVehicleToDepot():  " + AIVehicle.SendVehicleToDepot(13));
 
	print("    GetLastErrorString():  " + AIError.GetLastErrorString());
 

	
 
	local list = AIVehicleList();
 

	
 
	print("");
 
	print("--VehicleList--");
 
	print("  Count():             " + list.Count());
 
	list.Valuate(AIVehicle.GetLocation);
 
	print("  Location ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIVehicle.GetEngineType);
 
	print("  EngineType ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIVehicle.GetUnitNumber);
 
	print("  UnitNumber ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIVehicle.GetAge);
 
	print("  Age ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIVehicle.GetMaxAge);
 
	print("  MaxAge ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIVehicle.GetAgeLeft);
 
	print("  AgeLeft ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIVehicle.GetCurrentSpeed);
 
	print("  CurrentSpeed ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIVehicle.GetRunningCost);
 
	print("  RunningCost ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIVehicle.GetProfitThisYear);
 
	print("  ProfitThisYear ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIVehicle.GetProfitLastYear);
 
	print("  ProfitLastYear ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIVehicle.GetCurrentValue);
 
	print("  CurrentValue ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIVehicle.GetVehicleType);
 
	print("  VehicleType ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIVehicle.GetRoadType);
 
	print("  RoadType ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIVehicle.GetCapacity, 10);
 
	print("  VehicleType ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
	list.Valuate(AIVehicle.GetCargoLoad, 10);
 
	print("  VehicleType ListDump:");
 
	for (local i = list.Begin(); list.HasNext(); i = list.Next()) {
 
		print("    " + i + " => " + list.GetValue(i));
 
	}
 
}
 

	
 
function Regression::PrintSubsidy(subsidy_id)
 
{
 
	print("      --Subsidy (" + subsidy_id + ") --");
 
	print("        IsValidSubsidy():     " + AISubsidy.IsValidSubsidy(subsidy_id));
 
	print("        IsAwarded():          " + AISubsidy.IsAwarded(subsidy_id));
 
	print("        GetAwardedTo():       " + AISubsidy.GetAwardedTo(subsidy_id));
 
	print("        GetExpireDate():      " + AISubsidy.GetExpireDate(subsidy_id));
 
	print("        SourceIsTown():       " + AISubsidy.SourceIsTown(subsidy_id));
 
	print("        GetSource():          " + AISubsidy.GetSource(subsidy_id));
 
	print("        DestionationIsTown(): " + AISubsidy.DestinationIsTown(subsidy_id));
 
	print("        GetDestionation():    " + AISubsidy.GetDestination(subsidy_id));
 
	print("        GetCargoType():       " + AISubsidy.GetCargoType(subsidy_id));
 
}
 

	
 

	
 
function Regression::Start()
 
{
 
	this.TestInit();
 
	this.Std();
 
	this.Base();
 
	this.List();
 
	this.Airport();
 
	this.Bridge();
 
	this.BridgeList();
 
	this.Cargo();
 
	this.CargoList();
 
	this.Company();
 
	this.Engine();
 
	this.EngineList();
 
	this.Graph();
 
	this.Group();
 
	this.Industry();
 
	this.IndustryList();
 
	this.IndustryTypeList();
 
	this.Map();
 
	this.Marine();
 
	this.Pathfinder();
 
	this.Queues();
 
	this.Rail();
 
	this.RailTypeList();
 
	this.Road();
 
	this.Sign();
 
	this.Station();
 
	this.Tile();
 
	this.TileList();
 
	this.Town();
 
	this.TownList();
 
	this.Tunnel();
 
	this.Vehicle();
 
	/* Order has to be after Vehicle */
 
	this.Order();
 
	print("");
 
	print("  First Subsidy Test");
 
	PrintSubsidy(0);
 

	
 
	while (AIEventController.IsEventWaiting()) {
 
		local e = AIEventController.GetNextEvent();
 
		print("  GetNextEvent:          " + (e == null ? "null" : "instance"));
 
		print("    GetEventType:        " + e.GetEventType());
 
		switch (e.GetEventType()) {
 
			case AIEvent.AI_ET_SUBSIDY_OFFER: {
 
				local c = AIEventSubsidyOffer.Convert(e);
 
				print("      EventName:         SubsidyOffer");
 
				PrintSubsidy(c.GetSubsidyID());
 
			} break;
 

	
 
			case AIEvent.AI_ET_VEHICLE_WAITING_IN_DEPOT: {
 
				local c = AIEventVehicleWaitingInDepot.Convert(e);
 
				print("      EventName:         VehicleWaitingInDepot");
 
				print("      VehicleID:         " + c.GetVehicleID());
 
			} break;
 

	
 
			default:
 
				print("      Unknown Event");
 
				break;
 
		}
 
	}
 
	print("  IsEventWaiting:        false");
 
}
 

	

Changeset was too big and was cut off... Show full diff anyway

0 comments (0 inline, 0 general)