diff options
-rw-r--r-- | bin/ai/library/graph/aystar/library.nut | 14 | ||||
-rw-r--r-- | bin/ai/library/graph/aystar/main.nut | 238 | ||||
-rw-r--r-- | bin/ai/library/pathfinder/rail/library.nut | 14 | ||||
-rw-r--r-- | bin/ai/library/pathfinder/rail/main.nut | 389 | ||||
-rw-r--r-- | bin/ai/library/pathfinder/road/library.nut | 14 | ||||
-rw-r--r-- | bin/ai/library/pathfinder/road/main.nut | 363 | ||||
-rw-r--r-- | bin/ai/library/queue/binary_heap/library.nut | 14 | ||||
-rw-r--r-- | bin/ai/library/queue/binary_heap/main.nut | 131 | ||||
-rw-r--r-- | bin/ai/library/queue/fibonacci_heap/library.nut | 14 | ||||
-rw-r--r-- | bin/ai/library/queue/fibonacci_heap/main.nut | 204 | ||||
-rw-r--r-- | bin/ai/library/queue/priority_queue/library.nut | 14 | ||||
-rw-r--r-- | bin/ai/library/queue/priority_queue/main.nut | 115 | ||||
-rw-r--r-- | bin/ai/wrightai/info.nut | 16 | ||||
-rw-r--r-- | bin/ai/wrightai/main.nut | 387 |
14 files changed, 0 insertions, 1927 deletions
diff --git a/bin/ai/library/graph/aystar/library.nut b/bin/ai/library/graph/aystar/library.nut deleted file mode 100644 index 1f563961a..000000000 --- a/bin/ai/library/graph/aystar/library.nut +++ /dev/null @@ -1,14 +0,0 @@ -/* $Id$ */ - -class AyStar extends AILibrary { - function GetAuthor() { return "OpenTTD NoAI Developers Team"; } - function GetName() { return "AyStar"; } - function GetShortName() { return "GRA*"; } - function GetDescription() { return "An implementation of AyStar"; } - function GetVersion() { return 4; } - function GetDate() { return "2008-06-11"; } - function CreateInstance() { return "AyStar"; } - function GetCategory() { return "Graph"; } -} - -RegisterLibrary(AyStar()); diff --git a/bin/ai/library/graph/aystar/main.nut b/bin/ai/library/graph/aystar/main.nut deleted file mode 100644 index 1999eab14..000000000 --- a/bin/ai/library/graph/aystar/main.nut +++ /dev/null @@ -1,238 +0,0 @@ -/* $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; } -}; diff --git a/bin/ai/library/pathfinder/rail/library.nut b/bin/ai/library/pathfinder/rail/library.nut deleted file mode 100644 index 8f0dbad08..000000000 --- a/bin/ai/library/pathfinder/rail/library.nut +++ /dev/null @@ -1,14 +0,0 @@ -/* $Id$ */ - -class Rail extends AILibrary { - function GetAuthor() { return "OpenTTD NoAI Developers Team"; } - function GetName() { return "Rail"; } - function GetShortName() { return "PFRL"; } - function GetDescription() { return "An implementation of a rail pathfinder"; } - function GetVersion() { return 1; } - function GetDate() { return "2008-09-22"; } - function CreateInstance() { return "Rail"; } - function GetCategory() { return "Pathfinder"; } -} - -RegisterLibrary(Rail()); diff --git a/bin/ai/library/pathfinder/rail/main.nut b/bin/ai/library/pathfinder/rail/main.nut deleted file mode 100644 index 2a9186799..000000000 --- a/bin/ai/library/pathfinder/rail/main.nut +++ /dev/null @@ -1,389 +0,0 @@ -/* $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.VT_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.VT_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; -} diff --git a/bin/ai/library/pathfinder/road/library.nut b/bin/ai/library/pathfinder/road/library.nut deleted file mode 100644 index 727cdb9b0..000000000 --- a/bin/ai/library/pathfinder/road/library.nut +++ /dev/null @@ -1,14 +0,0 @@ -/* $Id$ */ - -class Road extends AILibrary { - function GetAuthor() { return "OpenTTD NoAI Developers Team"; } - function GetName() { return "Road"; } - function GetShortName() { return "PFRO"; } - function GetDescription() { return "An implementation of a road pathfinder"; } - function GetVersion() { return 3; } - function GetDate() { return "2008-06-18"; } - function CreateInstance() { return "Road"; } - function GetCategory() { return "Pathfinder"; } -} - -RegisterLibrary(Road()); diff --git a/bin/ai/library/pathfinder/road/main.nut b/bin/ai/library/pathfinder/road/main.nut deleted file mode 100644 index 9c5564656..000000000 --- a/bin/ai/library/pathfinder/road/main.nut +++ /dev/null @@ -1,363 +0,0 @@ -/* $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.VT_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.VT_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; -} diff --git a/bin/ai/library/queue/binary_heap/library.nut b/bin/ai/library/queue/binary_heap/library.nut deleted file mode 100644 index 5216fb588..000000000 --- a/bin/ai/library/queue/binary_heap/library.nut +++ /dev/null @@ -1,14 +0,0 @@ -/* $Id$ */ - -class Binary_Heap extends AILibrary { - function GetAuthor() { return "OpenTTD NoAI Developers Team"; } - function GetName() { return "Binary Heap"; } - function GetShortName() { return "QUBH"; } - function GetDescription() { return "An implementation of a Binary Heap"; } - function GetVersion() { return 1; } - function GetDate() { return "2008-06-10"; } - function CreateInstance() { return "Binary_Heap"; } - function GetCategory() { return "Queue"; } -} - -RegisterLibrary(Binary_Heap()); diff --git a/bin/ai/library/queue/binary_heap/main.nut b/bin/ai/library/queue/binary_heap/main.nut deleted file mode 100644 index 05fd452f3..000000000 --- a/bin/ai/library/queue/binary_heap/main.nut +++ /dev/null @@ -1,131 +0,0 @@ -/* $Id$ */ - -/** - * Binary Heap. - * Peek and Pop always return the current lowest value in the list. - * Sort is done on insertion and on deletion. - */ -class Binary_Heap -{ - _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 Binary_Heap::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 Binary_Heap::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 Binary_Heap::Peek() -{ - if (_count == 0) return null; - - return _queue[0][0]; -} - -function Binary_Heap::Count() -{ - return _count; -} - -function Binary_Heap::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 Binary_Heap::_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; -} diff --git a/bin/ai/library/queue/fibonacci_heap/library.nut b/bin/ai/library/queue/fibonacci_heap/library.nut deleted file mode 100644 index 6cbd614da..000000000 --- a/bin/ai/library/queue/fibonacci_heap/library.nut +++ /dev/null @@ -1,14 +0,0 @@ -/* $Id$ */ - -class Fibonacci_Heap extends AILibrary { - function GetAuthor() { return "OpenTTD NoAI Developers Team"; } - function GetName() { return "Fibonacci Heap"; } - function GetShortName() { return "QUFH"; } - function GetDescription() { return "An implementation of a Fibonacci Heap"; } - function GetVersion() { return 1; } - function GetDate() { return "2008-08-22"; } - function CreateInstance() { return "Fibonacci_Heap"; } - function GetCategory() { return "Queue"; } -} - -RegisterLibrary(Fibonacci_Heap()); diff --git a/bin/ai/library/queue/fibonacci_heap/main.nut b/bin/ai/library/queue/fibonacci_heap/main.nut deleted file mode 100644 index 6be8bdd49..000000000 --- a/bin/ai/library/queue/fibonacci_heap/main.nut +++ /dev/null @@ -1,204 +0,0 @@ -/* $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 Fibonacci_Heap { - _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 Fibonacci_Heap::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 Fibonacci_Heap::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 Fibonacci_Heap::Peek() { - if (_count == 0) return null; - return _min.item; -} - -function Fibonacci_Heap::Count() { - return _count; -} - -function Fibonacci_Heap::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 Fibonacci_Heap::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 Fibonacci_Heap.Node { - degree = null; - child = null; - - item = null; - priority = null; - - constructor() { - child = []; - degree = 0; - } -}; diff --git a/bin/ai/library/queue/priority_queue/library.nut b/bin/ai/library/queue/priority_queue/library.nut deleted file mode 100644 index 1559393ee..000000000 --- a/bin/ai/library/queue/priority_queue/library.nut +++ /dev/null @@ -1,14 +0,0 @@ -/* $Id$ */ - -class Priority_Queue extends AILibrary { - function GetAuthor() { return "OpenTTD NoAI Developers Team"; } - function GetName() { return "Priority Queue"; } - function GetShortName() { return "QUPQ"; } - function GetDescription() { return "An implementation of a Priority Queue"; } - function GetVersion() { return 2; } - function GetDate() { return "2008-06-10"; } - function CreateInstance() { return "Priority_Queue"; } - function GetCategory() { return "Queue"; } -} - -RegisterLibrary(Priority_Queue()); diff --git a/bin/ai/library/queue/priority_queue/main.nut b/bin/ai/library/queue/priority_queue/main.nut deleted file mode 100644 index feda89559..000000000 --- a/bin/ai/library/queue/priority_queue/main.nut +++ /dev/null @@ -1,115 +0,0 @@ -/* $Id$ */ - -/** - * Priority Queue. - * Peek and Pop always return the current lowest value in the list. - * Sort is done on insertion only. - */ -class Priority_Queue -{ - _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 Priority_Queue::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 Priority_Queue::Pop() -{ - if (_count == 0) return null; - - local node = _queue.pop(); - _count--; - - return node[0]; -} - -function Priority_Queue::Peek() -{ - if (_count == 0) return null; - - return _queue[_count - 1][0]; -} - -function Priority_Queue::Count() -{ - return _count; -} - -function Priority_Queue::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; -} diff --git a/bin/ai/wrightai/info.nut b/bin/ai/wrightai/info.nut deleted file mode 100644 index 7a3feb8c5..000000000 --- a/bin/ai/wrightai/info.nut +++ /dev/null @@ -1,16 +0,0 @@ -/* $Id$ */ - -class WrightAI extends AIInfo { - function GetAuthor() { return "OpenTTD NoAI Developers Team"; } - function GetName() { return "WrightAI"; } - function GetShortName() { return "WRAI"; } - function GetDescription() { return "A simple AI that tries to beat you with only aircrafts"; } - function GetVersion() { return 2; } - function GetDate() { return "2008-02-24"; } - function CreateInstance() { return "WrightAI"; } - function GetSettings() { - AddSetting({name = "min_town_size", description = "The minimal size of towns to work on", min_value = 100, max_value = 1000, easy_value = 500, medium_value = 400, hard_value = 300, custom_value = 500, flags = 0}); - } -} - -RegisterAI(WrightAI()); diff --git a/bin/ai/wrightai/main.nut b/bin/ai/wrightai/main.nut deleted file mode 100644 index 3c10aeca9..000000000 --- a/bin/ai/wrightai/main.nut +++ /dev/null @@ -1,387 +0,0 @@ -/* $Id$ */ - -class WrightAI extends AIController { - name = null; - towns_used = null; - route_1 = null; - route_2 = null; - distance_of_route = {}; - vehicle_to_depot = {}; - delay_build_airport_route = 1000; - passenger_cargo_id = -1; - - function Start(); - - constructor() { - this.towns_used = AIList(); - this.route_1 = AIList(); - this.route_2 = AIList(); - - local list = AICargoList(); - for (local i = list.Begin(); list.HasNext(); i = list.Next()) { - if (AICargo.HasCargoClass(i, AICargo.CC_PASSENGERS)) { - this.passenger_cargo_id = i; - break; - } - } - } -}; - -/** - * Check if we have enough money (via loan and on bank). - */ -function WrightAI::HasMoney(money) -{ - if (AICompany.GetBankBalance(AICompany.COMPANY_SELF) + (AICompany.GetMaxLoanAmount() - AICompany.GetLoanAmount()) > money) return true; - return false; -} - -/** - * Get the amount of money requested, loan if needed. - */ -function WrightAI::GetMoney(money) -{ - if (!this.HasMoney(money)) return; - if (AICompany.GetBankBalance(AICompany.COMPANY_SELF) > money) return; - - local loan = money - AICompany.GetBankBalance(AICompany.COMPANY_SELF) + AICompany.GetLoanInterval() + AICompany.GetLoanAmount(); - loan = loan - loan % AICompany.GetLoanInterval(); - AILog.Info("Need a loan to get " + money + ": " + loan); - AICompany.SetLoanAmount(loan); -} - -/** - * Build an airport route. Find 2 cities that are big enough and try to build airport in both cities. - * Then we can build an aircraft and make some money. - */ -function WrightAI::BuildAirportRoute() -{ - local airport_type = (AIAirport.AirportAvailable(AIAirport.AT_SMALL) ? AIAirport.AT_SMALL : AIAirport.AT_LARGE); - - /* Get enough money to work with */ - this.GetMoney(150000); - - AILog.Info("Trying to build an airport route"); - - local tile_1 = this.FindSuitableAirportSpot(airport_type, 0); - if (tile_1 < 0) return -1; - local tile_2 = this.FindSuitableAirportSpot(airport_type, tile_1); - if (tile_2 < 0) { - this.towns_used.RemoveValue(tile_1); - return -2; - } - - /* Build the airports for real */ - if (!AIAirport.BuildAirport(tile_1, airport_type, true)) { - AILog.Error("Although the testing told us we could build 2 airports, it still failed on the first airport at tile " + tile_1 + "."); - this.towns_used.RemoveValue(tile_1); - this.towns_used.RemoveValue(tile_2); - return -3; - } - if (!AIAirport.BuildAirport(tile_2, airport_type, true)) { - AILog.Error("Although the testing told us we could build 2 airports, it still failed on the second airport at tile " + tile_2 + "."); - AIAirport.RemoveAirport(tile_1); - this.towns_used.RemoveValue(tile_1); - this.towns_used.RemoveValue(tile_2); - return -4; - } - - local ret = this.BuildAircraft(tile_1, tile_2); - if (ret < 0) { - AIAirport.RemoveAirport(tile_1); - AIAirport.RemoveAirport(tile_2); - this.towns_used.RemoveValue(tile_1); - this.towns_used.RemoveValue(tile_2); - return ret; - } - - AILog.Info("Done building a route"); - return ret; -} - -/** - * Build an aircraft with orders from tile_1 to tile_2. - * The best available aircraft of that time will be bought. - */ -function WrightAI::BuildAircraft(tile_1, tile_2) -{ - /* Build an aircraft */ - local hangar = AIAirport.GetHangarOfAirport(tile_1); - local engine = null; - - local engine_list = AIEngineList(AIVehicle.VT_AIR); - - /* When bank balance < 300000, buy cheaper planes */ - local balance = AICompany.GetBankBalance(AICompany.COMPANY_SELF); - engine_list.Valuate(AIEngine.GetPrice); - engine_list.KeepBelowValue(balance < 300000 ? 50000 : (balance < 1000000 ? 300000 : 1000000)); - - engine_list.Valuate(AIEngine.GetCargoType); - engine_list.KeepValue(this.passenger_cargo_id); - - engine_list.Valuate(AIEngine.GetCapacity); - engine_list.KeepTop(1); - - engine = engine_list.Begin(); - - if (!AIEngine.IsValidEngine(engine)) { - AILog.Error("Couldn't find a suitable engine"); - return -5; - } - local vehicle = AIVehicle.BuildVehicle(hangar, engine); - if (!AIVehicle.IsValidVehicle(vehicle)) { - AILog.Error("Couldn't build the aircraft"); - return -6; - } - /* Send him on his way */ - AIOrder.AppendOrder(vehicle, tile_1, AIOrder.AIOF_NONE); - AIOrder.AppendOrder(vehicle, tile_2, AIOrder.AIOF_NONE); - AIVehicle.StartStopVehicle(vehicle); - this.distance_of_route.rawset(vehicle, AIMap.DistanceManhattan(tile_1, tile_2)); - this.route_1.AddItem(vehicle, tile_1); - this.route_2.AddItem(vehicle, tile_2); - - AILog.Info("Done building an aircraft"); - - return 0; -} - -/** - * Find a suitable spot for an airport, walking all towns hoping to find one. - * When a town is used, it is marked as such and not re-used. - */ -function WrightAI::FindSuitableAirportSpot(airport_type, center_tile) -{ - local airport_x, airport_y, airport_rad; - - airport_x = AIAirport.GetAirportWidth(airport_type); - airport_y = AIAirport.GetAirportHeight(airport_type); - airport_rad = AIAirport.GetAirportCoverageRadius(airport_type); - - local town_list = AITownList(); - /* Remove all the towns we already used */ - town_list.RemoveList(this.towns_used); - - town_list.Valuate(AITown.GetPopulation); - town_list.KeepAboveValue(GetSetting("min_town_size")); - /* Keep the best 10, if we can't find 2 stations in there, just leave it anyway */ - town_list.KeepTop(10); - town_list.Valuate(AIBase.RandItem); - - /* Now find 2 suitable towns */ - for (local town = town_list.Begin(); town_list.HasNext(); town = town_list.Next()) { - /* Don't make this a CPU hog */ - Sleep(1); - - local tile = AITown.GetLocation(town); - - /* Create a 30x30 grid around the core of the town and see if we can find a spot for a small airport */ - local list = AITileList(); - /* XXX -- We assume we are more than 15 tiles away from the border! */ - list.AddRectangle(tile - AIMap.GetTileIndex(15, 15), tile + AIMap.GetTileIndex(15, 15)); - list.Valuate(AITile.IsBuildableRectangle, airport_x, airport_y); - list.KeepValue(1); - if (center_tile != 0) { - /* If we have a tile defined, we don't want to be within 25 tiles of this tile */ - list.Valuate(AITile.GetDistanceSquareToTile, center_tile); - list.KeepAboveValue(625); - } - /* Sort on acceptance, remove places that don't have acceptance */ - list.Valuate(AITile.GetCargoAcceptance, this.passenger_cargo_id, airport_x, airport_y, airport_rad); - list.RemoveBelowValue(10); - - /* Couldn't find a suitable place for this town, skip to the next */ - if (list.Count() == 0) continue; - /* Walk all the tiles and see if we can build the airport at all */ - { - local test = AITestMode(); - local good_tile = 0; - - for (tile = list.Begin(); list.HasNext(); tile = list.Next()) { - Sleep(1); - if (!AIAirport.BuildAirport(tile, airport_type, true)) continue; - good_tile = tile; - break; - } - - /* Did we found a place to build the airport on? */ - if (good_tile == 0) continue; - } - - AILog.Info("Found a good spot for an airport in town " + town + " at tile " + tile); - - /* Make the town as used, so we don't use it again */ - this.towns_used.AddItem(town, tile); - - return tile; - } - - AILog.Info("Couldn't find a suitable town to build an airport in"); - return -1; -} - -function WrightAI::ManageAirRoutes() -{ - local list = AIVehicleList(); - list.Valuate(AIVehicle.GetAge); - /* Give the plane at least 2 years to make a difference */ - list.KeepAboveValue(365 * 2); - list.Valuate(AIVehicle.GetProfitLastYear); - - for (local i = list.Begin(); list.HasNext(); i = list.Next()) { - local profit = list.GetValue(i); - /* Profit last year and this year bad? Let's sell the vehicle */ - if (profit < 10000 && AIVehicle.GetProfitThisYear(i) < 10000) { - /* Send the vehicle to depot if we didn't do so yet */ - if (!vehicle_to_depot.rawin(i) || vehicle_to_depot.rawget(i) != true) { - AILog.Info("Sending " + i + " to depot as profit is: " + profit + " / " + AIVehicle.GetProfitThisYear(i)); - AIVehicle.SendVehicleToDepot(i); - vehicle_to_depot.rawset(i, true); - } - } - /* Try to sell it over and over till it really is in the depot */ - if (vehicle_to_depot.rawin(i) && vehicle_to_depot.rawget(i) == true) { - if (AIVehicle.SellVehicle(i)) { - AILog.Info("Selling " + i + " as it finally is in a depot."); - /* Check if we are the last one serving those airports; else sell the airports */ - local list2 = AIVehicleList_Station(AIStation.GetStationID(this.route_1.GetValue(i))); - if (list2.Count() == 0) this.SellAirports(i); - vehicle_to_depot.rawdelete(i); - } - } - } - - /* Don't try to add planes when we are short on cash */ - if (!this.HasMoney(50000)) return; - - list = AIStationList(AIStation.STATION_AIRPORT); - list.Valuate(AIStation.GetCargoWaiting, this.passenger_cargo_id); - list.KeepAboveValue(250); - - for (local i = list.Begin(); list.HasNext(); i = list.Next()) { - local list2 = AIVehicleList_Station(i); - /* No vehicles going to this station, abort and sell */ - if (list2.Count() == 0) { - this.SellAirports(i); - continue; - }; - - /* Find the first vehicle that is going to this station */ - local v = list2.Begin(); - local dist = this.distance_of_route.rawget(v); - - list2.Valuate(AIVehicle.GetAge); - list2.KeepBelowValue(dist); - /* Do not build a new vehicle if we bought a new one in the last DISTANCE days */ - if (list2.Count() != 0) continue; - - AILog.Info("Station " + i + " (" + AIStation.GetLocation(i) + ") has too many cargo, adding a new vehicle for the route."); - - /* Make sure we have enough money */ - this.GetMoney(50000); - - return this.BuildAircraft(this.route_1.GetValue(v), this.route_2.GetValue(v)); - } -} - -/** - * Sells the airports from route index i - * Removes towns from towns_used list too - */ -function WrightAI::SellAirports(i) { - /* Remove the airports */ - AILog.Info("Removing airports as nobody serves them anymore."); - AIAirport.RemoveAirport(this.route_1.GetValue(i)); - AIAirport.RemoveAirport(this.route_2.GetValue(i)); - /* Free the towns_used entries */ - this.towns_used.RemoveValue(this.route_1.GetValue(i)); - this.towns_used.RemoveValue(this.route_2.GetValue(i)); - /* Remove the route */ - this.route_1.RemoveItem(i); - this.route_2.RemoveItem(i); -} - -function WrightAI::HandleEvents() -{ - while (AIEventController.IsEventWaiting()) { - local e = AIEventController.GetNextEvent(); - switch (e.GetEventType()) { - case AIEvent.AI_ET_VEHICLE_CRASHED: { - local ec = AIEventVehicleCrashed.Convert(e); - local v = ec.GetVehicleID(); - AILog.Info("We have a crashed vehicle (" + v + "), buying a new one as replacement"); - this.BuildAircraft(this.route_1.GetValue(v), this.route_2.GetValue(v)); - this.route_1.RemoveItem(v); - this.route_2.RemoveItem(v); - } break; - - default: - break; - } - } -} - -function WrightAI::Start() -{ - if (this.passenger_cargo_id == -1) { - AILog.Error("WrightAI could not find the passenger cargo"); - return; - } - - /* Give the boy a name */ - if (!AICompany.SetName("WrightAI")) { - local i = 2; - while (!AICompany.SetName("WrightAI #" + i)) { - i++; - } - } - this.name = AICompany.GetName(AICompany.COMPANY_SELF); - /* Say hello to the user */ - AILog.Info("Welcome to WrightAI. I will be building airports all day long."); - AILog.Info(" - Minimum Town Size: " + GetSetting("min_town_size")); - - /* We start with almost no loan, and we take a loan when we want to build something */ - AICompany.SetLoanAmount(AICompany.GetLoanInterval()); - - /* We need our local ticker, as GetTick() will skip ticks */ - local ticker = 0; - /* Determine time we may sleep */ - local sleepingtime = 100; - if (this.delay_build_airport_route < sleepingtime) - sleepingtime = this.delay_build_airport_route; - - /* Let's go on for ever */ - while (true) { - /* Once in a while, with enough money, try to build something */ - if ((ticker % this.delay_build_airport_route == 0 || ticker == 0) && this.HasMoney(100000)) { - local ret = this.BuildAirportRoute(); - if (ret == -1 && ticker != 0) { - /* No more route found, delay even more before trying to find an other */ - this.delay_build_airport_route = 10000; - } - else if (ret < 0 && ticker == 0) { - /* The AI failed to build a first airport and is deemed */ - AICompany.SetName("Failed " + this.name); - AILog.Error("Failed to build first airport route, now giving up building. Repaying loan. Have a nice day!"); - AICompany.SetLoanAmount(0); - return; - } - } - /* Manage the routes once in a while */ - if (ticker % 2000 == 0) { - this.ManageAirRoutes(); - } - /* Try to get ride of our loan once in a while */ - if (ticker % 5000 == 0) { - AICompany.SetLoanAmount(0); - } - /* Check for events once in a while */ - if (ticker % 100 == 0) { - this.HandleEvents(); - } - /* Make sure we do not create infinite loops */ - Sleep(sleepingtime); - ticker += sleepingtime; - } -} - |