private void MoveTowards(Position targetPosition) { if (currentPath == null || currentPath.Count == 0 || !targetPosition.Equals(currentTargetPosition) || !CanMove(currentPath.First()) || (position.Distance(targetPosition) % 11 == 0)) // Every 11 steps make sure that a new best path hasn't magically appeared { // Try to create a path if the current one is invalid currentPath = Pathfinder.FindPath(engine, this, engine.map.GetTileAt(position), engine.map.GetTileAt(targetPosition)); currentTargetPosition = targetPosition; // Remove the first element because we are already there if (currentPath != null) { currentPath.RemoveAt(0); } } if (currentPath != null && currentPath.Count > 0 && currentTargetPosition.Equals(targetPosition) && CanMove(currentPath.First())) { Position nextStep = currentPath.First(); currentPath.RemoveAt(0); TryToMove(nextStep); } else { status = Status.Idle; // Retry after moveRetryCooldown ticks engine.ScheduleUpdate(moveRetryCooldown, this); } }
public int GetDistanceFrom(Position position) { // Calculate point nearest to startPosition inside this chunk Position nearestPosition = new Position(Math.Max(topLeft.x, Math.Min(bottomRight.x, position.x)), Math.Max(topLeft.y, Math.Min(bottomRight.y, position.y))); // Return distance return(nearestPosition.Distance(position)); }
// Kinda private methods public void MoveUnit(Unit unit, Position targetPosition) { Debug.Assert(targetPosition.Distance(unit.position) == 1); Debug.Assert(unitGrid[targetPosition.x, targetPosition.y] == null); CacheRemoveUnitAt(unit.position); unit.previousPosition = unit.position; unit.position = targetPosition; unit.animationStartTick = currentTick; CacheSetUnitAt(unit); }
public Unit NearestUnitTo(Unit startUnit, int maxDistance, Position startPosition = null) { if (startPosition == null) { startPosition = startUnit.position; } if (!Inside(startPosition)) { var nearestPosition = new Position(Math.Max(0, Math.Min(startPosition.x, width - 1)), Math.Max(0, Math.Min(startPosition.y, height - 1))); maxDistance -= nearestPosition.Distance(startPosition); startPosition = nearestPosition; } Chunk chunk = GetChunk(startPosition); // Breadth first search HashSet <Chunk> haveBeenInFrontier = new HashSet <Chunk> { chunk }; LinkedList <Chunk> frontier = new LinkedList <Chunk>(haveBeenInFrontier); while (frontier.Count > 0) { var top = frontier.First(); frontier.RemoveFirst(); // Try to find nearest in this chunk Unit closestUnit = null; int nearestDistance = Int32.MaxValue; foreach (var unit in top.units) { int distance = startPosition.Distance(unit.position); if (distance <= nearestDistance && unit != startUnit) { nearestDistance = distance; closestUnit = unit; } } if (closestUnit != null && nearestDistance <= maxDistance) { return(closestUnit); } // if a unit has not been found yet, try the neighbors foreach (var neighbor in top.neighbors) { if (!haveBeenInFrontier.Contains(neighbor) && neighbor.GetDistanceFrom(startPosition) <= maxDistance) { frontier.AddLast(neighbor); haveBeenInFrontier.Add(neighbor); } } } return(null); // Didn't find a unit within maxDistance }
//The engine can call this to tell the AI to issue upto numMoves orders. This allows the AI to scale how much it is doing public void makeMoves(int numMoves) { int peasentCount = 0, knightCount = 0, archerCount = 0, mineCount = 0, townCount = 0, attackingCount = 0; foreach (Unit u in engine.units) { if (u.owner != me) { continue; } if (u.type.Equals(engine.unitTypes[2])) { peasentCount++; } if (u.type.Equals(engine.unitTypes[0])) { knightCount++; if (u.orders.Count > 0 && u.orders[0].orderType.Equals(Order.OrderType.Attack)) { attackingCount++; } } if (u.type.Equals(engine.unitTypes[1])) { archerCount++; if (u.orders.Count > 0 && u.orders[0].orderType.Equals(Order.OrderType.Attack)) { attackingCount++; } } if (u.type.Equals(engine.unitTypes[4])) { mineCount++; } if (u.type.Equals(engine.unitTypes[3])) { townCount++; } } //generic loop to determine what the AI does for (int i = 0; i < numMoves; i++) { //Currently we want to be able to gather Unit currentUnit = null; foreach (Unit u in engine.units) { if (u.owner == me) { if (u.CanAttack() && !u.CanGather() && !u.CanProduce()) { if (u.orders.Count != 0) { continue; } Position p = null; int distance = 100000000; Unit closestTarget = null; foreach (Unit target in engine.units) { if (target.owner != me) { if (target.position.Distance(u.position) < distance) { distance = target.position.Distance(u.position); closestTarget = target; p = target.position; } } } if (p != null) { engine.OrderAttack(u, closestTarget); break; } } if (u.CanProduce() && !u.CanGather() && archerCount + knightCount <= attackingCount) { int unit_to_produce = -1; if (peasentCount == 0) { unit_to_produce = 2; } else if (knightCount < archerCount) { unit_to_produce = 0; } else { unit_to_produce = 1; } if (unit_to_produce >= 0) { engine.OrderProduce(u, engine.unitTypes[unit_to_produce]); break; } } if (townCount < 5 && me.gold >= engine.unitTypes[3].goldCost && u.CanBuild()) //Can build a town, build it { if (u.orders.Count == 0) { engine.OrderProduce(u, engine.unitTypes[3]); } } if (u.CanMove() && u.CanBuild() && me.gold >= engine.unitTypes[4].goldCost && mineCount < 5) //make mines { if (u.orders.Count == 0 || u.orders[0].orderType.Equals(Order.OrderType.Gather)) //if the unit is not doing anything { currentUnit = u; if (u.orders.Count != 0 && u.orders[0].orderType.Equals(Order.OrderType.Gather) && goldTiles.Contains(u.position)) { u.orders.Clear(); engine.OrderMove(u, u.position + new Position(0, 1)); engine.OrderProduce(u, engine.unitTypes[4], u.position); break; } //find closest open goldtile and issue order for that Position closestGold = goldTiles[0]; Position unitPosition = currentUnit.position; int distance = unitPosition.Distance(closestGold); foreach (Position p in goldTiles) { if (engine.GetUnitAt(p) == null) //no one is on the tile { if (unitPosition.Distance(p) < distance) { distance = unitPosition.Distance(p); closestGold = p; } } } engine.OrderProduce(currentUnit, engine.unitTypes[4], closestGold); break; } } else if (u.CanMove() && u.CanGather() && me.gold < 1000) { if (u.orders.Count == 0 /* || u.orders[0].orderType.Equals(Order.OrderType.Move) */) //if the unit is not doing anything { currentUnit = u; if (currentUnit == null) { return; //I have no units } if (goldTiles.Contains(currentUnit.position)) { continue; } //find closest open goldtile and issue order for that Position closestGold = goldTiles[0]; Position unitPosition = currentUnit.position; int distance = unitPosition.Distance(closestGold); foreach (Position p in goldTiles) { if (engine.GetUnitAt(p) == null) //no one is on the tile { bool alreadyTargeted = false; foreach (Unit blocker in engine.units) { if (blocker.orders.Count > 0 && blocker.orders[0].orderType.Equals(Order.OrderType.Gather) && blocker.orders[0].targetPosition.Equals(p)) { alreadyTargeted = true; break; } } if (alreadyTargeted) { continue; } if (unitPosition.Distance(p) < distance) { distance = unitPosition.Distance(p); closestGold = p; } } } if (distance != 0) { engine.OrderGather(currentUnit, closestGold); break; } } } } } } }
// Kinda private methods public void MoveUnit(Unit unit, Position targetPosition) { Debug.Assert(targetPosition.Distance(unit.position) == 1); Debug.Assert(unitGrid[targetPosition.x, targetPosition.y] == null); CacheRemoveUnitAt(unit.position); unit.previousPosition = unit.position; unit.position = targetPosition; unit.animationStartTick = currentTick; CacheSetUnitAt(unit); }
public Unit NearestUnitTo(Unit startUnit, int maxDistance, Position startPosition=null) { if (startPosition == null) { startPosition = startUnit.position; } if (!Inside(startPosition)) { var nearestPosition = new Position(Math.Max(0, Math.Min(startPosition.x, width - 1)), Math.Max(0, Math.Min(startPosition.y, height - 1))); maxDistance -= nearestPosition.Distance(startPosition); startPosition = nearestPosition; } Chunk chunk = GetChunk(startPosition); // Breadth first search HashSet<Chunk> haveBeenInFrontier = new HashSet<Chunk> {chunk}; LinkedList<Chunk> frontier = new LinkedList<Chunk>(haveBeenInFrontier); while (frontier.Count > 0) { var top = frontier.First(); frontier.RemoveFirst(); // Try to find nearest in this chunk Unit closestUnit = null; int nearestDistance = Int32.MaxValue; foreach (var unit in top.units) { int distance = startPosition.Distance(unit.position); if (distance <= nearestDistance && unit != startUnit) { nearestDistance = distance; closestUnit = unit; } } if (closestUnit != null && nearestDistance <= maxDistance) { return closestUnit; } // if a unit has not been found yet, try the neighbors foreach (var neighbor in top.neighbors) { if (!haveBeenInFrontier.Contains(neighbor) && neighbor.GetDistanceFrom(startPosition) <= maxDistance) { frontier.AddLast(neighbor); haveBeenInFrontier.Add(neighbor); } } } return null; // Didn't find a unit within maxDistance }
public int GetDistanceFrom(Position position) { // Calculate point nearest to startPosition inside this chunk Position nearestPosition = new Position(Math.Max(topLeft.x, Math.Min(bottomRight.x, position.x)), Math.Max(topLeft.y, Math.Min(bottomRight.y, position.y))); // Return distance return nearestPosition.Distance(position); }