public int GetDestinationCost(Pos destination) { openList.Clear(); closedList.Clear(); int _destinationX = destination.x; int _destinationY = destination.y; openList.Add(globalMap[gameInfo.myHero.pos.x, gameInfo.myHero.pos.y]); PathfinderTile lastTileAddedToClosedList; do { AddLowestHeuristicToClosedListFromOpenList(_destinationX, _destinationY); lastTileAddedToClosedList = closedList.ElementAt(closedList.Count - 1); openList.Remove(lastTileAddedToClosedList); AddSurroundingTilesToOpenList(lastTileAddedToClosedList.x, lastTileAddedToClosedList.y, globalMap[_destinationX, _destinationY]); } while (openList.Count > 0 && (lastTileAddedToClosedList.x != _destinationX || lastTileAddedToClosedList.y != _destinationY)); if (openList.Count == 0) return 9999; List<PathfinderTile> finalPath = new List<PathfinderTile>(); do { finalPath.Add(lastTileAddedToClosedList); lastTileAddedToClosedList = lastTileAddedToClosedList.parent; } while (lastTileAddedToClosedList != null); finalPath.RemoveAt(finalPath.Count - 1); return finalPath.Count; }
public TargetInfo(Pos pos, int distance, Tile tile) { Debug.Assert(pos != null); this.pos = pos; this.distance = distance; this.tile = tile; }
public PathData pathTo(Pos target, Pos currentLocation, Tile[][] board, int spikeCost = 5) { PathData pathData = null; foreach (IPathfinder pathfinder in pathfinders) { PathData newPathData = pathfinder.pathTo(target, currentLocation, board, spikeCost); if (pathData == null || pathData.lostHealth > newPathData.lostHealth) { pathData = newPathData; } } return pathData; }
public PathData pathTo(Pos target, Pos currentLocation, Tile[][] board, int spikeCost = 5) { Dictionary<string, InternalTile> Navigated = new Dictionary<string, InternalTile>(); HashSet<InternalTile> Closed = new HashSet<InternalTile>(); InternalTile beginning = new InternalTile() { TilePos = currentLocation, Weight = 0 }; HashSet<InternalTile> Opened = new HashSet<InternalTile> { beginning }; Dictionary<string, int> Scores = new Dictionary<string, int> { {GetKey(beginning.TilePos.x, beginning.TilePos.y), beginning.Weight} }; Dictionary<string, float> FullScores = new Dictionary<string, float> { {GetKey(beginning.TilePos.x, beginning.TilePos.y), GetDistance(currentLocation, target)} }; while (Opened.Any()) { InternalTile lowest = Opened.First(tile => GetKey(tile.TilePos.x, tile.TilePos.y) == GetLowestCostTile(FullScores, Opened)); if (lowest.TilePos.x == target.x && lowest.TilePos.y == target.y) { return ReconstructPath(Navigated, target); } Opened.Remove(lowest); Closed.Add(lowest); foreach (Pos neighbor in GetNeighbors(lowest.TilePos, board.Length, board[0].Length)) { if (Closed.Any(tile => tile.TilePos.x == neighbor.x && tile.TilePos.y == neighbor.y)) { continue; } string neighborKey = GetKey(neighbor.x, neighbor.y); int curScore = Scores[GetKey(lowest.TilePos.x, lowest.TilePos.y)] + 1; if (!Opened.Any(tile => tile.TilePos.x == neighbor.x && tile.TilePos.y == neighbor.y)) { Opened.Add(new InternalTile { TilePos = new Pos { x = neighbor.x, y = neighbor.y } }); } else if (curScore >= (Scores.ContainsKey(neighborKey) ? Scores[neighborKey] : int.MaxValue)) { continue; } Navigated.Add(neighborKey, lowest); Scores.Add(neighborKey, curScore); FullScores.Add(neighborKey, curScore + GetDistance(neighbor, target)); } } return null; }
private string OneBestMove(GameState gameState, IPathfinder pathfinder) { string murderDirection = murderAlgo(gameState); if (!string.IsNullOrEmpty(murderDirection)) { Console.Out.WriteLine("WARWARWAR"); return murderDirection; } // If we suddenly lost a lot of life, maybe we should reconsider. if (heroLife.HasValue && heroLife.Value >= (gameState.myHero.life + 20)) { Console.WriteLine("EvenBestChoice: LOW ON LIFE! Maybe we were attacked?"); target = null; } heroLife = gameState.myHero.life; // If we suddenly moved a lot, maybe we should reconsider. if (heroPos != null && Pos.DistanceBetween(heroPos, gameState.myHero.pos) >= 2) { Console.WriteLine("EvenBestChoice: TELEPORTED! Maybe we were killed?"); target = null; } heroPos = gameState.myHero.pos; Tuple<PathData, TargetInfo> pathDataAndTarget = null; if (target != null) { Console.WriteLine("EvenBestChoice: Current target: ({0},{1}) [tile {2}]", target.pos.x, target.pos.y, target.tile); pathDataAndTarget = Tuple.Create(pathfinder.pathTo(target.pos, gameState.myHero.pos, gameState.board, SPIKE_COST), target); } else { // Seek mine if possible, otherwise seek a tavern if (gameState.myHero.life >= 35) { pathDataAndTarget = SeekMine(gameState, pathfinder); } if (pathDataAndTarget == null || pathDataAndTarget.Item1.lostHealth >= gameState.myHero.life) { pathDataAndTarget = SeekTavern(gameState, pathfinder); } } // If this is the last move, release target unless it's a tavern and we're < 90 life if (target != null && pathDataAndTarget != null && pathDataAndTarget.Item1.nextDirection != Direction.Stay && Pos.DistanceBetween(target.pos, gameState.myHero.pos) <= 1 && (target.tile != Tile.TAVERN || gameState.myHero.life >= 90)) { Console.WriteLine("EvenBestChoice: Reached destination ({0},{1}) [{2}], releasing target", target.pos.x, target.pos.y, target.tile); target = null; } string nextDirection = pathDataAndTarget != null ? pathDataAndTarget.Item1.nextDirection : null; return !String.IsNullOrEmpty(nextDirection) ? nextDirection : Direction.Stay; }
public string WhatShouldIDo(GameState state) { gState = state; Dictionary<Pos, Tile> POI = new Dictionary<Pos, Tile>(); numberOfMinePlayer1 = 0; numberOfMinePlayer2 = 0; numberOfMinePlayer3 = 0; numberOfMinePlayer4 = 0; for (int i = 0; i < state.board.Length; i++) { for (int j = 0; j < state.board[i].Length; j++) { if (state.board[i][j] != Tile.FREE && state.board[i][j] != Tile.IMPASSABLE_WOOD) { POI.Add(new Pos() { x = i, y = j }, state.board[i][j]); } if (state.board[i][j] == Tile.GOLD_MINE_1) numberOfMinePlayer1++; else if (state.board[i][j] == Tile.GOLD_MINE_2) numberOfMinePlayer2++; else if (state.board[i][j] == Tile.GOLD_MINE_3) numberOfMinePlayer3++; else if (state.board[i][j] == Tile.GOLD_MINE_4) numberOfMinePlayer4++; } } Pos bestPoiPos = new Pos(); int bestScore = Int32.MaxValue; Pathfinder pathfinder = new Pathfinder(state); foreach (var poi in POI) { int cost = WhatsMyScore(pathfinder.GetDestinationCost(poi.Key), poi.Value); if (cost < bestScore) { bestPoiPos = poi.Key; bestScore = cost; } } return pathfinder.GetNextMoveToGetToDestination(bestPoiPos.x, bestPoiPos.y); }
public PathData pathTo(Pos target, Pos currentLocation, Tile[][] board, int spikeCost = 10) { spikePrice = spikeCost; //int resultCost = 0; PathData pathData = new PathData(); int size = board.GetLength(0); int[][] pointValues = new int[size][]; for (int x = 0; x < size; x++) { pointValues[x] = new int[size]; } pointValues[currentLocation.x][currentLocation.y] = 1; SortedList<int, Pos> newMarkedPoints = new SortedList<int, Pos>(new DuplicateKeyComparer<int>()); newMarkedPoints.Add(1, currentLocation); size--; while (newMarkedPoints.Count() != 0) { Pos pos = newMarkedPoints.First().Value; newMarkedPoints.RemoveAt(0); int basecost = pointValues[pos.x][pos.y]; int x; int y; x = pos.x; y = pos.y + 1; if(x<= size && x >=0 && y <= size && y >=0) { if (target.x == x && target.y == y) { pathData.distance = tilePrice(board[x][y]) + basecost + 1; break; } if (tilePrice(board[x][y]) != -1 && pointValues[x][y] == 0) { pointValues[x][y] = tilePrice(board[x][y]) + basecost + 1; newMarkedPoints.Add(pointValues[x][y], new Pos(x, y)); } } x = pos.x + 1; y = pos.y; if(x<= size && x >=0 && y <= size && y >=0) { if (target.x == x && target.y == y) { pathData.distance = tilePrice(board[x][y]) + basecost + 1; break; } if (tilePrice(board[x][y]) != -1 && pointValues[x][y] == 0) { pointValues[x][y] = tilePrice(board[x][y]) + basecost + 1; newMarkedPoints.Add(pointValues[x][y], new Pos(x, y)); } } x = pos.x - 1; y = pos.y; if(x<= size && x >=0 && y <= size && y >=0) { if (target.x == x && target.y == y) { pathData.distance = tilePrice(board[x][y]) + basecost + 1; break; } if (tilePrice(board[x][y]) != -1 && pointValues[x][y] == 0) { pointValues[x][y] = tilePrice(board[x][y]) + basecost + 1; newMarkedPoints.Add(pointValues[x][y], new Pos(x, y)); } } x = pos.x; y = pos.y - 1; if(x<= size && x >=0 && y <= size && y >=0) { if (target.x == x && target.y == y) { pathData.distance = tilePrice(board[x][y]) + basecost + 1; break; } if (tilePrice(board[x][y]) != -1 && pointValues[x][y] == 0) { pointValues[x][y] = tilePrice(board[x][y]) + basecost + 1; newMarkedPoints.Add(pointValues[x][y], new Pos(x, y)); } } } //Console.Out.WriteLine(resultCost); //backtrace Pos currentPos = target; while (true) { //Console.Out.WriteLine(currentPos.x + "," + currentPos.y); int x, y, a=99999,b=99999,c=99999,d=99999; x = currentPos.x - 1; y = currentPos.y; if (x <= size && x >= 0 && y <= size && y >= 0) { if (currentLocation.x == x && currentLocation.y == y) { pathData.nextDirection = Direction.South; break; } a = pointValues[x][y]; } x = currentPos.x; y = currentPos.y - 1; if (x <= size && x >= 0 && y <= size && y >= 0) { if (currentLocation.x == x && currentLocation.y == y) { pathData.nextDirection = Direction.East; break; } b = pointValues[x][y]; } x = currentPos.x; y = currentPos.y + 1; if (x <= size && x >= 0 && y <= size && y >= 0) { if (currentLocation.x == x && currentLocation.y == y) { pathData.nextDirection = Direction.West; break; } c = pointValues[x][y]; } x = currentPos.x + 1; y = currentPos.y; if (x <= size && x >= 0 && y <= size && y >= 0) { if (currentLocation.x == x && currentLocation.y == y) { pathData.nextDirection = Direction.North; break; } d = pointValues[x][y]; } if (a == 0) { a = 10000; } if (b == 0) { b = 10000; } if (c == 0) { c = 10000; } if (d == 0) { d = 10000; } try { if (a <= b && a <= c && a <= d) { pointValues[currentPos.x - 1][currentPos.y] = 123456789;// taken path currentPos = new Pos(currentPos.x - 1, currentPos.y); } else if (b <= a && b <= c && b <= d) { pointValues[currentPos.x][currentPos.y - 1] = 123456789; currentPos = new Pos(currentPos.x, currentPos.y - 1); } else if (c <= b && c <= a && c <= d) { pointValues[currentPos.x][currentPos.y + 1] = 123456789; currentPos = new Pos(currentPos.x, currentPos.y + 1); } else if (d <= b && d <= c && d <= a) { pointValues[currentPos.x + 1][currentPos.y] = 123456789; currentPos = new Pos(currentPos.x + 1, currentPos.y); } } catch (Exception) { Console.Out.WriteLine("Couldn't find path and had to abandon."); return pathData; } } Console.Out.WriteLine("Move to " + pathData.nextDirection + " with cost " + pathData.distance + " to go to" + target.x + "," + target.y); pathData.lostHealth = pathData.distance; return pathData; }
public static int DistanceBetween(Pos p1, Pos p2) { Debug.Assert(p1 != null); Debug.Assert(p2 != null); int xDist = p1.x < p2.x ? p2.x - p1.x : p1.x - p2.x; int yDist = p1.y < p2.y ? p2.y - p1.y : p1.y - p2.y; return xDist + yDist; }
private PathData ReconstructPath(Dictionary<string, InternalTile> navigated, Pos current) { Stack<Pos> totalPath = new Stack<Pos>(); totalPath.Push(current); while (navigated.ContainsKey(GetKey(current.x, current.y))) { current = navigated[GetKey(current.x, current.y)].TilePos; totalPath.Push(current); } return new PathData { distance = navigated.Count, lostHealth = 0, nextDirection = GetDirectionOfPos(totalPath.Pop(), totalPath.Pop()) }; }
public float GetDistance(Pos a, Pos b) { return (float) Math.Sqrt(Math.Pow(Math.Abs(b.x - a.x), 2) + Math.Pow(Math.Abs(b.y - a.y), 2)); }
private List<Pos> GetNeighbors(Pos current, int maxX, int maxY) { List<Pos> lst = new List<Pos>(); if (current.x + 1 < maxX) lst.Add(new Pos { x = current.x + 1, y = current.y }); if (current.x - 1 >= 0) { lst.Add(new Pos { x = current.x - 1, y = current.y }); } if (current.y + 1 < maxY) { lst.Add(new Pos { x = current.x, y = current.y + 1 }); } if(current.y - 1 >= 0) lst.Add(new Pos { x = current.x, y = current.y - 1 }); return lst; }
private string GetDirectionOfPos(Pos a, Pos b) { if (a.x > b.x) { return Direction.North; } if (a.x < b.x) { return Direction.South; } if (a.y > b.y) { return Direction.West; } if(a.y < b.y) return Direction.East; return Direction.Stay; }
private Tuple<PathData, TargetInfo> SeekTiles(GameState gameState, IPathfinder pathfinder, int tileCost, params Tile[] soughtTiles) { // Scan game board and find path data to all matching tiles List<Tuple<Pos, Tile, PathData>> moves = new List<Tuple<Pos, Tile, PathData>>(); SortedSet<Tile> tiles = new SortedSet<Tile>(soughtTiles); for (int x = 0; x < gameState.board.Length; ++x) { for (int y = 0; y < gameState.board[x].Length; ++y) { Tile tile = gameState.board[x][y]; if (tiles.Contains(tile)) { Pos pos = new Pos(x, y); PathData curPathData = pathfinder.pathTo(pos, gameState.myHero.pos, gameState.board, SPIKE_COST); // Fix health if we don't have one if (curPathData.lostHealth == 0) { curPathData.lostHealth = curPathData.distance; } // Add tile cost to health cost curPathData.lostHealth += tileCost; // Add potential target. moves.Add(Tuple.Create(pos, tile, curPathData)); } } } // Seek to minimize lost health. moves.Sort((a, b) => a.Item3.lostHealth - b.Item3.lostHealth); // Find a move that will take us to the target. Tuple<PathData, TargetInfo> res = null; if (moves.Count != 0 && moves[0].Item3.distance < 1000) { res = Tuple.Create(moves[0].Item3, new TargetInfo(moves[0].Item1, moves[0].Item3.distance, moves[0].Item2)); if (res.Item1.lostHealth >= gameState.myHero.life) { Console.WriteLine("EvenBestChoice: WARNING: current choice will kill us: costs {0}, remaining life {1}", res.Item1.lostHealth, gameState.myHero.life); } } if (res != null && res.Item1 == null) { res = null; } return res; }
static void Main(string[] args) { AStar lol = new AStar(); float dist = lol.GetDistance(new Pos { x=4, y=4 }, new Pos { x = 0, y = 0 }); Console.WriteLine(dist); Tile[][] tiles = { new [] { Tile.FREE, Tile.FREE, Tile.FREE, Tile.FREE, Tile.FREE }, new [] { Tile.FREE, Tile.FREE, Tile.FREE, Tile.FREE, Tile.FREE }, new [] { Tile.FREE, Tile.FREE, Tile.FREE, Tile.FREE, Tile.FREE }, new [] { Tile.FREE, Tile.FREE, Tile.FREE, Tile.FREE, Tile.FREE }, new [] { Tile.FREE, Tile.FREE, Tile.FREE, Tile.FREE, Tile.FREE } }; foreach (Tile[] row in tiles) { foreach (Tile tile in row) { Console.Write(tile); } Console.WriteLine(); } PathData result = lol.pathTo(new Pos { x = 0, y = 0 }, new Pos { x = 4, y = 4 }, tiles); Console.WriteLine("Dist:{0} - Direction: {1}", result.distance, result.nextDirection); result = lol.pathTo(new Pos { x = 4, y = 0 }, new Pos { x = 4, y = 4 }, tiles); Console.WriteLine("Dist:{0} - Direction: {1}", result.distance, result.nextDirection); result = lol.pathTo(new Pos { x = 0, y = 4 }, new Pos { x = 4, y = 4 }, tiles); Console.WriteLine("Dist:{0} - Direction: {1}", result.distance, result.nextDirection); result = lol.pathTo(new Pos { x = 4, y = 4 }, new Pos { x = 4, y = 0 }, tiles); Console.WriteLine("Dist:{0} - Direction: {1}", result.distance, result.nextDirection); result = lol.pathTo(new Pos { x = 4, y = 4 }, new Pos { x = 0, y = 4 }, tiles); Console.WriteLine("Dist:{0} - Direction: {1}", result.distance, result.nextDirection); result = lol.pathTo(new Pos { x = 4, y = 4 }, new Pos { x = 0, y = 0 }, tiles); Console.WriteLine("Dist:{0} - Direction: {1}", result.distance, result.nextDirection); Console.WriteLine("====================="); Pos cur = new Pos() {x = 0, y=0}; Pos target = new Pos() {x = 4, y=4}; int nbTours = 0; while (cur.x != target.x || cur.y != target.y) { result = lol.pathTo(target, cur, tiles); switch(result.nextDirection) { case Direction.East: cur.y += 1; break; case Direction.West: cur.y -= 1; break; case Direction.North: cur.x -= 1; break; case Direction.South: cur.x += 1; break; } Console.WriteLine("Dist:{0} - Direction: {1}", result.distance, result.nextDirection); Console.WriteLine("CurPos = {0}-{1}", cur.x, cur.y); if (nbTours++ > 10) { break; } } Console.ReadKey(); }