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);
        }
        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> GetDistanceMatrixFromTankByTankIndex(int tankIndex)
        {
            if (distanceMatricesFromTankByTankIndex == null)
            {
                distanceMatricesFromTankByTankIndex = new DirectionalMatrix <DistanceCalculation> [Constants.TANK_COUNT];
            }
            if (distanceMatricesFromTankByTankIndex[tankIndex] == null)
            {
                TurnCalculationCache turnCalcCache = TurnCalculationCache;

                // Don't ride over your own base!
                Tank         tank       = Game.Current.Elements[tankIndex] as Tank;
                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 = TankOuterEdgeMatrix;
                distanceCalculator.CellMatrix          = turnCalcCache.CellMatrix;
                distanceCalculator.TabooAreas          = tabooAreas;

                MobileState tankState = GameState.GetMobileState(tankIndex);

                distanceMatricesFromTankByTankIndex[tankIndex]
                    = distanceCalculator.CalculateShortestDistancesFromTank(ref tankState);
            }
            return(distanceMatricesFromTankByTankIndex[tankIndex]);
        }