public TankAction[] GetActionsToReachLineOfFireDefencePointByIncomingAttackDirection( int playerIndex, int tankNumber, Direction finalIncomingDirectionOfAttack) { Player player = Game.Current.Players[playerIndex]; Tank tank = player.Tanks[tankNumber]; MobileState tankState = GetTankState(playerIndex, tankNumber); if (tankState.IsActive) // TODO: Check if locked in a firefight also { DirectionalMatrix <DistanceCalculation> distanceMatrix = GameState.CalculationCache.GetDistanceMatrixFromTankByTankIndex(tank.Index); Direction defenceDir = finalIncomingDirectionOfAttack.GetOpposite(); if (defenceDir == Direction.NONE) { defenceDir = Direction.RIGHT; } int startPosOffsetFromBase = Constants.TANK_OUTER_EDGE_OFFSET; int endPosOffsetFromBase = startPosOffsetFromBase + MAX_POINTS_TO_TRY_FOR_DEFENCE_POS; for (int offsetSize = startPosOffsetFromBase; offsetSize < endPosOffsetFromBase; offsetSize++) { Point defencePos = player.Base.Pos + defenceDir.GetOffset(offsetSize); DistanceCalculation tankDefenceCalc = distanceMatrix[defenceDir, defencePos]; if (tankDefenceCalc.CodedDistance == 0) { // This defence point can't be reached, try further away continue; } return(PathCalculator.GetTankActionsOnOutgoingShortestPath(distanceMatrix, defenceDir, defencePos)); } } return(new TankAction[0]); }
public DirectionalMatrix <DistanceCalculation> GetIncomingDistanceMatrixForBase(int playerIndex) { if (incomingDistanceMatricesByBase == null) { incomingDistanceMatricesByBase = new DirectionalMatrix <DistanceCalculation> [Constants.PLAYERS_PER_GAME]; } DirectionalMatrix <DistanceCalculation> incomingDistanceMatrix = incomingDistanceMatricesByBase[playerIndex]; if (incomingDistanceMatrix == null) { Base @base = Game.Current.Players[playerIndex].Base; Base @ownBase = Game.Current.Players[1 - playerIndex].Base; TurnCalculationCache turnCalcCache = TurnCalculationCache; Cell baseCell = turnCalcCache.CellMatrix[@base.Pos]; AttackTargetDistanceCalculator attackCalculator = new AttackTargetDistanceCalculator( ElementType.BASE, FiringLinesForPointsMatrix, this, turnCalcCache); // Don't move over your own base: TankLocation tankLoc = turnCalcCache.TankLocationMatrix[@ownBase.Pos]; attackCalculator.TabooAreas = new Rectangle[] { tankLoc.TankHalo }; incomingDistanceMatrix = attackCalculator.CalculateMatrixOfShortestDistancesToTargetCell(baseCell); incomingDistanceMatricesByBase[playerIndex] = incomingDistanceMatrix; } return(incomingDistanceMatrix); }
public DirectionalMatrix <DistanceCalculation> GetIncomingDistanceMatrixForBaseWithFinalDirectionOfMovement( int playerIndex, Direction finalDirectionOfMovement) { if (incomingDistanceMatricesByBaseAndFinalDirectionOfMovement == null) { incomingDistanceMatricesByBaseAndFinalDirectionOfMovement = new DirectionalMatrix <DistanceCalculation> [ Constants.PLAYERS_PER_GAME, Constants.RELEVANT_DIRECTION_COUNT]; } DirectionalMatrix <DistanceCalculation> incomingDistanceMatrix = incomingDistanceMatricesByBaseAndFinalDirectionOfMovement[playerIndex, (int)finalDirectionOfMovement]; if (incomingDistanceMatrix == null) { Base @base = Game.Current.Players[playerIndex].Base; TurnCalculationCache turnCalcCache = TurnCalculationCache; Cell baseCell = turnCalcCache.CellMatrix[@base.Pos]; AttackTargetDistanceCalculator attackCalculator = new AttackTargetDistanceCalculator( ElementType.BASE, FiringLinesForPointsMatrix, this, turnCalcCache); attackCalculator.MovementDirections = new Direction[] { finalDirectionOfMovement }; incomingDistanceMatrix = attackCalculator.CalculateMatrixOfShortestDistancesToTargetCell(baseCell); incomingDistanceMatricesByBaseAndFinalDirectionOfMovement[playerIndex, (int)finalDirectionOfMovement] = incomingDistanceMatrix; } return(incomingDistanceMatrix); }
public DirectionalMatrix <DistanceCalculation> GetIncomingAttackMatrixForTankByTankIndex(int tankIndex) { if (incomingAttackMatrixByTankIndex == null) { incomingAttackMatrixByTankIndex = new DirectionalMatrix <DistanceCalculation> [Constants.TANK_COUNT]; } DirectionalMatrix <DistanceCalculation> incomingAttackMatrix = incomingAttackMatrixByTankIndex[tankIndex]; if (incomingAttackMatrix == null) { MobileState tankState = GameState.GetMobileState(tankIndex); if (!tankState.IsActive) { return(null); } TurnCalculationCache turnCalcCache = TurnCalculationCache; Cell tankCell = turnCalcCache.CellMatrix[tankState.Pos]; AttackTargetDistanceCalculator attackCalculator = new AttackTargetDistanceCalculator( ElementType.TANK, FiringLinesForTanksMatrix, this, turnCalcCache); incomingAttackMatrix = attackCalculator.CalculateMatrixOfShortestDistancesToTargetCell(tankCell); incomingAttackMatrixByTankIndex[tankIndex] = incomingAttackMatrix; } return(incomingAttackMatrix); }
private void AddNodesToQueueForMovingOverTarget( DirectionalMatrix <DistanceCalculation> attackMatrix, TwoValuedCircularBuffer <Node> bfsQueue, TankLocation tankLocationAtTargetPoint) { // Give a distance of zero for internal points, but don't add them to the queue: DistanceCalculation zeroDistCalc = new DistanceCalculation(0, new Node()); foreach (Point interiorPoint in tankLocationAtTargetPoint.TankBody.GetPoints()) { foreach (Direction dir in BoardHelper.AllRealDirections) { attackMatrix[dir, interiorPoint] = zeroDistCalc; } } // Calculate the tank positions that will destroy the base or bullet via movement from various directions: foreach (Direction movementDir in MovementDirections) { Direction oppositeDir = movementDir.GetOpposite(); // Get the inside edge (segment) of the tank centred at the base in the opposite direction: Segment tankPositionsInDirection = tankLocationAtTargetPoint.InsideEdgesByDirection[(int)oppositeDir]; // For each point on the segment add it to the bfs queue with a distance of zero: foreach (Cell tankCellInDir in tankPositionsInDirection.Cells) { if (tankCellInDir.IsValid) { Node node = new Node(ActionType.Moving, movementDir, tankCellInDir.Position); bfsQueue.Add(node, 0); } } } }
public DirectionalMatrix <DistanceCalculation> CalculateShortestDistancesFromTank(ref MobileState tankState) { DirectionalMatrix <DistanceCalculation> distanceMatrix = new DirectionalMatrix <DistanceCalculation>(Walls.Width, Walls.Height); distanceMatrix[tankState.Dir, tankState.Pos] = new DistanceCalculation(0, new Node()); // Mark taboo areas: if (TabooAreas != null) { for (int r = 0; r < TabooAreas.Length; r++) { Rectangle tabooRect = TabooAreas[r]; foreach (Point tabooPoint in tabooRect.GetPoints()) { foreach (Direction dir in BoardHelper.AllRealDirections) { if (CellMatrix[tabooPoint].IsValid) { distanceMatrix[dir, tabooPoint] = new DistanceCalculation( DistanceCalculationConstants.TABOO_DISTANCE, new Node()); } } } } } // Restrict the area of the board within which to do shortest path calculations (i.e. for efficiency reasons): if (RestrictedMovementArea != Rectangle.Unrestricted) { foreach (Direction restrictedAreaDir in BoardHelper.AllRealDirections) { Rectangle outerEdge = RestrictedMovementArea.GetOuterEdgeInDirection(restrictedAreaDir); if (outerEdge.IntersectsWith(Walls.BoardBoundary)) { foreach (Point restrictedPoint in outerEdge.GetPoints()) { if (Walls.BoardBoundary.ContainsPoint(restrictedPoint) && CellMatrix[restrictedPoint].IsValid) { foreach (Direction dir in BoardHelper.AllRealDirections) { distanceMatrix[dir, restrictedPoint] = new DistanceCalculation( DistanceCalculationConstants.TABOO_DISTANCE, new Node()); } } } } } } if (TicksWithoutFiring > 0) { FindShortestPathsWithRestrictionsOnFiring(tankState, distanceMatrix); } else { FindShortestPaths(tankState, distanceMatrix); } return(distanceMatrix); }
public static Node[] GetOutgoingNodesOnShortestPath( DirectionalMatrix <DistanceCalculation> distances, Direction dir, int x, int y) { DistanceCalculation distanceCalc = distances[dir, x, y]; if (distanceCalc.Distance == Constants.UNREACHABLE_DISTANCE) { return(new Node[0]); } Node[] nodes = new Node[distanceCalc.Distance]; int index = distanceCalc.Distance; Node node = new Node(ActionType.Moving, dir, x, y); while (index != 0) { index--; nodes[index] = node; node = distanceCalc.AdjacentNode; if (node.ActionType == ActionType.Firing) { index--; nodes[index] = node; node = new Node(ActionType.Moving, node.Dir, node.X, node.Y); } distanceCalc = distances[node.Dir, node.X, node.Y]; } return(nodes); }
public void AttackClosestEnemyTankToOwnBase(GameState currGameState, Tank killerTank, Tank targetTank, TankActionSet actionSet, bool[] moveChosenByTankNumber) { MobileState killerTankState = currGameState.GetMobileState(killerTank.Index); if (killerTankState.IsActive) { MobileState enemyTankState = currGameState.GetMobileState(targetTank.Index); if (enemyTankState.IsActive) { DirectionalMatrix <DistanceCalculation> attackMatrix = currGameState.CalculationCache.GetIncomingAttackMatrixForTankByTankIndex(targetTank.Index); if (attackMatrix != null) { DistanceCalculation attackCalculation = attackMatrix[killerTankState.Dir, killerTankState.Pos]; TankAction[] tankActions = PathCalculator.GetTankActionsOnIncomingShortestPath(attackMatrix, killerTankState, enemyTankState.Pos, currGameState.CalculationCache.FiringLinesForTanksMatrix, keepMovingCloserOnFiringLastBullet: true); if (tankActions.Length > 0) { actionSet.Actions[killerTank.Number] = tankActions[0]; moveChosenByTankNumber[killerTank.Number] = true; } } } } }
public static TankAction[] GetTankActionsOnShortestPath( DirectionalMatrix <DistanceCalculation> distances, Direction dir, int x, int y) { DistanceCalculation distanceCalc = distances[dir, x, y]; if (distanceCalc.Distance == Constants.UNREACHABLE_DISTANCE) { return(new TankAction[0]); } TankAction[] tankActions = new TankAction[distanceCalc.Distance]; int index = distanceCalc.Distance; Node node = new Node(ActionType.Moving, dir, x, y); while (index != 0) { index--; tankActions[index] = node.Dir.ToTankAction(); node = distanceCalc.AdjacentNode; if (node.ActionType == ActionType.Firing) { index--; tankActions[index] = TankAction.FIRE; node = new Node(ActionType.Moving, node.Dir, node.X, node.Y); } distanceCalc = distances[node.Dir, node.X, node.Y]; } return(tankActions); }
public DirectionalMatrix <DistanceCalculation> GetCustomDistanceMatrixFromTank( int playerIndex, int tankNumber, int ticksWithoutFiring, Rectangle restrictedBoardArea) { Tank tank = Game.Current.Players[playerIndex].Tanks[tankNumber]; TurnCalculationCache turnCalcCache = Game.Current.Turns[GameState.Tick].CalculationCache; // Don't ride over your own base! Base @base = tank.Player.Base; TankLocation tankLoc = turnCalcCache.TankLocationMatrix[@base.Pos]; Rectangle[] tabooAreas = new Rectangle[] { tankLoc.TankBody }; DistanceCalculator distanceCalculator = new DistanceCalculator(); distanceCalculator.Walls = GameState.Walls; distanceCalculator.TankOuterEdgeMatrix = GameState.CalculationCache.TankOuterEdgeMatrix; distanceCalculator.CellMatrix = turnCalcCache.CellMatrix; distanceCalculator.TabooAreas = tabooAreas; distanceCalculator.TicksWithoutFiring = ticksWithoutFiring; distanceCalculator.RestrictedMovementArea = restrictedBoardArea; MobileState tankState = GameState.GetMobileState(tank.Index); DirectionalMatrix <DistanceCalculation> distanceMatrix = distanceCalculator.CalculateShortestDistancesFromTank(ref tankState); return(distanceMatrix); }
public int GetAttackingDistanceToTank(Tank tank) { DirectionalMatrix <DistanceCalculation> distanceCalcs = CellState.GameState.CalculationCache.GetIncomingAttackMatrixForTankByTankIndex(tank.Index); return(distanceCalcs[MobileState].Distance); }
public CombinedMovementAndFiringDistanceCalculation GetShortestAttackDistanceFromCurrentTankPosition( int tankIndex, Cell target) { DirectionalMatrix <DistanceCalculation> movementDistanceMatrix = GameStateCalculationCache.GetDistanceMatrixFromTankByTankIndex(tankIndex); return(GetShortestAttackDistanceGivenTheSourcePointsMovementMatrix(movementDistanceMatrix, target)); }
public int GetDistanceFromTankToPointUsingDistanceMatrix( DirectionalMatrix <DistanceCalculation> distanceMatrix, Direction directionAtDestination, Point destination) { DistanceCalculation distanceCalc = distanceMatrix[directionAtDestination, destination]; return(distanceCalc.Distance); }
public static TankAction[] GetTanksActionsOnOutgoingShortestAttackPath( CombinedMovementAndFiringDistanceCalculation combinedCalculation, DirectionalMatrix <DistanceCalculation> distances, bool keepMovingCloserOnFiringLastBullet = false) { Node[] nodes = GetOutgoingNodesOnShortestAttackPath( combinedCalculation, distances, keepMovingCloserOnFiringLastBullet); return(ConvertNodesToTankActions(nodes)); }
public int GetAttackDistanceFromTankToTank(int playerIndex, int tankNumber, int targetTankNumber) { Tank targetTank = Game.Current.Players[1 - playerIndex].Tanks[targetTankNumber]; DirectionalMatrix <DistanceCalculation> distanceMatrix = GameState.CalculationCache.GetIncomingAttackMatrixForTankByTankIndex(targetTank.Index); MobileState tankState = GetTankState(playerIndex, tankNumber); return(distanceMatrix[tankState].Distance); }
public TankAction[] GetTankActionsToMoveToPoint(int playerIndex, int tankNumber, Direction directionAtDestination, Point destination) { Tank tank = Game.Current.Players[playerIndex].Tanks[tankNumber]; DirectionalMatrix <DistanceCalculation> distanceMatrix = GameState.CalculationCache.GetDistanceMatrixFromTankByTankIndex(tank.Index); return(PathCalculator.GetTankActionsOnOutgoingShortestPath(distanceMatrix, directionAtDestination, destination)); }
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)); }
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 int GetDistanceFromTankToPoint(int playerIndex, int tankNumber, Direction directionAtDestination, Point destination) { Tank tank = Game.Current.Players[playerIndex].Tanks[tankNumber]; DirectionalMatrix <DistanceCalculation> distanceMatrix = GameState.CalculationCache.GetDistanceMatrixFromTankByTankIndex(tank.Index); DistanceCalculation distanceCalc = distanceMatrix[directionAtDestination, destination]; return(distanceCalc.Distance); }
public FiringLineMatrix(Point topLeft, int width, int height, ElementExtentType extentType, TurnCalculationCache turnCalcationCache, GameStateCalculationCache gameStateCalculationCache, EdgeOffsetType lastSupportedEdgeOffsetType = EdgeOffsetType.Centre) { directionalMatrixOfFiringLinesByEdgeOffset = new DirectionalMatrix <Line <FiringDistance>[]>(topLeft, width, height); LastSupportedEdgeOffsetType = lastSupportedEdgeOffsetType; ExtentType = extentType; TurnCalcationCache = turnCalcationCache; GameStateCalculationCache = gameStateCalculationCache; }
public int GetAttackDistanceToEnemyBaseFromTankState(int playerIndex, ref MobileState tankState) { if (tankState.IsActive) { DirectionalMatrix <DistanceCalculation> attackDistanceMatrix = GameState.CalculationCache.GetIncomingDistanceMatrixForBase(1 - playerIndex); return(attackDistanceMatrix[tankState].Distance); } return(Constants.UNREACHABLE_DISTANCE); }
public static TankAction[] GetTanksActionsOnOutgoingShortestAttackPathFromCurrentTankPosition( int tankIndex, CombinedMovementAndFiringDistanceCalculation combinedCalculation, GameStateCalculationCache gameStateCalcCache, bool keepMovingCloserOnFiringLastBullet = false) { DirectionalMatrix <DistanceCalculation> distanceMatrix = gameStateCalcCache.GetDistanceMatrixFromTankByTankIndex(tankIndex); Node[] nodes = GetOutgoingNodesOnShortestAttackPath( combinedCalculation, distanceMatrix, keepMovingCloserOnFiringLastBullet); return(ConvertNodesToTankActions(nodes)); }
public int GetAttackDistanceFromHypotheticalTankStateToTank( MobileState attackTankState, int targetPlayerIndex, int targetTankNumber, EdgeOffset[] edgeOffsets) { Tank targetTank = Game.Current.Players[targetPlayerIndex].Tanks[targetTankNumber]; DirectionalMatrix <DistanceCalculation> distanceMatrix = GameState.CalculationCache.GetIncomingAttackMatrixForTankByTankIndex(targetTank.Index); DistanceCalculation distanceCalc = distanceMatrix[attackTankState]; return(distanceCalc.Distance); }
public TankAction[] GetTankActionsFromTankToAttackTank(int playerIndex, int tankNumber, int targetTankNumber) { Tank targetTank = Game.Current.Players[1 - playerIndex].Tanks[targetTankNumber]; MobileState targetTankState = GetTankState(1 - playerIndex, targetTankNumber); DirectionalMatrix <DistanceCalculation> distanceMatrix = GameState.CalculationCache.GetIncomingAttackMatrixForTankByTankIndex(targetTank.Index); MobileState attackingTankState = GetTankState(playerIndex, tankNumber); return(PathCalculator.GetTankActionsOnIncomingShortestPath(distanceMatrix, attackingTankState, targetTankState.Pos, GameState.CalculationCache.FiringLinesForTanksMatrix, keepMovingCloserOnFiringLastBullet: false)); }
protected override void ChooseMoves() { GameState currGameState = Game.Current.CurrentTurn.GameState; TankActionSet actionSet = new TankActionSet(YourPlayerIndex, currGameState.Tick); for (int tankNumber = 0; tankNumber < Constants.TANKS_PER_PLAYER; tankNumber++) { Tank tank = You.Tanks[tankNumber]; MobileState tankState = currGameState.GetMobileState(tank.Index); if (!tankState.IsActive) { continue; } int midX = currGameState.Walls.Width / 2; int midY = currGameState.Walls.Height / 2; int targetX; int targetY; Direction direction; if (tankState.Pos.X > midX) { targetX = currGameState.Walls.Width - Constants.SEGMENT_SIZE; } else { targetX = Constants.SEGMENT_SIZE; } if (tankState.Pos.Y > midY) { targetY = currGameState.Walls.Height - Constants.SEGMENT_SIZE; direction = Direction.UP; } else { targetY = Constants.SEGMENT_SIZE; direction = Direction.DOWN; } DirectionalMatrix <DistanceCalculation> distancesFromTank = currGameState.CalculationCache.GetDistanceMatrixFromTankByTankIndex(tank.Index); TankAction[] tankActions = PathCalculator.GetTankActionsOnOutgoingShortestPath( distancesFromTank, direction, targetX, targetY); if (tankActions.Length > 0) { actionSet.Actions[tank.Number] = tankActions[0]; } } Coordinator.SetBestMoveSoFar(actionSet); }
public int GetDistanceFromTankToTargetTank( int attackPlayerIndex, int attackTankNumber, int targetPlayerIndex, int targetTankNumber) { Tank attackTank = Game.Current.Players[attackPlayerIndex].Tanks[attackTankNumber]; DirectionalMatrix <DistanceCalculation> distanceMatrix = GameState.CalculationCache.GetDistanceMatrixFromTankByTankIndex(attackTank.Index); Tank defenceTank = Game.Current.Players[targetPlayerIndex].Tanks[targetTankNumber]; MobileState targetTankState = GetTankState(targetPlayerIndex, targetTankNumber); DistanceCalculation distanceCalc = distanceMatrix[targetTankState]; return(distanceCalc.Distance); }
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); }
public int GetAttackDistanceOfTankToEnemyBaseFromDirection(int playerIndex, int tankNumber, Direction finalDirectionOfMovement) { MobileState tankState = GetTankState(playerIndex, tankNumber); if (tankState.IsActive) { DirectionalMatrix <DistanceCalculation> attackDistanceMatrix = GameState.CalculationCache.GetIncomingDistanceMatrixForBaseWithFinalDirectionOfMovement( 1 - playerIndex, finalDirectionOfMovement); return(attackDistanceMatrix[tankState].Distance); } return(Constants.UNREACHABLE_DISTANCE); }
/* 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); }
private void FindShortestPaths(MobileState tankState, DirectionalMatrix <DistanceCalculation> distanceMatrix) { TwoValuedCircularBuffer <Node> bfsQueue = new TwoValuedCircularBuffer <Node>(CircularBufferCapacityRequired); Node currNode = new Node(ActionType.Moving, tankState.Dir, tankState.Pos); int adjDistance = 1; bool nodesToProcess = true; while (nodesToProcess) { // Get each node adjacent to the current node: Node[] adjacentNodes = currNode.GetAdjacentOutgoingNodes(TankOuterEdgeMatrix[currNode.X, currNode.Y]); foreach (Node adj in adjacentNodes) { if (adj.ActionType == ActionType.Moving) { // Check if the node already has a distance i.e. has it already been expanded? if (distanceMatrix[adj.Dir, adj.X, adj.Y].CodedDistance == 0) { // Set the new shortest distance: distanceMatrix[adj.Dir, adj.X, adj.Y] = new DistanceCalculation(adjDistance, currNode); // Add to the queue to be expanded: bfsQueue.Add(adj, adjDistance); } } else { // A firing node can only be reached in one way (from the moving node on the same cell). // So we don't need to check if it is the shortest path to the node (it must be). // And we aren't interested in it, so no need to store it. // Hence just add it to the queue (it is a "convenience" node to allow a BFS): bfsQueue.Add(adj, adjDistance); } } if (bfsQueue.Size == 0) { nodesToProcess = false; } else { CircularBufferItem <Node> nextItem = bfsQueue.Remove(); currNode = nextItem.Item; adjDistance = nextItem.Value + 1; } } }