public TankAction[] GetTankActionsFromTankToAttackTankAtPointAlongDirectionOfMovement( int playerIndex, int tankNumber, Point targetPoint, Direction finalMovementDir, EdgeOffset[] edgeOffsets, bool keepMovingCloserOnFiringLastBullet) { Tank tank = Game.Current.Players[playerIndex].Tanks[tankNumber]; MobileState tankState = GameState.GetMobileState(tank.Index); TurnCalculationCache turnCalcCache = Game.Current.Turns[GameState.Tick].CalculationCache; Cell targetCell = turnCalcCache.CellMatrix[targetPoint]; FiringLineMatrix firingLinesForTanksMatrix = GameState.CalculationCache.FiringLinesForTanksMatrix; AttackTargetDistanceCalculator attackCalculator = new AttackTargetDistanceCalculator( ElementType.TANK, firingLinesForTanksMatrix, GameState.CalculationCache, turnCalcCache); attackCalculator.MovementDirections = new Direction[] { finalMovementDir }; attackCalculator.EdgeOffsets = edgeOffsets; CombinedMovementAndFiringDistanceCalculation combinedDistCalc = attackCalculator.GetShortestAttackDistanceFromCurrentTankPosition(tank.Index, targetCell); return(PathCalculator.GetTanksActionsOnOutgoingShortestAttackPathFromCurrentTankPosition( tank.Index, combinedDistCalc, GameState.CalculationCache, keepMovingCloserOnFiringLastBullet)); /* was: * DirectionalMatrix<DistanceCalculation> incomingDistanceMatrix * = attackCalculator.CalculateMatrixOfShortestDistancesToTargetCell(targetCell); * DistanceCalculation distanceCalc = incomingDistanceMatrix[tankState]; * return PathCalculator.GetTankActionsOnIncomingShortestPath(incomingDistanceMatrix, tankState.Dir, tankState.Pos.X, tankState.Pos.Y, * targetPoint.X, targetPoint.Y, firingLinesForTanksMatrix, keepMovingCloserOnFiringLastBullet); */ }
public int GetAttackDistanceFromTankToTankAtPointAlongDirectionOfMovement( int playerIndex, int tankNumber, Point targetPoint, Direction finalMovementDir, EdgeOffset[] edgeOffsets) { Tank tank = Game.Current.Players[playerIndex].Tanks[tankNumber]; MobileState tankState = GameState.GetMobileState(tank.Index); TurnCalculationCache turnCalcCache = Game.Current.Turns[GameState.Tick].CalculationCache; Cell targetCell = turnCalcCache.CellMatrix[targetPoint]; FiringLineMatrix firingLinesForTanksMatrix = GameState.CalculationCache.FiringLinesForTanksMatrix; AttackTargetDistanceCalculator attackCalculator = new AttackTargetDistanceCalculator( ElementType.TANK, firingLinesForTanksMatrix, GameState.CalculationCache, turnCalcCache); attackCalculator.MovementDirections = new Direction[] { finalMovementDir }; attackCalculator.EdgeOffsets = edgeOffsets; CombinedMovementAndFiringDistanceCalculation combinedDistCalc = attackCalculator.GetShortestAttackDistanceFromCurrentTankPosition(tank.Index, targetCell); if (combinedDistCalc == null) { return(Constants.UNREACHABLE_DISTANCE); } else { return(combinedDistCalc.TicksTillTargetShot); } /* was: * DirectionalMatrix<DistanceCalculation> incomingDistanceMatrix * = attackCalculator.CalculateMatrixOfShortestDistancesToTargetCell(targetCell); * DistanceCalculation distanceCalc = incomingDistanceMatrix[tankState]; * return distanceCalc.Distance; */ }
public static TankAction[] GetTankActionsOnIncomingShortestPath( DirectionalMatrix <DistanceCalculation> distances, Direction dir, int fromX, int fromY, int targetX, int targetY, FiringLineMatrix firingLineMatrix, bool keepMovingCloserOnFiringLastBullet = false) { Node[] nodes = GetIncomingNodesOnShortestPath( distances, dir, fromX, fromY, targetX, targetY, firingLineMatrix, keepMovingCloserOnFiringLastBullet); return(ConvertNodesToTankActions(nodes)); }
public static TankAction[] GetTankActionsOnIncomingShortestPath( DirectionalMatrix <DistanceCalculation> distances, MobileState attackingTankState, Point targetPos, FiringLineMatrix firingLineMatrix, bool keepMovingCloserOnFiringLastBullet = false) { return(GetTankActionsOnIncomingShortestPath(distances, attackingTankState.Dir, attackingTankState.Pos.X, attackingTankState.Pos.Y, targetPos.X, targetPos.Y, firingLineMatrix, keepMovingCloserOnFiringLastBullet)); }
/// <summary> /// AttackTargetDistanceCalculator constructor /// </summary> /// <param name="targetElementType">The type of element (base, tank or bullet) which is being attacked</param> /// <param name="firingLineMatrix">The firing line matrix must be applicable to the target element type's extent</param> /// <param name="gameStateCalculationCache"></param> /// <param name="turnCalculationCache"></param> public AttackTargetDistanceCalculator( ElementType targetElementType, FiringLineMatrix firingLineMatrix, GameStateCalculationCache gameStateCalculationCache, TurnCalculationCache turnCalculationCache) : this() { FiringLineMatrix = firingLineMatrix; GameStateCalculationCache = gameStateCalculationCache; TurnCalculationCache = turnCalculationCache; TargetElementType = targetElementType; }
public static Node[] GetIncomingNodesOnShortestPath( DirectionalMatrix <DistanceCalculation> distances, Direction dir, int fromX, int fromY, int toX, int toY, FiringLineMatrix firingLineMatrix = null, bool keepMovingCloserOnFiringLastBullet = false) { DistanceCalculation distanceCalc = distances[dir, fromX, fromY]; if (distanceCalc.Distance == Constants.UNREACHABLE_DISTANCE) { return(new Node[0]); } int length = distanceCalc.Distance; Node[] nodes = new Node[length]; int nodeIndex; Node node; nodeIndex = 0; node = distanceCalc.AdjacentNode; while (nodeIndex != length) { if (node.ActionType == ActionType.FiringLine) { Line <FiringDistance> firingLine = firingLineMatrix[toX, toY, node.Dir.GetOpposite(), node.EdgeOffset]; FiringDistance firingDistance = firingLine[node.FiringLineIndex]; FiringDistanceCalculator.AddFiringLineNodesToRoute(firingDistance, firingLine.DirectionOfLine.GetOpposite(), nodes, ref nodeIndex, keepMovingCloserOnFiringLastBullet); break; } // Add the node: nodes[nodeIndex] = node; nodeIndex++; if (node.ActionType == ActionType.Firing) { // Add a moving node - the only reason to fire is to move... node = new Node(ActionType.Moving, node.Dir, node.X + node.Dir.GetXOffset(), node.Y + node.Dir.GetYOffset()); nodes[nodeIndex] = node; nodeIndex++; } distanceCalc = distances[node.Dir, node.X, node.Y]; node = distanceCalc.AdjacentNode; } if (nodeIndex < length) { Array.Resize(ref nodes, nodeIndex); } return(nodes); }
/* TODO: Allow easy comparison across actions... * public int[] GetAttackDistanceOfTankToEnemyBasePerTankAction(int playerIndex, int tankNumber) * { * MobileState tankState = GetTankState(playerIndex, tankNumber); * int[] attackDistancesByTankAction = new int[Constants.TANK_ACTION_COUNT]; * foreach (TankAction tankAction in TankHelper.TankActions) * { * if (tankState.IsActive) * { * * * DirectionalMatrix<DistanceCalculation> attackDistanceMatrix * = GameState.CalculationCache.GetIncomingDistanceMatrixForBase(1 - playerIndex); * return attackDistanceMatrix[tankState].Distance; * } * return Constants.UNREACHABLE_DISTANCE; * } * return attackDistancesByTankAction; * } */ public TankAction[] GetActionsToAttackEnemyBase(int playerIndex, int tankNumber) { MobileState tankState = GetTankState(playerIndex, tankNumber); if (tankState.IsActive) { Base enemyBase = GetEnemyBase(playerIndex); FiringLineMatrix firingLineMatrix = GameState.CalculationCache.FiringLinesForPointsMatrix; DirectionalMatrix <DistanceCalculation> attackDistanceMatrix = GameState.CalculationCache.GetIncomingDistanceMatrixForBase(1 - playerIndex); return(PathCalculator.GetTankActionsOnIncomingShortestPath(attackDistanceMatrix, tankState, enemyBase.Pos, firingLineMatrix, keepMovingCloserOnFiringLastBullet: true)); } return(NoTankActions); }
public int GetAttackDistanceFromTankToHypotheticalTankAtPoint( int playerIndex, int tankNumber, Point targetTankPoint, EdgeOffset[] edgeOffsets) { Tank tank = Game.Current.Players[playerIndex].Tanks[tankNumber]; MobileState tankState = GameState.GetMobileState(tank.Index); TurnCalculationCache turnCalcCache = Game.Current.Turns[GameState.Tick].CalculationCache; Cell targetCell = turnCalcCache.CellMatrix[targetTankPoint]; FiringLineMatrix firingLinesForTanksMatrix = GameState.CalculationCache.FiringLinesForTanksMatrix; AttackTargetDistanceCalculator attackCalculator = new AttackTargetDistanceCalculator( ElementType.TANK, firingLinesForTanksMatrix, GameState.CalculationCache, turnCalcCache); attackCalculator.MovementDirections = BoardHelper.AllRealDirections; attackCalculator.EdgeOffsets = edgeOffsets; CombinedMovementAndFiringDistanceCalculation combinedDistCalc = attackCalculator.GetShortestAttackDistanceFromCurrentTankPosition(tank.Index, targetCell); return(combinedDistCalc.TicksTillTargetShot); }
private void ChooseShortestPathBotMoves() { GameState currGameState = Game.Current.CurrentTurn.GameState; TankActionSet actionSet = new TankActionSet(YourPlayerIndex, currGameState.Tick); bool[] moveChosen = new bool[Constants.TANKS_PER_PLAYER]; RespondToBullets(currGameState, actionSet, moveChosen); Tuple <int, int, TankAction>[] tankNumberDistanceAndActionArray = new Tuple <int, int, TankAction> [Constants.TANKS_PER_PLAYER]; // The closest bot can attack the base: for (int tankNumber = 0; tankNumber < Constants.TANKS_PER_PLAYER; tankNumber++) { Tank tank = You.Tanks[tankNumber]; MobileState tankState = currGameState.GetMobileState(tank.Index); if (!tankState.IsActive) { tankNumberDistanceAndActionArray[tankNumber] = new Tuple <int, int, TankAction>(tankNumber, Constants.UNREACHABLE_DISTANCE, TankAction.NONE); continue; } Base enemyBase = Opponent.Base; DirectionalMatrix <DistanceCalculation> distancesToEnemyBase = currGameState.CalculationCache.GetIncomingDistanceMatrixForBase(Opponent.Index); DistanceCalculation distanceCalc = distancesToEnemyBase[tankState.Dir, tankState.Pos]; FiringLineMatrix firingLineMatrix = currGameState.CalculationCache.FiringLinesForPointsMatrix; TankAction[] tankActions = PathCalculator.GetTankActionsOnIncomingShortestPath(distancesToEnemyBase, tankState.Dir, tankState.Pos.X, tankState.Pos.Y, enemyBase.Pos.X, enemyBase.Pos.Y, firingLineMatrix, keepMovingCloserOnFiringLastBullet: false); if (tankActions.Length == 0) { tankNumberDistanceAndActionArray[tankNumber] = new Tuple <int, int, TankAction>(tankNumber, Constants.UNREACHABLE_DISTANCE, TankAction.NONE); } else { tankNumberDistanceAndActionArray[tankNumber] = new Tuple <int, int, TankAction>(tankNumber, distanceCalc.Distance, tankActions[0]); } } int chosenTank; if (tankNumberDistanceAndActionArray[1].Item2 < tankNumberDistanceAndActionArray[0].Item2) { chosenTank = 1; } else { chosenTank = 0; } actionSet.Actions[chosenTank] = tankNumberDistanceAndActionArray[chosenTank].Item3; // The other bot can attack the closest enemy tank: Tank killerTank = You.Tanks[1 - chosenTank]; MobileState killerTankState = currGameState.GetMobileState(killerTank.Index); if (killerTankState.IsActive) { Tank enemyTank1 = Opponent.Tanks[0]; MobileState enemyTankState1 = currGameState.GetMobileState(enemyTank1.Index); int killerDistance1 = Constants.UNREACHABLE_DISTANCE; TankAction killerAction1 = TankAction.NONE; if (enemyTankState1.IsActive) { DirectionalMatrix <DistanceCalculation> attackMatrix1 = currGameState.CalculationCache.GetIncomingAttackMatrixForTankByTankIndex(enemyTank1.Index); if (attackMatrix1 != null) { DistanceCalculation attackCalculation1 = attackMatrix1[killerTankState.Dir, killerTankState.Pos]; killerDistance1 = attackCalculation1.Distance; TankAction[] tankActions = PathCalculator.GetTankActionsOnIncomingShortestPath(attackMatrix1, killerTankState, enemyTankState1.Pos, currGameState.CalculationCache.FiringLinesForTanksMatrix, keepMovingCloserOnFiringLastBullet: true); if (tankActions.Length > 0) { killerAction1 = tankActions[0]; } } } Tank enemyTank2 = Opponent.Tanks[1]; MobileState enemyTankState2 = currGameState.GetMobileState(enemyTank2.Index); int killerDistance2 = Constants.UNREACHABLE_DISTANCE; TankAction killerAction2 = TankAction.NONE; if (enemyTankState2.IsActive) { DirectionalMatrix <DistanceCalculation> attackMatrix2 = currGameState.CalculationCache.GetIncomingAttackMatrixForTankByTankIndex(enemyTank2.Index); if (attackMatrix2 != null) { DistanceCalculation attackCalculation2 = attackMatrix2[killerTankState.Dir, killerTankState.Pos]; killerDistance2 = attackCalculation2.Distance; TankAction[] tankActions = PathCalculator.GetTankActionsOnIncomingShortestPath(attackMatrix2, killerTankState, enemyTankState2.Pos, currGameState.CalculationCache.FiringLinesForTanksMatrix, keepMovingCloserOnFiringLastBullet: true); if (tankActions.Length > 0) { killerAction2 = tankActions[0]; } } } actionSet.Actions[1 - chosenTank] = (killerDistance1 <= killerDistance2) ? killerAction1 : killerAction2; } Coordinator.SetBestMoveSoFar(actionSet); }
private static void CalculateBulletThreats(BulletCalculation bulletCalc, GameState gameState, Player you) { TurnCalculationCache turnCalcCache = Game.Current.Turns[gameState.Tick].CalculationCache; Tank[] tanks; if (you != null) { tanks = you.Tanks; } else { tanks = Game.Current.Tanks; } foreach (Tank tank in tanks) { MobileState tankState = gameState.GetMobileState(tank.Index); foreach (BulletPathCalculation bulletPathCalc in bulletCalc.BulletPaths) { List <BulletThreat> bulletThreats = new List <BulletThreat>(); foreach (BulletPathPoint bulletPathPoint in bulletPathCalc.BulletPathPoints) { if (bulletPathPoint.DangerArea.ContainsPoint(tankState.Pos)) { BulletThreat bulletThreat = new BulletThreat(bulletPathCalc) { FiringTank = bulletPathCalc.Bullet.Tank, TankThreatened = tank }; bulletThreats.Add(bulletThreat); // Take the bullet on: FiringLineMatrix firingLineMatrix = gameState.CalculationCache.FiringLinesForPointsMatrix; AttackTargetDistanceCalculator attackCalculator = new AttackTargetDistanceCalculator( ElementType.BULLET, firingLineMatrix, gameState.CalculationCache, turnCalcCache); attackCalculator.MovementDirections = new Direction[] { bulletPathCalc.BulletState.Dir.GetOpposite() }; Cell bulletCell = turnCalcCache.CellMatrix[bulletPathCalc.BulletState.Pos]; DirectionalMatrix <DistanceCalculation> distanceCalcs = attackCalculator.CalculateMatrixOfShortestDistancesToTargetCell(bulletCell); DistanceCalculation distanceCalc = distanceCalcs[tankState]; if (distanceCalc.Distance <= bulletPathPoint.TicksToEscape) { Node[] nodes = PathCalculator.GetIncomingNodesOnShortestPath( distanceCalcs, tankState.Dir, tankState.Pos.X, tankState.Pos.Y, bulletPathCalc.BulletState.Pos.X, bulletPathCalc.BulletState.Pos.Y, firingLineMatrix, keepMovingCloserOnFiringLastBullet: true); bulletThreat.NodePathToTakeOnBullet = nodes; TankAction[] tankActions = PathCalculator.GetTankActionsOnIncomingShortestPath(distanceCalcs, tankState.Dir, tankState.Pos.X, tankState.Pos.Y, bulletPathCalc.BulletState.Pos.X, bulletPathCalc.BulletState.Pos.Y, firingLineMatrix, keepMovingCloserOnFiringLastBullet: true); bulletThreat.TankActionsToTakeOnBullet = tankActions; } // Move off his path in one direction: Point tankOffset = tankState.Pos - bulletPathCalc.BulletState.Pos; Point bulletMovementOffset = bulletPathCalc.BulletState.Dir.GetOffset(); Point newTankPoint1; Point newTankPoint2; Direction newTankDir1; Direction newTankDir2; if (bulletPathCalc.BulletState.Dir.ToAxis() == Axis.Horizontal) { newTankPoint1 = new Point( (short)tankState.Pos.X, (short)(bulletPathCalc.BulletState.Pos.Y - Constants.TANK_OUTER_EDGE_OFFSET)); newTankDir1 = Direction.UP; newTankPoint2 = new Point( (short)tankState.Pos.X, (short)(bulletPathCalc.BulletState.Pos.Y + Constants.TANK_OUTER_EDGE_OFFSET)); newTankDir2 = Direction.DOWN; } else { newTankPoint1 = new Point( (short)(bulletPathCalc.BulletState.Pos.X - Constants.TANK_OUTER_EDGE_OFFSET), (short)tankState.Pos.Y); newTankDir1 = Direction.LEFT; newTankPoint2 = new Point( (short)(bulletPathCalc.BulletState.Pos.X + Constants.TANK_OUTER_EDGE_OFFSET), (short)tankState.Pos.Y); newTankDir2 = Direction.RIGHT; } DirectionalMatrix <DistanceCalculation> tankDistanceCalcs = gameState.CalculationCache.GetDistanceMatrixFromTankByTankIndex(tank.Index); distanceCalc = tankDistanceCalcs[newTankDir1, newTankPoint1.X, newTankPoint1.Y]; if (distanceCalc.Distance <= bulletPathPoint.TicksToEscape) { Node[] shortestPathsIn1Direction = PathCalculator.GetOutgoingNodesOnShortestPath(tankDistanceCalcs, newTankDir1, newTankPoint1.X, newTankPoint1.Y); bulletThreat.LateralMoveInOneDirection = shortestPathsIn1Direction; TankAction[] tankActionsIn1Direction = PathCalculator.GetTankActionsOnOutgoingShortestPath(tankDistanceCalcs, newTankDir1, newTankPoint1.X, newTankPoint1.Y); bulletThreat.TankActionsForLateralMoveInOneDirection = tankActionsIn1Direction; } distanceCalc = tankDistanceCalcs[newTankDir2, newTankPoint2.X, newTankPoint2.Y]; if (distanceCalc.Distance <= bulletPathPoint.TicksToEscape) { Node[] shortestPathsInOtherDirection = PathCalculator.GetOutgoingNodesOnShortestPath(tankDistanceCalcs, newTankDir2, newTankPoint2.X, newTankPoint2.Y); bulletThreat.LateralMoveInOtherDirection = shortestPathsInOtherDirection; TankAction[] tankActionsInOtherDirection = PathCalculator.GetTankActionsOnOutgoingShortestPath(tankDistanceCalcs, newTankDir2, newTankPoint2.X, newTankPoint2.Y); bulletThreat.TankActionsForLateralMoveInOtherDirection = tankActionsInOtherDirection; } } } bulletPathCalc.BulletThreats = bulletThreats.ToArray(); } } }
public void ChooseActions(GameState currGameState, TankActionSet actionSet, bool[] moveChosenByTankNumber) { int[] minDistanceToAttackEnemyBaseByPlayerIndex = new int[Constants.PLAYERS_PER_GAME]; int[] minDistanceToDefendOwnBaseByPlayerIndex = new int[Constants.PLAYERS_PER_GAME]; bool[] isUnmarked = new bool[Constants.PLAYERS_PER_GAME]; Direction[] attackDirOnEnemyBaseByPlayerIndex = new Direction[Constants.PLAYERS_PER_GAME]; for (int p = 0; p < 2; p++) { attackDirOnEnemyBaseByPlayerIndex[p] = Direction.NONE; } Tank closestFriendlyTankToAttackEnemyBase = null; Tank closestFriendlyTankToDefendOwnBase = null; Tank closestEnemyTankToAttackYourBase = null; TankAction[] tankActionsForClosestFriendlyTankToAttackEnemyBase = null; TankAction[] tankActionsForClosestFriendlyTankToDefendOwnBase = null; foreach (Player player in Game.Current.Players) { int minDistanceToEnemyBase = Constants.UNREACHABLE_DISTANCE; foreach (Tank tank in player.Tanks) { MobileState tankState = currGameState.GetMobileState(tank.Index); if (!tankState.IsActive) // TODO: Check if locked in a firefight also { continue; } DirectionalMatrix <DistanceCalculation> distanceCalcMatrix = currGameState.CalculationCache.GetIncomingDistanceMatrixForBase(1 - player.Index); DistanceCalculation baseAttackCalc = distanceCalcMatrix[tankState]; int distanceToEnemyBase = baseAttackCalc.Distance; if (distanceToEnemyBase < minDistanceToEnemyBase) { minDistanceToEnemyBase = distanceToEnemyBase; attackDirOnEnemyBaseByPlayerIndex[player.Index] = baseAttackCalc.AdjacentNode.Dir; if (player == You) { closestFriendlyTankToAttackEnemyBase = tank; Base enemyBase = Game.Current.Players[1 - You.Index].Base; FiringLineMatrix firingLineMatrix = currGameState.CalculationCache.FiringLinesForPointsMatrix; tankActionsForClosestFriendlyTankToAttackEnemyBase = PathCalculator.GetTankActionsOnIncomingShortestPath( distanceCalcMatrix, tankState, enemyBase.Pos, firingLineMatrix, true); } else { closestEnemyTankToAttackYourBase = tank; } } } minDistanceToAttackEnemyBaseByPlayerIndex[player.Index] = minDistanceToEnemyBase; } foreach (Player player in Game.Current.Players) { int minDistanceToDefendOwnBase = Constants.UNREACHABLE_DISTANCE; foreach (Tank tank in player.Tanks) { MobileState tankState = currGameState.GetMobileState(tank.Index); if (tankState.IsActive) // TODO: Check if locked in a firefight also { DirectionalMatrix <DistanceCalculation> distanceMatrix = currGameState.CalculationCache.GetDistanceMatrixFromTankByTankIndex(tank.Index); Direction attackDir = attackDirOnEnemyBaseByPlayerIndex[1 - player.Index]; Direction defenceDir = attackDir.GetOpposite(); if (defenceDir == Direction.NONE) { defenceDir = Direction.RIGHT; } Point defencePos = player.Base.Pos + (Constants.SEGMENT_SIZE + 1) * defenceDir.GetOffset(); DistanceCalculation tankDefenceCalc = distanceMatrix[ defenceDir, defencePos]; int distance = tankDefenceCalc.Distance; if (distance < minDistanceToDefendOwnBase) { minDistanceToDefendOwnBase = distance; if (player == You) { closestFriendlyTankToDefendOwnBase = tank; tankActionsForClosestFriendlyTankToDefendOwnBase = PathCalculator.GetTankActionsOnOutgoingShortestPath( distanceMatrix, defenceDir, defencePos.X, defencePos.Y); } } } } minDistanceToDefendOwnBaseByPlayerIndex[player.Index] = minDistanceToDefendOwnBase; if (minDistanceToAttackEnemyBaseByPlayerIndex[1 - player.Index] < minDistanceToDefendOwnBase) { isUnmarked[1 - player.Index] = true; } } /* * int minAttackDistance = minDistanceToAttackEnemyBaseByPlayerIndex[You.Index]; * if (Game.Current.CurrentTurn.Tick + minAttackDistance > Game.Current.FinalTickInGame) * { * // Can't attack in time, rather defend... * return; * } */ // You're unmarked... Tank attackTank = closestFriendlyTankToAttackEnemyBase; if (isUnmarked[You.Index] && attackTank != null) { bool shouldAttack = true; // Enemy is marked... if (!isUnmarked[1 - You.Index]) { int minAttackDistance = minDistanceToAttackEnemyBaseByPlayerIndex[You.Index]; int minEnemyAttackDistance = minDistanceToAttackEnemyBaseByPlayerIndex[1 - You.Index]; // But if you stop marking them, by going for their base, they can get there first... if ((minAttackDistance > minEnemyAttackDistance) && (closestFriendlyTankToDefendOwnBase == attackTank)) { shouldAttack = false; // TODO: See if your other tank can do defence duty instead... } } if (shouldAttack && !moveChosenByTankNumber[attackTank.Number]) { actionSet.Actions[attackTank.Number] = tankActionsForClosestFriendlyTankToAttackEnemyBase[0]; moveChosenByTankNumber[attackTank.Number] = true; } } // If there is a slack of less than 5 ticks to defend your base, get back to defend it: Tank defenceTank = closestFriendlyTankToDefendOwnBase; if ((defenceTank != null) && (minDistanceToAttackEnemyBaseByPlayerIndex[1 - You.Index] < minDistanceToDefendOwnBaseByPlayerIndex[You.Index] + 5)) { if (!moveChosenByTankNumber[defenceTank.Number]) { actionSet.Actions[defenceTank.Number] = tankActionsForClosestFriendlyTankToAttackEnemyBase[0]; moveChosenByTankNumber[defenceTank.Number] = true; } } // Otherwise choose an enemy tank to attack: for (int t = 0; t < Constants.TANKS_PER_PLAYER; t++) { if ((closestEnemyTankToAttackYourBase != null) && (!moveChosenByTankNumber[t])) { // Rather attack an enemy tank in a firefight with own tank.. Tank killerTank = You.Tanks[t]; AttackClosestEnemyTankToOwnBase(currGameState, killerTank, closestEnemyTankToAttackYourBase, actionSet, moveChosenByTankNumber); } } }