Пример #1
0
        public CombinedMovementAndFiringDistanceCalculation(
            DistanceCalculation movementDistanceToFiringLine,
            FiringDistance firingDistance, Direction finalMovementDirectionTowardsTarget)
        {
            MovementDistanceToFiringLine = movementDistanceToFiringLine;
            FiringDistance = firingDistance;
            FinalMovementDirectionTowardsTarget = finalMovementDirectionTowardsTarget;

            // Calculate ticks until the target is shot:
            int ticksTillTargetShot = MovementDistanceToFiringLine.Distance + FiringDistance.TicksTillTargetShot;

            if (ticksTillTargetShot > Constants.UNREACHABLE_DISTANCE)
            {
                ticksTillTargetShot = Constants.UNREACHABLE_DISTANCE;
            }
            TicksTillTargetShot = ticksTillTargetShot;

            // Calculate ticks until the last shot is fired:
            int ticksTillLastShotFired = MovementDistanceToFiringLine.Distance + FiringDistance.TicksTillLastShotFired;

            if (ticksTillLastShotFired > Constants.UNREACHABLE_DISTANCE)
            {
                ticksTillLastShotFired = Constants.UNREACHABLE_DISTANCE;
            }
            TicksTillLastShotFired = ticksTillLastShotFired;
        }
Пример #2
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);
        }
Пример #3
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);
        }
Пример #4
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);
                    }
                }
            }
        }
        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 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);
        }
Пример #7
0
        public CombinedMovementAndFiringDistanceCalculation GetShortestAttackDistanceGivenTheSourcePointsMovementMatrix(
            DirectionalMatrix <DistanceCalculation> movementDistanceMatrix, Cell target)
        {
            int bestCombinedTicksUntilTargetShot = Constants.UNREACHABLE_DISTANCE;
            CombinedMovementAndFiringDistanceCalculation bestCombinedDistance = null;

            foreach (Direction attackDir in MovementDirections)
            {
                foreach (EdgeOffset edgeOffset in EdgeOffsets)
                {
                    Direction             outwardDir = attackDir.GetOpposite();
                    Line <FiringDistance> firingLine = FiringLineMatrix[target.Position, outwardDir, edgeOffset];

                    for (int i = 0; i < firingLine.Length; i++)
                    {
                        FiringDistance firingDist = firingLine[i];

                        // Ignore firing line points that start off with a normal movement,
                        // as that path can be found by moving to the closer point in a non-firing line way:
                        if (firingDist.CanMoveOrFire)
                        {
                            continue;
                        }

                        // Ignore invalid starting points on the firing line:
                        if (!(GameStateCalculationCache.GameState.Walls.BoardBoundary.ContainsPoint(firingDist.StartingTankPosition) &&
                              TurnCalculationCache.TankLocationMatrix[firingDist.StartingTankPosition].IsValid))
                        {
                            break;
                        }

                        DistanceCalculation movementDist = movementDistanceMatrix[attackDir, firingDist.StartingTankPosition];

                        int combinedTicks = movementDist.Distance + firingDist.TicksTillTargetShot;
                        if (combinedTicks < bestCombinedTicksUntilTargetShot)
                        {
                            bestCombinedTicksUntilTargetShot = combinedTicks;
                            bestCombinedDistance
                                = new CombinedMovementAndFiringDistanceCalculation(movementDist, firingDist, attackDir);
                        }
                    }
                }
            }

            return(bestCombinedDistance);
        }
        public static Node[] GetOutgoingNodesOnShortestAttackPath(
            CombinedMovementAndFiringDistanceCalculation combinedCalculation,
            DirectionalMatrix <DistanceCalculation> distances,
            bool keepMovingCloserOnFiringLastBullet = false)
        {
            int length = combinedCalculation.TicksTillTargetShot;

            if (length == Constants.UNREACHABLE_DISTANCE)
            {
                return(new Node[0]);
            }

            Point               startingTankPositionOnFiringLine = combinedCalculation.FiringDistance.StartingTankPosition;
            Direction           finalAttackDir = combinedCalculation.FinalMovementDirectionTowardsTarget;
            DistanceCalculation distanceCalc   = combinedCalculation.MovementDistanceToFiringLine;

            // Add nodes to move onto firing line (in reverse order):
            Node[] nodes     = new Node[combinedCalculation.TicksTillTargetShot];
            int    nodeIndex = distanceCalc.Distance;
            Node   node      = new Node(ActionType.Moving, finalAttackDir,
                                        startingTankPositionOnFiringLine.X, startingTankPositionOnFiringLine.Y);

            while (nodeIndex != 0)
            {
                nodeIndex--;
                nodes[nodeIndex] = node;
                node             = distanceCalc.AdjacentNode;
                if (node.ActionType == ActionType.Firing)
                {
                    nodeIndex--;
                    nodes[nodeIndex] = node;
                    node             = new Node(ActionType.Moving, node.Dir, node.X, node.Y);
                }
                distanceCalc = distances[node.Dir, node.X, node.Y];
            }

            // Add firing line nodes:
            FiringDistanceCalculator.AddFiringLineNodesToRoute(combinedCalculation.FiringDistance,
                                                               finalAttackDir, nodes, ref nodeIndex, keepMovingCloserOnFiringLastBullet);

            if (nodeIndex < length)
            {
                Array.Resize(ref nodes, nodeIndex);
            }
            return(nodes);
        }