/// <summary> /// Return build moves around the unit of the selected type and in a specified maximum distance /// </summary> /// <param name="unit">The unit that will build</param> /// <param name="board">The board to build on</param> /// <param name="type">The type of unit to build</param> /// <param name="distance">The maximum distance to build in</param> /// <returns>A list of movement moves that unit can do, of units of type 'type' and in distance 'distance'</returns> public static List <Move> BuildAroundMove(this Unit unit, Tile[,] board, UnitType type, int distance) { List <Move> moves = new List <Move>(); //Get the 9 tiles around this building int xStart = Math.Max(0, unit.px / Tile.TILE_WIDTH - distance); int xEnd = Math.Min(Game.TILES_WIDTH - 1, unit.px / Tile.TILE_WIDTH + distance); int yStart = Math.Max(0, unit.py / Tile.TILE_HEIGHT - distance); int yEnd = Math.Min(Game.TILES_HEIGHT - 1, unit.py / Tile.TILE_HEIGHT + distance); for (int x = xStart; x <= xEnd; x++) { for (int y = yStart; y <= yEnd; y++) { if (type.CanPlaceOn(board, x, y)) { moves.Add(new BuildMove(unit, x, y, type)); } } } return(moves); }
/// <summary> /// Get a path to the nearest tile satisfying a TileLookupConstraint. The algorithm used is flood fill, meaning the optimal path is /// Gurrenteed. /// </summary> /// <param name="traveler">The unit type that attempts to travel</param> /// <param name="board">The board to search for a path in</param> /// <param name="xStart">The beggining position of the path in tiles</param> /// <param name="yStart">The beggining position of the path in tiles</param> /// <param name="constraint">The TileLookupConstraint object that decides if a tile is good</param> /// <returns>A List of ALocations starting at (xStart,yStart) and ending at the nearest tile satisfying the constraint</returns> public static List <ALocation> PathToNearestTile(UnitType traveler, Tile[,] board, int xStart, int yStart, TileLookupConstraint constraint) { ALocation start = new ALocation(xStart, yStart); //Current positions to check Stack <ALocation> current = new Stack <ALocation>(); //Next positions to check Stack <ALocation> next = new Stack <ALocation>(); //Start by checking the start current.Push(start); //Iteration i checks all the tiles in distance 1 from the beggining. Repeat until the maximum path length is reached. for (int i = 0; i < MAX_PATH_LENGTH; i++) { //Check every tile in the current list foreach (ALocation test in current) { Console.WriteLine("Checking " + test); //Check if the tile satisfies the constraint if (constraint.Check(test.Tile(board))) { //If it does, trace the path using the parent property of each ALocation and return it. Console.WriteLine("Found tile satisfying " + constraint + " in " + test.x + ", " + test.y); List <ALocation> res = new List <ALocation>(); ALocation curr = test; while (curr != null) { res.Add(curr); curr = curr.parent; } //Clear the flags foreach (Tile t in board) { t.flag = false; } //Return the path res.Reverse(); res.RemoveAt(0); return(res); } //If the traveler cannot walk on that tile, stop checking it, it cannot be path of a path. if (!traveler.CanPlaceOn(board, test.x, test.y) && test != start) { continue; } //This tile is not final but may be in the shortest path. Check all tiles adjecent to it. foreach (ALocation l in GetAdjacentSquares(traveler, board, test.x, test.y)) { //Only check tiles that weren't checked yet. if (!board[l.x, l.y].flag) { l.parent = test; next.Push(l); //Mark this tile as checked. board[l.x, l.y].flag = true; } } } //Finished checking current tiles, switch on to the next batch. current = next; next = new Stack <ALocation>(); } //If the maximum tile length is reached and no path was found, stop looking, unflag all tiles and return null. foreach (Tile t in board) { t.flag = false; } return(null); }