예제 #1
0
        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);
        }
예제 #5
0
        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);
                    }
                }
            }
        }
예제 #6
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);
        }
예제 #8
0
        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;
                        }
                    }
                }
            }
        }
예제 #9
0
        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);
        }
예제 #10
0
        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);
        }
예제 #11
0
        public int GetAttackingDistanceToTank(Tank tank)
        {
            DirectionalMatrix <DistanceCalculation> distanceCalcs
                = CellState.GameState.CalculationCache.GetIncomingAttackMatrixForTankByTankIndex(tank.Index);

            return(distanceCalcs[MobileState].Distance);
        }
예제 #12
0
        public CombinedMovementAndFiringDistanceCalculation GetShortestAttackDistanceFromCurrentTankPosition(
            int tankIndex, Cell target)
        {
            DirectionalMatrix <DistanceCalculation> movementDistanceMatrix
                = GameStateCalculationCache.GetDistanceMatrixFromTankByTankIndex(tankIndex);

            return(GetShortestAttackDistanceGivenTheSourcePointsMovementMatrix(movementDistanceMatrix, target));
        }
예제 #13
0
        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));
 }
예제 #15
0
        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);
        }
예제 #16
0
        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));
 }
예제 #19
0
        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);
        }
예제 #20
0
 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;
 }
예제 #21
0
 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));
        }
예제 #23
0
        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);
        }
예제 #24
0
        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));
        }
예제 #25
0
        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);
        }
예제 #26
0
        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);
        }
예제 #28
0
        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);
        }
예제 #29
0
        /* 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);
        }
예제 #30
0
        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;
                }
            }
        }