private void DrawGrid() { //draws the map grid int sz = level.GridSize; for (int x = 0; x < sz; x++) { for (int y = 0; y < sz; y++) { Coord2 pos = new Coord2((x * 15), (y * 15)); if (level.tiles[x, y] == 0) { if (level.dijkstra.inPath[x, y]) { spriteBatch.Draw(tile1Texture, pos, Color.Red); } else { spriteBatch.Draw(tile1Texture, pos, Color.White); } } else { spriteBatch.Draw(tile2Texture, pos, Color.White); } } } }
public void Build(Coord2 startPos, Coord2 targetPos) { buffer2 = buffer1; // Copy Buffers // Increment player's value sourceValue = sourceValue + 1; Coord2 currentLoc; // Update all locations for (int x = 0; x < gridSize; x++) { for (int y = 0; y < gridSize; y++) { currentLoc = new Coord2(x, y); if (map.ValidPosition(currentLoc)) // Ignore blocked spaces { ProcessLocation(currentLoc, targetPos); } } } // Update data in player's location buffer1.data[targetPos.X, targetPos.Y] = sourceValue; }
Coord2 SetNextPos(int movementDirection, Coord2 pos) { Coord2 temp = pos; switch (movementDirection) { case 1: temp.X -= 1; break; case 2: temp.X += 1; break; case 3: temp.Y -= 1; break; case 4: temp.Y += 1; break; default: break; } return(temp); }
public Node() { closed = false; cost = INITIAL_COST; inPath = false; link = new Coord2(-1, -1); }
//constructor: takes an initial position as arguments public Player(int x, int y) { gridPosition = new Coord2(x, y); targetPosition = new Coord2(x, y); screenPosition = new Coord2(x, y); timerMs = moveTime; }
//constructor: requires initial position public AiBotBase(int x, int y) { gridPosition = new Coord2(x, y); targetPosition = new Coord2(x, y); screenPosition = new Coord2(x, y); timerMs = moveTime; }
/// <summary> /// A background worker, used to run testing on a background thread. /// </summary> protected override void OnDoWork(DoWorkEventArgs e) { base.OnDoWork(e); for (int i = 0; i < config.NumberOfTestRuns; i++) { if (!CheckCancellation()) { // Calculate positions for this test run Coord2 targetPos = new Coord2(0, 0); Coord2 botPos = new Coord2(0, 0); // Assign a random bot position do { botPos.X = rand.Next(0, LevelHandler.Level.Map.GridSize); botPos.Y = rand.Next(0, LevelHandler.Level.Map.GridSize); } while (!LevelHandler.Level.Map.ValidPosition(botPos)); // Assign a target position the correct distance from the bot do { } while (!LevelHandler.Level.Map.ValidPosition(targetPos)); // Run test on the loaded level results.Add(LevelHandler.RunTest(config.Algorithm, new Coord2(0, 0), new Coord2(0, 0))); // Report the thread's current progress ReportProgress((i / config.NumberOfTestRuns) * 100); } else break; } }
protected virtual void RecalculateCosts(Coord2[] neighbours, Coord2 pos) { for (int i = 0; i < 8; i++) { if (map.ValidPosition(neighbours[i]) && nodes.Get(neighbours[i].X, neighbours[i].Y).closed == false) { float costToAdd = 0.0f; if (neighbours[i].X != 0 && neighbours[i].Y != 0) { costToAdd = D_COST; } else { costToAdd = HV_COST; } float newCost = nodes.Get(pos.X, pos.Y).cost + costToAdd; if (newCost < nodes.Get(neighbours[i].X, neighbours[i].Y).cost) { nodes.Get(neighbours[i].X, neighbours[i].Y).cost = newCost; nodes.Get(neighbours[i].X, neighbours[i].Y).link = pos; } } } }
//constructor: requires initial position public AiBotBase(int x, int y) { gridPosition = new Coord2(x, y); targetPosition = new Coord2(x, y); screenPosition = new Coord2(x, y); timerMs = 1; }
protected override void ChooseNextGridLocation(Level level, Player plr) { double currentDistance = GetDistance(plr.GridPosition, GridPosition); Coord2 testPosition = new Coord2(GridPosition.X, GridPosition.Y); for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (i == 0 || j == 0) { testPosition = new Coord2(GridPosition.X + i, GridPosition.Y + j); if (currentDistance > GetDistance(plr.GridPosition, testPosition)) { currentDistance = GetDistance(plr.GridPosition, testPosition); SetNextGridPosition(testPosition, level); currentDirection = testPosition - GridPosition; } } } } if (!level.ValidPosition(GridPosition + currentDirection)) { currentDirection = new Coord2(currentDirection.Y, currentDirection.X); SetNextGridPosition(GridPosition + currentDirection, level); } }
private void HandlePlayerMovement() { Coord2 currentPos = new Coord2(); currentPos = player.GridPosition; if (InputHandler.IsKeyDown(Keys.Up)) { currentPos.Y -= 1; player.SetNextLocation(currentPos, map); } else if (InputHandler.IsKeyDown(Keys.Down)) { currentPos.Y += 1; player.SetNextLocation(currentPos, map); } else if (InputHandler.IsKeyDown(Keys.Left)) { currentPos.X -= 1; player.SetNextLocation(currentPos, map); } else if (InputHandler.IsKeyDown(Keys.Right)) { currentPos.X += 1; player.SetNextLocation(currentPos, map); } }
//sets target position: the next grid location to move to //need to validate this position - so must be within 1 cell of current position(in x and y directions) //and must also be valid on the map: greater than 0, less than mapsize, and not a wall public bool SetNextGridPosition(Coord2 pos, Level level) { if (pos.X < (gridPosition.X - 1)) { return(false); } if (pos.X > (gridPosition.X + 1)) { return(false); } if (pos.Y < (gridPosition.Y - 1)) { return(false); } if (pos.Y > (gridPosition.Y + 1)) { return(false); } if (!level.ValidPosition(pos)) { return(false); } targetPosition = pos; return(true); }
public void UpdateScent() { for (int x = 0; x < 8; x++) { Coord2 neighbourPos = new Coord2(currentNode.X + PreCalcNeighbours[x].X, currentNode.Y + PreCalcNeighbours[x].Y); } }
/// <summary> /// Sets the render color of the given tile. Useful for visualization of a pathfinding algorithm. /// </summary> /// <param name="pos">Position of the tile to set.</param> /// <param name="color">Color to draw the tile as.</param> public void SetRenderColor(Coord2 pos, Color color) { if (ValidPosition(pos)) { tiles[pos.X, pos.Y].SetRenderColor(color); } }
public override void Update(GameTime gameTime) { level.Update(gameTime); if (Game.IsActive) { // Check if user wishes to return to menu if (InputHandler.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape)) { if (MessageBox.Show("Return to the menu?", "Return to Menu", MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Question) == DialogResult.Yes) { Main.SetState(typeof(ProfilerMenu)); SetBotPosition(new Coord2(0, 0)); SetPlayerPosition(new Coord2(1, 0)); } } // Check for mouse clicks if (InputHandler.IsMouseInWindow(GraphicsDevice.Viewport.Bounds)) { // Check for mouse clicks if (InputHandler.IsMouseButtonPressed(MouseButton.LeftButton) || InputHandler.IsMouseButtonPressed(MouseButton.RightButton)) { ClearAll(); Coord2 mp = new Coord2(InputHandler.MousePosition().X / level.Map.TileSize, InputHandler.MousePosition().Y / level.Map.TileSize); if (level.Map.ValidPosition(mp)) { if (InputHandler.IsMouseButtonPressed(MouseButton.LeftButton)) { if (level.Bot.GridPosition != mp) { level.SetPlayerPosition(mp); } } else { if (level.Player.GridPosition != mp) { level.SetBotPosition(mp); } } } } // Update mouse position mousePos = new Point(InputHandler.MousePosition().X / level.Map.TileSize, InputHandler.MousePosition().Y / level.Map.TileSize); } // Check for hide/show instructions if (InputHandler.IsKeyPressed(Microsoft.Xna.Framework.Input.Keys.Tab)) { showInstructions = !showInstructions; } } base.Update(gameTime); }
public Node() { cost = INITIAL_COST; inPath = false; closed = false; parent = null; position = new Coord2(-1, -1); }
//validates a grid position (passed as a 2d vector): returns false if position is blocked, or if x or y //positions are greater than grid size, or less than 0 public bool ValidPosition(Coord2 pos) { if (pos.X < 0) return false; if (pos.X >= gridSize) return false; if (pos.Y < 0) return false; if (pos.Y >= gridSize) return false; return (tiles[pos.X,pos.Y] == 0); }
/// <summary> /// Finds the manhattan distance between two locations. /// </summary> protected int manhattanDist(Coord2 playerPos, Coord2 currentPos) { Coord2 dist = playerPos - currentPos; if (dist.X < 0) dist.X *= -1; if (dist.Y < 0) dist.Y *= -1; return dist.X + dist.Y; }
public Entity(Texture2D texture, int x, int y, int moveTime) { gridPosition = new Coord2(x, y); targetPosition = new Coord2(x, y); screenPosition = new Coord2(x, y); this.texture = texture; this.moveTime = moveTime; timerMs = moveTime; }
public void SetPosition(Coord2 newPos, Level level) { if (level.ValidPosition(newPos)) { gridPosition = newPos; targetPosition = newPos; screenPosition = newPos; } }
public void Update(Level level, Player plr, AiBotBase bot) { if (running == true) { watch.Start(); } sourceValue++; for (int x = 0; x < 40; x++) { for (int y = 0; y < 40; y++) { buffer1[x, y] = buffer2[x, y]; } } //Array.Copy(buffer1, buffer2, buffer2.Length); buffer1[plr.GridPosition.X, plr.GridPosition.Y] = sourceValue; for (int xx = 0; xx < 40; xx++) { for (int yy = 0; yy < 40; yy++) { if (level.ValidPosition(new Coord2(xx, yy))) { int highestScent = 0; Coord2 pos = new Coord2(xx, yy); for (int i = 0; i < 8; i++) { Coord2 test = pos + PreCalcNeighbours[i]; if (test.X >= 0 && test.X < gridSize && test.Y >= 0 && test.Y < gridSize) { int temp = buffer1[pos.X + PreCalcNeighbours[i].X, pos.Y + PreCalcNeighbours[i].Y]; if (temp > highestScent) { highestScent = temp; } } buffer2[pos.X, pos.Y] = highestScent - 1; } } } } if ((buffer1[bot.GridPosition.X, bot.GridPosition.Y] <= 0)) { running = true; } else if ((buffer1[bot.GridPosition.X, bot.GridPosition.Y] >= 1)) { running = false; if (running == false) { watch.Stop(); scentTimer = watch.ElapsedMilliseconds.ToString(); //Console.WriteLine("Scent time = " + scentTimer + " Milliseconds"); watch.Reset(); } } }
//sets next position for player to move to: called by keyboard processing functions. validates new position against level, //so can't move to blocked position, or position off grid public void SetNextLocation(Coord2 newLoc, Level level) { if (timerMs > 0) return; if (level.ValidPosition(newLoc)) { targetPosition = newLoc; timerMs = moveTime; } }
/// <summary> /// A background worker, used to run testing on a background thread. /// </summary> protected override void OnDoWork(DoWorkEventArgs e) { base.OnDoWork(e); // Assign a random start position Coord2 startPos; do { startPos.X = rand.Next(0, LevelHandler.Level.Map.GridSize); startPos.Y = rand.Next(0, LevelHandler.Level.Map.GridSize); } while (!LevelHandler.Level.Map.ValidPosition(startPos)); // Find the possible spawn points List <Coord2> possibleTargets = new List <Coord2>(); Coord2 topLeft = new Coord2(startPos.X - config.PathDistance, startPos.Y - config.PathDistance); for (int x = 0; x < (config.PathDistance * 2); x++) { possibleTargets.Add(new Coord2(topLeft.X + x, topLeft.Y)); possibleTargets.Add(new Coord2(topLeft.X + x, topLeft.Y + (config.PathDistance * 2))); } for (int y = 0; y < (config.PathDistance * 2); y++) { possibleTargets.Add(new Coord2(topLeft.X, topLeft.Y + y)); possibleTargets.Add(new Coord2(topLeft.X + (config.PathDistance * 2), topLeft.Y + y)); } for (int i = 0; i < config.NumberOfTestRuns; i++) { if (!CheckCancellation()) { // Find a random position Coord2 targetPos = possibleTargets[rand.Next(0, possibleTargets.Count)]; // Run test on the loaded level TestResult result = new TestResult(); do { result = LevelHandler.RunTest(config.Algorithm, startPos, possibleTargets); } while (result.Failed == true); // If the result reported a failure, run it again // Add the result results.Add(result); // Report the thread's current progress ReportProgress((int)(((float)100 / (float)config.NumberOfTestRuns) * (i + 1)), new TestProgress(i + 1, config.NumberOfTestRuns, new TimeSpan(results.AverageTicksForPath))); } else { results.Cancel(); break; } } }
//sets target position: the next grid location to move to //need to validate this position - so must be within 1 cell of current position(in x and y directions) //and must also be valid on the map: greater than 0, less than mapsize, and not a wall public bool SetNextGridPosition(Coord2 pos, Level level) { if (pos.X < (gridPosition.X - 1)) return false; if (pos.X > (gridPosition.X + 1)) return false; if (pos.Y < (gridPosition.Y - 1)) return false; if (pos.Y > (gridPosition.Y + 1)) return false; if (!level.ValidPosition(pos)) return false; targetPosition = pos; return true; }
/// <summary> /// Builds/Updates a scent map given a starting position and target position. If test mode is active, finds an entire /// path. Otherwise, performs a single update. /// <param name="startPos">Starting position.</param> /// <param name="targetPos">The current target positon.</param> /// <param name="testMode">Whether or not to find an entire path, or update the map once.</param> public override void Build(Coord2 startPos, Coord2 targetPos, bool testMode = false) { if (!path.Contains(targetPos)) { buffer2.Copy(buffer1); // Copy Buffers // Increment player's value sourceValue = sourceValue + 1; // Update data in player's location buffer1.data[targetPos.X, targetPos.Y] = sourceValue; Coord2 currentLoc; // Update all locations for (int x = 0; x < gridSize; x++) { for (int y = 0; y < gridSize; y++) { currentLoc = new Coord2(x, y); if (map.ValidPosition(currentLoc)) // Ignore blocked spaces { ProcessLocation(currentLoc, targetPos); } } } // Update visuals UpdateVisualization(); // Only recursive if not live - that is, is being used for non-visual profiling if (testMode) { // Find best move position List <Coord2> neighbours = GetNeighbours(startPos); Coord2 highest = neighbours[0]; for (int i = 0; i < neighbours.Count; i++) { if (map.ValidPosition(neighbours[i])) { if (buffer2.data[neighbours[i].X, neighbours[i].Y] > buffer2.data[highest.X, highest.Y]) { highest = neighbours[i]; } } } // Add lowest to the path, if scent has reached this point path.Add(highest); // Call recursively Build(highest, targetPos, testMode); } } }
/// <summary> /// Returns whether or not the given position is blocked. Does not ensure given positon is within the map. Returns false if position is /// out of map bounds. /// </summary> /// <param name="pos">Position to check for block</param> /// <returns></returns> public bool IsBlocked(Coord2 pos) { if (IsWithinMap(pos)) { return(tiles[pos.X, pos.Y].IsBlocked); } else { return(false); } }
/// <summary> /// A background worker, used to run testing on a background thread. /// </summary> protected override void OnDoWork(DoWorkEventArgs e) { base.OnDoWork(e); // Assign a random start position Coord2 startPos; do { startPos.X = rand.Next(0, LevelHandler.Level.Map.GridSize); startPos.Y = rand.Next(0, LevelHandler.Level.Map.GridSize); } while (!LevelHandler.Level.Map.ValidPosition(startPos)); // Find the possible spawn points List<Coord2> possibleTargets = new List<Coord2>(); Coord2 topLeft = new Coord2(startPos.X - config.PathDistance, startPos.Y - config.PathDistance); for(int x = 0; x < (config.PathDistance*2); x++) { possibleTargets.Add(new Coord2(topLeft.X + x, topLeft.Y)); possibleTargets.Add(new Coord2(topLeft.X + x, topLeft.Y + (config.PathDistance*2))); } for(int y = 0; y < (config.PathDistance*2); y++) { possibleTargets.Add(new Coord2(topLeft.X, topLeft.Y + y)); possibleTargets.Add(new Coord2(topLeft.X + (config.PathDistance*2), topLeft.Y + y)); } for (int i = 0; i < config.NumberOfTestRuns; i++) { if (!CheckCancellation()) { // Find a random position Coord2 targetPos = possibleTargets[rand.Next(0, possibleTargets.Count)]; // Run test on the loaded level TestResult result = new TestResult(); do { result = LevelHandler.RunTest(config.Algorithm, startPos, possibleTargets); } while (result.Failed == true); // If the result reported a failure, run it again // Add the result results.Add(result); // Report the thread's current progress ReportProgress((int)(((float)100 / (float)config.NumberOfTestRuns) * (i + 1)), new TestProgress(i + 1, config.NumberOfTestRuns, new TimeSpan(results.AverageTicksForPath))); } else { results.Cancel(); break; } } }
protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) { this.Exit(); } //player movement: read keyboard KeyboardState keyState = Keyboard.GetState(); Coord2 currentPos = new Coord2(); currentPos = player.GridPosition; if (keyState.IsKeyDown(Keys.Up)) { currentPos.Y -= 1; player.SetNextLocation(currentPos, level); level.dijkstra.Build(level, bot, player); } else if (keyState.IsKeyDown(Keys.Down)) { currentPos.Y += 1; player.SetNextLocation(currentPos, level); level.dijkstra.Build(level, bot, player); } else if (keyState.IsKeyDown(Keys.Left)) { currentPos.X -= 1; player.SetNextLocation(currentPos, level); level.dijkstra.Build(level, bot, player); } else if (keyState.IsKeyDown(Keys.Right)) { currentPos.X += 1; player.SetNextLocation(currentPos, level); level.dijkstra.Build(level, bot, player); } // INITIATE THE DIJKSTRA ALGORITHM PATHFINDING else if (keyState.IsKeyDown(Keys.D)) { level.dijkstra.Build(level, bot, player); } // INITIATE ASTAR ALGORITH PATHFINDING else if (keyState.IsKeyDown(Keys.A)) { level.astar.Build(level, bot, player); } //update bot and player bot.Update(gameTime, level, player); player.Update(gameTime, level); base.Update(gameTime); }
public override bool Equals(Object obj) { //Check for null and compare run-time types. if (obj == null || GetType() != obj.GetType()) { return(false); } Coord2 p = (Coord2)obj; return((X == p.X) && (Y == p.Y)); }
/// <summary> /// Retrieve the node at the given location, if it is valid. /// </summary> public Node Get(Coord2 loc) { if (IsValid(loc)) { return(nodes[loc.X, loc.Y]); } else { Console.WriteLine("Error, tried to access invalid node in node collection!\n"); return(null); } }
//Handles animation moving from current grid position (gridLocation) to next grid position (targetLocation) //When target location is reached, sets grid location to targetLocation, and then calls ChooseNextGridLocation //and resets animation timer public void Update(GameTime gameTime, Level level, Player plr) { timerMs -= gameTime.ElapsedGameTime.Milliseconds; if (timerMs <= 0) { gridPosition = targetPosition; ChooseNextGridLocation(level, plr); timerMs = moveTime; } //calculate screen position screenPosition = (gridPosition * 15) + ((((targetPosition * 15) - (gridPosition * 15)) * (moveTime - timerMs)) / moveTime); }
//sets next position for player to move to: called by keyboard processing functions. validates new position against level, //so can't move to blocked position, or position off grid public void SetNextLocation(Coord2 newLoc, Map level) { if (timerMs > 0) { return; } if (level.ValidPosition(newLoc)) { targetPosition = newLoc; timerMs = moveTime; } }
/// <summary> /// Draws the grid and any neccesary pathfinding visual representation. /// </summary> /// <param name="sb">The spritebatch to use.</param> public void DrawGrid(SpriteBatch sb) { int sz = map.GridSize; // Draw grid the same way for both dijkstra and astar if (map.PathfindingAlgorithm == PathfinderAlgorithm.Dijkstra || map.PathfindingAlgorithm == PathfinderAlgorithm.AStar) { for (int x = 0; x < sz; x++) { for (int y = 0; y < sz; y++) { Coord2 pos = new Coord2((x * 15), (y * 15)); if (map.tiles[x, y] == 0) { if (map.pathfinder.IsInPath(x, y) == true) sb.Draw(map.Tile1Texture, pos, Color.Red); else { if (map.pathfinder.GetValue(x, y) == 0) sb.Draw(map.Tile1Texture, pos, Color.White); else sb.Draw(map.Tile1Texture, pos, Color.Blue); } } else sb.Draw(map.Tile2Texture, pos, Color.White); } } } else if (map.PathfindingAlgorithm == PathfinderAlgorithm.ScentMap) { int highestValue = map.pathfinder.HighestValue(); for (int x = 0; x < sz; x++) { for (int y = 0; y < sz; y++) { Coord2 pos = new Coord2((x * 15), (y * 15)); if (map.tiles[x, y] == 0) { if (map.pathfinder.IsInPath(x, y) == true) sb.Draw(map.Tile1Texture, pos, Color.Red); else sb.Draw(map.Tile1Texture, pos, Color.Lerp(Color.White, Color.Red, map.pathfinder.GetValue(x, y)/highestValue)); } else sb.Draw(map.Tile2Texture, pos, Color.White); } } } }
/// <summary> /// Builds/Updates a scent map given a starting position and target position. If test mode is active, finds an entire /// path. Otherwise, performs a single update. /// <param name="startPos">Starting position.</param> /// <param name="targetPos">The current target positon.</param> /// <param name="testMode">Whether or not to find an entire path, or update the map once.</param> public override void Build(Coord2 startPos, Coord2 targetPos, bool testMode = false) { if (!path.Contains(targetPos)) { buffer2.Copy(buffer1); // Copy Buffers // Increment player's value sourceValue = sourceValue + 1; // Update data in player's location buffer1.data[targetPos.X, targetPos.Y] = sourceValue; Coord2 currentLoc; // Update all locations for (int x = 0; x < gridSize; x++) { for (int y = 0; y < gridSize; y++) { currentLoc = new Coord2(x, y); if (map.ValidPosition(currentLoc)) // Ignore blocked spaces ProcessLocation(currentLoc, targetPos); } } // Update visuals UpdateVisualization(); // Only recursive if not live - that is, is being used for non-visual profiling if (testMode) { // Find best move position List<Coord2> neighbours = GetNeighbours(startPos); Coord2 highest = neighbours[0]; for (int i = 0; i < neighbours.Count; i++) { if (map.ValidPosition(neighbours[i])) { if (buffer2.data[neighbours[i].X, neighbours[i].Y] > buffer2.data[highest.X, highest.Y]) highest = neighbours[i]; } } // Add lowest to the path, if scent has reached this point path.Add(highest); // Call recursively Build(highest, targetPos, testMode); } } }
private Coord2[] GetNeighbours() { Coord2[] neighbours = new Coord2[8]; neighbours[0] = new Coord2(GridPosition.X + 1, GridPosition.Y + 1); neighbours[1] = new Coord2(GridPosition.X - 1, GridPosition.Y - 1); neighbours[2] = new Coord2(GridPosition.X - 1, GridPosition.Y + 1); neighbours[3] = new Coord2(GridPosition.X + 1, GridPosition.Y - 1); neighbours[4] = new Coord2(GridPosition.X, GridPosition.Y + 1); neighbours[5] = new Coord2(GridPosition.X + 1, GridPosition.Y); neighbours[6] = new Coord2(GridPosition.X - 1, GridPosition.Y); neighbours[7] = new Coord2(GridPosition.X, GridPosition.Y - 1); return(neighbours); }
private Coord2[] GetNeighbours() { Coord2[] neighbours = new Coord2[8]; neighbours[0] = new Coord2(GridPosition.X + 1, GridPosition.Y + 1); neighbours[1] = new Coord2(GridPosition.X - 1, GridPosition.Y - 1); neighbours[2] = new Coord2(GridPosition.X - 1, GridPosition.Y + 1); neighbours[3] = new Coord2(GridPosition.X + 1, GridPosition.Y - 1); neighbours[4] = new Coord2(GridPosition.X, GridPosition.Y + 1); neighbours[5] = new Coord2(GridPosition.X + 1, GridPosition.Y); neighbours[6] = new Coord2(GridPosition.X - 1, GridPosition.Y); neighbours[7] = new Coord2(GridPosition.X, GridPosition.Y - 1); return neighbours; }
/// <summary> /// Finds the manhattan distance between two locations. /// </summary> protected int manhattanDist(Coord2 playerPos, Coord2 currentPos) { Coord2 dist = playerPos - currentPos; if (dist.X < 0) { dist.X *= -1; } if (dist.Y < 0) { dist.Y *= -1; } return(dist.X + dist.Y); }
protected Coord2[] GetNeighbours(Coord2 location) { Coord2[] neighbours = new Coord2[8]; neighbours[0] = new Coord2(location.X + 1, location.Y + 1); neighbours[1] = new Coord2(location.X - 1, location.Y - 1); neighbours[2] = new Coord2(location.X - 1, location.Y + 1); neighbours[3] = new Coord2(location.X + 1, location.Y - 1); neighbours[4] = new Coord2(location.X, location.Y + 1); neighbours[5] = new Coord2(location.X + 1, location.Y); neighbours[6] = new Coord2(location.X - 1, location.Y); neighbours[7] = new Coord2(location.X, location.Y - 1); return(neighbours); }
protected override void ChooseNextGridLocation(Map level, Player plr) { try { if (level.pathfinder.GetAlgorithm() != PathfinderAlgorithm.ScentMap) { throw new Exception("Wrong bot used for pathfinding algorithm."); } // Get a copy of the scent map ScentMap map = (level.pathfinder as ScentMap); // Get neighbouring coordinates Coord2[] neighbours = GetNeighbours(); Coord2 highest = new Coord2(0, 0); bool validFound = false; for (int i = 0; i < neighbours.Length; i++) // Ensures a valid position is initially selected { if (level.ValidPosition(neighbours[i])) { highest = neighbours[i]; validFound = true; break; } } if (validFound) // Only update if at least one neighbouring positon is in fact valid on the map { // Find the highest neighbouring coorindate for (int i = 0; i < neighbours.Length; i++) { if (level.ValidPosition(neighbours[i])) { if (map.Scents.data[neighbours[i].X, neighbours[i].Y] > map.Scents.data[highest.X, highest.Y]) { highest = neighbours[i]; } } } SetNextGridPosition(highest, level); } } catch (Exception e) { Console.WriteLine("Bot Exception: " + e.Message); } }
/// <summary> /// Processes an individual location and updates it's scent value. /// </summary> /// <param name="location">The location to update.</param> /// <param name="targetPos">The current position of the target.</param> private void ProcessLocation(Coord2 location, Coord2 targetPos) { List <Coord2> neighbours = GetNeighbours(location); for (int i = 0; i < neighbours.Count; i++) { if (map.ValidPosition(neighbours[i])) { if (buffer2.data[neighbours[i].X, neighbours[i].Y] > buffer1.data[location.X, location.Y]) { buffer1.data[location.X, location.Y] = buffer2.data[neighbours[i].X, neighbours[i].Y] - 1; } } } }
//Handles animation moving from current grid position (gridLocation) to next grid position (targetLocation) public void Update(GameTime gameTime, Level level) { if (timerMs > 0) { timerMs -= gameTime.ElapsedGameTime.Milliseconds; if (timerMs <= 0) { timerMs = 0; gridPosition = targetPosition; } } //calculate screen position screenPosition = (gridPosition * 15) + ((((targetPosition * 15) - (gridPosition * 15)) * (moveTime - timerMs)) / moveTime); }
private void ProcessLocation(Coord2 location, Coord2 targetPos) { Coord2[] neighbours = GetNeighbours(location); for (int i = 0; i < neighbours.Length; i++) { if (map.ValidPosition(neighbours[i]) && targetPos != neighbours[i]) { if (buffer2.data[neighbours[i].X, neighbours[i].Y] > buffer1.data[location.X, location.Y]) { buffer1.data[location.X, location.Y] = buffer2.data[neighbours[i].X, neighbours[i].Y] - 1; } } } }
protected override void ChooseNextGridLocation(Map level, Player plr) { try { if (level.pathfinder.GetAlgorithm() != PathfinderAlgorithm.ScentMap) throw new Exception("Wrong bot used for pathfinding algorithm."); // Get a copy of the scent map ScentMap map = (level.pathfinder as ScentMap); // Get neighbouring coordinates Coord2[] neighbours = GetNeighbours(); Coord2 highest = new Coord2(0, 0); bool validFound = false; for (int i = 0; i < neighbours.Length; i++) // Ensures a valid position is initially selected { if (level.ValidPosition(neighbours[i])) { highest = neighbours[i]; validFound = true; break; } } if (validFound) // Only update if at least one neighbouring positon is in fact valid on the map { // Find the highest neighbouring coorindate for (int i = 0; i < neighbours.Length; i++) { if (level.ValidPosition(neighbours[i])) { if (map.Scents.data[neighbours[i].X, neighbours[i].Y] > map.Scents.data[highest.X, highest.Y]) highest = neighbours[i]; } } SetNextGridPosition(highest, level); } } catch (Exception e) { Console.WriteLine("Bot Exception: " + e.Message); } }
public Dijkstra(Level level) { closed = new bool[level.GridSize, level.GridSize]; cost = new float[level.GridSize, level.GridSize]; link = new Coord2[level.GridSize, level.GridSize]; inPath = new bool[level.GridSize, level.GridSize]; path = new List<Coord2>(); for (int i = 0; i < level.GridSize; i++) { for (int j = 0; j < level.GridSize; j++) { cost[i, j] = int.MaxValue-1; closed[i, j] = false; link[i, j] = new Coord2(-1, -1); inPath[i, j] = false; } } }
public static TestResult RunTest(PathfinderAlgorithm algorithm, Coord2 startPos, Coord2 targetPos) { // Set the pathfinding algorithm Level.SetPathfindingAlgorithm(algorithm); // Get Start Time DateTime startTime = DateTime.Now; // Find Path Level.Map.pathfinder.Build(startPos, targetPos); // Calculate time taken DateTime finishTime = DateTime.Now; TimeSpan timeTaken = finishTime - startTime; // Return results return new TestResult(timeTaken.Ticks, Level.Map.pathfinder.GetPath().Count); }
// Create a text file by flooding Dijkstra's for every cell. public void Calculate(Level level) { int firstTile = level.tiles[0][0]; level.tiles[0][0] = 1; Dijkstra dijkstra = new Dijkstra(level); AiBotSimple bot = new AiBotSimple(0,0); Player player = new Player(level.GridSizeX-1, level.GridSizeY-1); Coord2 current = new Coord2(-1, -1); dijkstra.Build(level, bot, player); StreamWriter writer = new StreamWriter("precompute.txt", true); for (int x = 0; x < level.GridSize; x++) { for (int y = 0; y < level.GridSize; y++) { for (int i = 0; i < level.GridSize; i++) { for (int j = 0; j < level.GridSize; j++) { if (new Coord2(i, j) == player.GridPosition) writer.Write(0); else if (level.ValidPosition(new Coord2(i, j)) && dijkstra.cost[i,j].ToString() != "2.147484E+09") writer.Write(dijkstra.cost[i, j].ToString()); else writer.Write("-"); string tab = "\t"; writer.Write(tab); } } writer.WriteLine(); bot = new AiBotSimple(x, y); player = new Player(0, 0); dijkstra = new Dijkstra(level); dijkstra.Build(level, bot, player); } } writer.Close(); level.tiles[0][0] = firstTile; }
/// <summary> /// A background worker, used to run testing on a background thread. /// </summary> protected override void OnDoWork(DoWorkEventArgs e) { base.OnDoWork(e); for (int i = 0; i < config.NumberOfTestRuns; i++) { if (!CheckCancellation()) { // Calculate positions for this test run Coord2 targetPos = new Coord2(0, 0); Coord2 botPos = new Coord2(0, 0); // Assign a random bot position do { botPos.X = rand.Next(0, LevelHandler.Level.Map.GridSize); botPos.Y = rand.Next(0, LevelHandler.Level.Map.GridSize); } while (!LevelHandler.Level.Map.ValidPosition(botPos)); // Calculate area in which the target should not be Rectangle noSpawnArea = new Rectangle(botPos.X - config.PathDistance, botPos.Y - config.PathDistance, config.PathDistance * 2, config.PathDistance * 2); // Assign a target position the correct distance from the bot do { targetPos.X = rand.Next(0, LevelHandler.Level.Map.GridSize); targetPos.Y = rand.Next(0, LevelHandler.Level.Map.GridSize); } while (!LevelHandler.Level.Map.ValidPosition(targetPos) && noSpawnArea.Contains(new Point(targetPos.X, targetPos.Y))); // Run test on the loaded level results.Add(LevelHandler.RunTest(config.Algorithm, botPos, targetPos)); // Report the thread's current progress ReportProgress((int)(100/config.NumberOfTestRuns)*i, null); } else break; } }
public void Build(Coord2 startPos, Coord2 targetPos) { if(InputHandler.IsKeyPressed(Microsoft.Xna.Framework.Input.Keys.Enter)) { this.startPos = startPos; this.targetPos = targetPos; path = new List<Coord2>(); nodes = new NodeCollection(GridSize); // Initialize bot position nodes.Get(startPos.X, startPos.Y).cost = 0; bool firstLoop = true; while (nodes.Get(targetPos.X, targetPos.Y).closed == false) { if (firstLoop) { currentLowestPos = startPos; firstLoop = false; } else FindLowestCost(); // Find lowest cost // Mark lowest cost as closed nodes.Get(currentLowestPos.X, currentLowestPos.Y).closed = true; // Find the neigbour positions Coord2[] neighbours = GetNeighbours(currentLowestPos); // Recalculate Costs RecalculateCosts(neighbours, currentLowestPos); } // Trace the completed path TracePath(); } }
// Follow the highest adjacent scent value. protected override void ChooseNextGridLocation(Level level, Player plr) { if (GridPosition == plr.GridPosition) return; Coord2 next = new Coord2(-1, -1); int highest = 0; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (level.ValidPosition(new Coord2(GridPosition.X+i, GridPosition.Y+j)) && plr.GetScent(GridPosition.X + i, GridPosition.Y + j) > highest && (i == 0 || j == 0)) { if (i == 0 && j == 0) continue; highest = plr.GetScent(GridPosition.X + i, GridPosition.Y + j); next = new Coord2(GridPosition.X + i, GridPosition.Y + j); } } } SetNextGridPosition(next, level); }
public void Build(Coord2 startPos, Coord2 targetPos) { buffer2 = buffer1; // Copy Buffers // Increment player's value sourceValue = sourceValue + 1; Coord2 currentLoc; // Update all locations for (int x = 0; x < gridSize; x++) { for (int y = 0; y < gridSize; y++) { currentLoc = new Coord2(x, y); if (map.ValidPosition(currentLoc)) // Ignore blocked spaces ProcessLocation(currentLoc, targetPos); } } // Update data in player's location buffer1.data[targetPos.X, targetPos.Y] = sourceValue; }
protected override void RecalculateCosts(Coord2[] neighbours, Coord2 pos) { for (int i = 0; i < 8; i++) { if(map.ValidPosition(neighbours[i]) && nodes.Get(neighbours[i].X, neighbours[i].Y).closed == false) { float costToAdd = 0.0f; if (neighbours[i].X != 0 && neighbours[i].Y != 0) costToAdd = D_COST; else costToAdd = HV_COST; float newCost = nodes.Get(pos.X, pos.Y).cost + costToAdd + manhattanDist(neighbours[i], currentLowestPos); if (newCost < nodes.Get(neighbours[i].X, neighbours[i].Y).cost) { nodes.Get(neighbours[i].X, neighbours[i].Y).cost = newCost; nodes.Get(neighbours[i].X, neighbours[i].Y).link = pos; } } } }
protected override void ChooseNextGridLocation(Level level, Player plr) { Coord2 CurrentPos; CurrentPos = GridPosition; //checks bot surrounding nodes. if(GridPosition != plr.GridPosition) { for (int f = -1; f <= 1; f++) { for (int g = -1; g <= 1; g++) { //changes bot position. if (level.scentmap.buffer1[GridPosition.X + f, GridPosition.Y + g] > level.scentmap.buffer1[GridPosition.X, GridPosition.Y]) { CurrentPos = new Coord2(GridPosition.X + f, GridPosition.Y + g); level.path_count ++; } SetNextGridPosition(CurrentPos, level); } } } }
public void Build(Level level, Coord2 from, Coord2 to, bool cutCorners, string heuristicIn) { cutCorners = !cutCorners; heuristic = heuristicIn; gCost[from.X, from.Y] = 0; Coord2 currentPosition = from; closed[from.X, from.Y] = true; while (!closed[to.X, to.Y]) { // Open adjacent cells. for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (level.ValidPosition(new Coord2(currentPosition.X + i, currentPosition.Y + j)) && !closed[currentPosition.X+i, currentPosition.Y+j]) // Make sure position is valid// Make sure position is in range { if (cutCorners) if (!(level.ValidPosition(new Coord2(currentPosition.X + i, currentPosition.Y)) && level.ValidPosition(new Coord2(currentPosition.X, currentPosition.Y + j)))) continue; if (!open.Contains(new Coord2(currentPosition.X + i, currentPosition.Y + j))) open.Add(new Coord2(currentPosition.X + i, currentPosition.Y + j)); if (i == 0 || j == 0) SetCost(currentPosition, to, level, i, j, false); else SetCost(currentPosition, to, level, i, j, true); } } } float lowestCost = int.MaxValue; Coord2 nextPosition = currentPosition; // Iterate through the open list to find next cell. for (int i = 0; i < open.Count; i++) { if (cost[open[i].X, open[i].Y] < lowestCost) { lowestCost = cost[open[i].X, open[i].Y]; nextPosition = new Coord2(open[i].X, open[i].Y); } } if (currentPosition == nextPosition) break; open.Remove(nextPosition); closed[nextPosition.X, nextPosition.Y] = true; currentPosition = nextPosition; } bool done = false; Coord2 nextClose = to; // When destination is found, cycle through parents to find the path. while (!done) { if (nextClose.X == -1) break; if (nextClose == from) { playerPos = to; done = true; } inPath[nextClose.X, nextClose.Y] = true; path.Add(new Coord2(nextClose.X, nextClose.Y)); nextClose = link[nextClose.X, nextClose.Y]; } }
// Set the total cost of cells (parent + movement + heuristic). private void SetCost(Coord2 currentPosition, Coord2 plr, Level level, int x, int y, bool diag) { int moveCost; if (!diag) moveCost = 10; else moveCost = 14; if (gCost[currentPosition.X + x, currentPosition.Y + y] > gCost[currentPosition.X, currentPosition.Y] + moveCost) { float hCost = 0; if (heuristic == "Manhattan") hCost = Manhattan(currentPosition, plr, x, y); else if (heuristic == "Chebyshev") hCost = Chebyshev(currentPosition, plr, x, y); else if (heuristic == "Euclidean") hCost = Euclidean(currentPosition, plr, x, y); link[currentPosition.X + x, currentPosition.Y + y] = currentPosition; gCost[currentPosition.X + x, currentPosition.Y + y] = gCost[currentPosition.X, currentPosition.Y] + moveCost; cost[currentPosition.X + x, currentPosition.Y + y] = gCost[currentPosition.X + x, currentPosition.Y + y] + hCost; // // Heuristic. } }