예제 #1
0
        public IEnumerable <WaveFront> ContractAndCalculate(GameState gameState, int distance, PlayerCalculator calculator, HashSet <CellState> reachableCells)
        {
            bool      isWesternMostPoint            = true;
            WaveFront newFront                      = null;
            Position  easternMostPositionOfNewFront = null;

            foreach (Position position in GetPointsFromWestToEast())
            {
                CellState cellState         = gameState[position];
                bool      isPointOnNewFront = true; // A flag to indicate whether to keep this point on the new front
                if (calculator.IsCellOccupied(cellState))
                {
                    isPointOnNewFront = false;
                }
                else
                {
                    // See if the point has already been visited:
                    int existingDistance = calculator.GetExistingDistance(cellState);
                    if (existingDistance <= distance)
                    {
                        isPointOnNewFront = (existingDistance == distance) && !position.IsPole &&
                                            ((isWesternMostPoint && IsWesternPointShared) ||
                                             (position == EasternPoint && IsEasternPointShared)
                                            );

                        /* This will be false except when this is the shared point on the Western-most edge.
                         * If it's a shared point then the adjacent front may have already set the distance.
                         * So we assume that the distance has already been set by the adjacent front.
                         */
                    }
                    else
                    {
                        calculator.SetDistance(cellState, distance, reachableCells);
                    }
                }

                bool isWesternPointShared = false;

                if (isWesternMostPoint)
                {
                    isWesternPointShared = IsWesternPointShared;

                    if (isPointOnNewFront)
                    {
                        if (position.IsPole)
                        {
                            // Create a polar wave front going in the opposite direction:
                            WaveFront polarWaveFront = CreateAReflectedPolarWaveFront(position);
                            yield return(polarWaveFront);

                            isPointOnNewFront    = false;
                            isWesternPointShared = false;
                        }
                        else
                        if (!IsWesternPointShared)
                        {
                            // Create a new wave front to expand around any barriers:
                            WaveFront adjacentFrontOnWesternSide = CreateAPointWaveOnTheWesternEdge(position);
                            yield return(adjacentFrontOnWesternSide);

                            isWesternPointShared = true;
                        }
                    }
                }

                if (isPointOnNewFront)
                {
                    if (position.IsPole)
                    {
                        /* Note: The following code assumes that this is a diagonal front.
                         * There is a very small chance that this is a polar front that has reached the opposite pole.
                         * Since this is a very rare event, we can afford the cost of testing every single point in the front.
                         * So don't worry about fixing this.
                         * /
                         *
                         * /* End off current front (if there is one): */
                        if (newFront != null)
                        {
                            newFront.EasternPoint         = easternMostPositionOfNewFront;
                            newFront.IsEasternPointShared = false;
                            yield return(newFront);

                            newFront = null;
                        }

                        /* Create a polar wave front going in the opposite direction: */
                        WaveFront polarWaveFront = CreateAReflectedPolarWaveFront(position);
                        yield return(polarWaveFront);

                        isPointOnNewFront = false;
                    }
                    else
                    {
                        if (newFront == null)
                        {
                            /* Create a new front in the same direction for this next segment of the original wave front: */
                            newFront = WaveFrontFactory.CreateWaveFront(Direction);
                            newFront.WesternPoint         = position;
                            newFront.IsWesternPointShared = isWesternPointShared;
                            isWesternPointShared          = false;
                        }
                        easternMostPositionOfNewFront = position;
                    }
                }
                else
                {
                    /* End the front currently being built: */
                    if (newFront != null)
                    {
                        newFront.EasternPoint         = easternMostPositionOfNewFront;
                        newFront.IsEasternPointShared = false;
                        yield return(newFront);

                        newFront = null;
                    }
                }

                // No longer the western-most point
                isWesternMostPoint = false;
            }

            if (newFront != null)
            {
                bool isEasternPointShared = IsEasternPointShared;

                // End off the Eastern-most front:
                newFront.EasternPoint         = EasternPoint;
                newFront.IsEasternPointShared = true;
                yield return(newFront);

                if (!IsEasternPointShared)
                {
                    // Create a new wave front to expand around any barriers:
                    newFront = CreateAPointWaveOnTheEasternEdge(EasternPoint);
                    yield return(newFront);
                }
                newFront = null;
            }
        }
예제 #2
0
        protected override void CalculateDistancesFromAPlayer(GameState gameState, PlayerType player, HashSet <CellState> reachableCells)
        {
            CellState        startingCell = null;
            PlayerCalculator calculator   = null;

            switch (player)
            {
            case PlayerType.You:
                gameState.OpponentIsInSameCompartment = false;      // Clear this property, so the algorithm can set it
                calculator   = new YouCalculator();
                startingCell = gameState.YourCell;
                break;

            case PlayerType.Opponent:
                startingCell = gameState.OpponentsCell;
                calculator   = new OpponentCalculator();
                break;
            }

            /* Set up the initial wave fronts, all for a single point (the player's position): */
            Position startPoint = startingCell.Position;
            LinkedList <WaveFront> currentWaveFronts = new LinkedList <WaveFront>();

            if (startingCell == gameState.NorthPole)
            {
                WaveFront waveFront = new SouthTravellingPolarWaveFront
                {
                    WesternPoint = startPoint,
                    EasternPoint = startPoint
                };
                currentWaveFronts.AddLast(waveFront);
            }
            else
            if (startingCell == gameState.SouthPole)
            {
                WaveFront waveFront = new NorthTravellingPolarWaveFront
                {
                    WesternPoint = startPoint,
                    EasternPoint = startPoint
                };
                currentWaveFronts.AddLast(waveFront);
            }
            else
            {
                /* Create 4 wave fronts of a single point each, in each of the diagonal directions: */
                WaveDirection[] diagonalDirections = { WaveDirection.NW, WaveDirection.NE, WaveDirection.SE, WaveDirection.SW };
                foreach (WaveDirection direction in diagonalDirections)
                {
                    WaveFront waveFront = WaveFrontFactory.CreateWaveFront(direction);
                    waveFront.WesternPoint         = waveFront.EasternPoint = startPoint;
                    waveFront.IsWesternPointShared = true;
                    waveFront.IsEasternPointShared = true;
                    currentWaveFronts.AddLast(waveFront);
                }
            }

            /* Iteratively expand the wave fronts until there are none left to expand: */
            int nextDistance = 0;
            LinkedList <WaveFront> nextWaveFronts;

            while (currentWaveFronts.Count > 0)
            {
                nextDistance++;
                nextWaveFronts = new LinkedList <WaveFront>();
                foreach (WaveFront currentWaveFront in currentWaveFronts)
                {
                    WaveFront expandedWaveFront           = currentWaveFront.Expand();
                    IEnumerable <WaveFront> newWaveFronts = expandedWaveFront.ContractAndCalculate(gameState, nextDistance, calculator, reachableCells);
                    foreach (WaveFront newWaveFront in newWaveFronts)
                    {
                        nextWaveFronts.AddLast(newWaveFront);
                    }
                }
                currentWaveFronts = nextWaveFronts;
            }

            /* Update aggregate data: */
            switch (player)
            {
            case PlayerType.You:
                gameState.NumberOfCellsReachableByYou       = calculator.NumberOfCellsReachable;
                gameState.TotalDegreesOfCellsReachableByYou = calculator.TotalDegreesOfCellsReachable;
                gameState.YourDijkstraStatus           = DijkstraStatus.FullyCalculated;
                gameState.YourUpToDateDijkstraDistance = int.MaxValue;
                break;

            case PlayerType.Opponent:
                gameState.NumberOfCellsReachableByOpponent       = calculator.NumberOfCellsReachable;
                gameState.TotalDegreesOfCellsReachableByOpponent = calculator.TotalDegreesOfCellsReachable;
                gameState.OpponentsDijkstraStatus           = DijkstraStatus.FullyCalculated;
                gameState.OpponentsUpToDateDijkstraDistance = int.MaxValue;
                break;
            }
        }