/// <summary> /// Uses A*-algorithm to find the best route between two tiles. /// </summary> /// <param name="start">First tile to search from.</param> /// <param name="goal">Goal to find.</param> /// <param name="previous">Tile just before the first tile.</param> /// <param name="forbidden">List of tiles that should be never used on route.</param> /// <param name="sign">Optional function for building signs.</param> /// <returns></returns> internal static List <PathInfo> FindPath(TileIndex start, TileIndex goal, TileIndex previous, HashSet <TileIndex> forbidden = null, Action <TileIndex, string> sign = null) { // Nodes to evaluate var tilesToProcess = new FibonacciHeap <TileIndex>(); tilesToProcess.Insert(start, 0); // Nodes evaluated var cameFrom = new Dictionary <TileIndex, PathInfo>(); cameFrom[start] = new PathInfo(start, 1, 0, BuildType.Basic, previous != null ? new PathInfo(previous, 1, 0, BuildType.Basic, null) : null); while (tilesToProcess.Count() > 0) { var current = tilesToProcess.Pop(); //AILog.Info($"Processing: {Helper.FormatTile(current)}"); if (current == goal) { // We found the target. return(RoadBuilder.BuildFinalPath(cameFrom[current])); } var neighbors = RoadBuilder.GetNeighbors(current, cameFrom[current]); foreach (var neighborItem in neighbors) { var neighbor = neighborItem.Tile; if ((neighbor == previous) || ((forbidden != null) && forbidden.Contains(neighbor))) { // We can't go here. continue; } var neighborDist = neighborItem.Length; if (!cameFrom.ContainsKey(neighbor)) { tilesToProcess.Insert(neighbor, neighborItem.Cost); } else { if (neighborItem.Cost >= cameFrom[neighbor].Cost) { continue; } } sign?.Invoke(neighbor, neighborItem.Cost.ToString()); cameFrom[neighbor] = neighborItem; } } return(null); }
protected override void Start() { AICompany.SetLoanAmount(0); SignManager signManager = new SignManager(); TownNetwork tn = new TownNetwork(); try { AICompany.SetLoanAmount(AICompany.GetMaxLoanAmount()); AIRoad.SetCurrentRoadType(AIRoad.ROADTYPE_ROAD); foreach (var edge in tn.Graph.Edges) { AILog.Info($"Build road from {edge.Node1.Name} to {edge.Node2.Name}."); var stationInfo1 = tn.EnsureStation(edge.Node1); var stationInfo2 = tn.EnsureStation(edge.Node2); RoadBuilder.BuildRoad( stationInfo1.tile, stationInfo1.entryPoint, stationInfo2.entryPoint, stationInfo2.tile, new HashSet <TileIndex>() ); var depotInfo1 = tn.EnsureDepot(edge.Node1); var depotInfo2 = tn.EnsureDepot(edge.Node2); tn.MakeRoute(edge.Node1, edge.Node2); tn.MakeRoute(edge.Node2, edge.Node1); } } catch { } Sleep(50); signManager.ClearSigns(); var step = 0; while (true) { // Main loop //this.setMinLoan(); CsTestAi.SetMinimumLoanAmount(); tn.UpdateRoutes(); Sleep(100); step++; } }
internal static bool BuildRoad(TileIndex previous, TileIndex from, TileIndex to, TileIndex next, HashSet <TileIndex> forbidden, Action <TileIndex, string> sign = null) { var path = RoadBuilder.FindPath(from, to, previous, forbidden); if (path == null) { return(false); } for (var i = 0; i < path.Count - 1; i++) { var p = i == 0 ? next : path[i - 1].Tile; var c = path[i].Tile; var n = i == path.Count - 1 ? previous : path[i + 1].Tile; var nt = i == 0 ? BuildType.Basic : path[i - 1].Type; //sign(c, "[" + AIMap.GetTileX(c) + ", " + AIMap.GetTileY(c) + "] " + path[i].type); bool good = false; switch (path[i].Type) { case BuildType.Basic: if (path[i].Length > 1) { AILog.Error($"Length is: {path[i].Length}. ([" + AIMap.GetTileX(p) + ", " + AIMap.GetTileY(p) + "] via [" + AIMap.GetTileX(c) + ", " + AIMap.GetTileY(c) + "] to [" + AIMap.GetTileX(n) + ", " + AIMap.GetTileY(n) + "])"); continue; //throw new Exception("Should not be Road"); } if (nt != BuildType.Basic) { continue; } //AILog.Info("Build a Road from [" + AIMap.GetTileX(p) + ", " + AIMap.GetTileY(p) + "] via [" + AIMap.GetTileX(c) + ", " + AIMap.GetTileY(c) + "] to [" + AIMap.GetTileX(n) + ", " + AIMap.GetTileY(n) + "]."); good = AIRoad.BuildRoad(p, c); good = AIRoad.BuildRoad(c, n); break; case BuildType.Bridge: var bridgeTypes = new AIBridgeList_Length(path[i].Length); //AILog.Info("Build a bridge " + bridgeTypes.Begin() + " from [" + AIMap.GetTileX(c) + ", " + AIMap.GetTileY(c) + "] to [" + AIMap.GetTileX(n) + ", " + AIMap.GetTileY(n) + "]."); good = AIBridge.BuildBridge(AIVehicle.VT_ROAD, bridgeTypes.Begin(), c, n); if ((!good) && (sign != null)) { sign(p, "s"); sign(c, "e"); } break; case BuildType.Tunnel: throw new Exception("Tunnels not supported"); } if (!good) { var reason = AIError.GetLastErrorString(); if (reason != "ERR_ALREADY_BUILT") { AILog.Error("Failed to build on [" + AIMap.GetTileX(c) + ", " + AIMap.GetTileY(c) + "]. Reason: " + reason); } } } return(true); }