Пример #1
0
        private static void ReverseSolveDirection(
            GameBoard gameBoard,
            IGameBlockDestination gameBlock,
            IGameBlockDestination destinationBlock,
            MovementDirection direction,
            int maxCountAtPlayer,
            int maxNumberOfSolutions,
            int variability,
            ref int stepsBack,
            BlockMovement nextMove,
            Dictionary <string, GameBoard> solutionGameBoards)
        {
            // Test the board to see if a reverse solve is even possible.  If it's not, return early so it doesn't
            // waste time trying to solve something that can't be solved.
            if (CanTestReverseSolve && !gameBoard.TestCanReverseSolve())
            {
                return;
            }

            // So it doesn't always choose the max
            List <int> counts = Enumerable.Range(1, maxCountAtPlayer).ToList();

            for (int i = 0; i < counts.Count; i++)
            {
                int next  = RandomGenerator.Next(0, counts.Count - 1);
                int index = counts[next];
                counts.Remove(index);
                counts.Add(index);
            }

            for (int i = 0; i < counts.Count && solutionGameBoards.Count < maxNumberOfSolutions && !RequestAbort; i++)
            {
                BlockMovement temp;

                if (gameBlock.ApplyReverseMove(destinationBlock, direction, counts[i], out temp, null, null, new Queue <IGameBlock>()))
                {
                    bool allMovesUsed           = true;
                    int  originalAvailableMoves = temp.SourceBlock.AvailableMoves;

                    List <List <IGameBlockDestination> > removedCombinations;

                    if (nextMove != null)
                    {
                        temp.NextMove         = nextMove;
                        nextMove.PreviousMove = temp;
                    }

                    // Got more moves that we wanted, so take out a few randomly
                    int max = counts[i];

                    if (temp.SourceBlock.PreferredMaxMoves != 0 && temp.SourceBlock.AvailableMoves > temp.SourceBlock.PreferredMaxMoves)
                    {
                        max = Math.Min(max, temp.SourceBlock.PreferredMaxMoves);
                    }

                    // More moves than can be used
                    if (temp.SourceBlock.AvailableMoves > max)
                    {
                        int numberOfMovedNeedRemoving = temp.SourceBlock.AvailableMoves - max;

                        int numberAvailableForRemoving = temp.IntermediateBlocks.Count(ib => ib.CanBeRemovedIntermediate());

                        // Not possible because it needs to remove more items than it could
                        if (numberAvailableForRemoving < numberOfMovedNeedRemoving)
                        {
                            BlockMovement move = new BlockMovement(temp.SourceBlock, temp.Direction);
                            temp.SourceBlock.ApplyMove(null, temp.Direction, move);

                            continue;
                        }

                        allMovesUsed = false;

                        List <IGameBlockDestination> removeableIntermediates =
                            temp.IntermediateBlocks.Where(ib => ib.CanBeRemovedIntermediate()).ToList();

                        removedCombinations = new List <List <IGameBlockDestination> >();
                        IEnumerable <IEnumerable <IGameBlockDestination> > combos =
                            removeableIntermediates.Combinations(numberOfMovedNeedRemoving).ToList();

                        int count = 0;
                        foreach (IEnumerable <IGameBlockDestination> gameBlockDestinations in combos)
                        {
                            removedCombinations.Add(gameBlockDestinations.ToList());

                            if (MaxCombinations > 0 && ++count >= MaxCombinations)
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        removedCombinations = new List <List <IGameBlockDestination> > {
                            new List <IGameBlockDestination>()
                        };
                    }

                    List <IGameBlockDestination> originalIntermediateBlocks = new List <IGameBlockDestination>();

                    foreach (IGameBlockDestination gameBlockDestination in temp.IntermediateBlocks)
                    {
                        originalIntermediateBlocks.Add(gameBlockDestination.Clone() as IGameBlockDestination);
                    }

                    foreach (List <IGameBlockDestination> removedCombination in removedCombinations)
                    {
                        List <IGameBlockDestination>         unusedBlocks          = new List <IGameBlockDestination>();
                        List <List <IGameBlockDestination> > intermediateBlockSets = new List <List <IGameBlockDestination> >();

                        foreach (IGameBlockDestination gameBlockDestination in removedCombination)
                        {
                            temp.IntermediateBlocks.Remove(gameBlockDestination);

                            temp.SourceBlock.AvailableMoves--;
                            gameBlockDestination.SetAvailability(false);
                            unusedBlocks.Add(gameBlockDestination);
                        }

                        foreach (IGameBlockDestination unusedBlock in unusedBlocks)
                        {
                            for (int j = 0; j < temp.IntermediateBlocks.Count; j++)
                            {
                                List <IGameBlockDestination> sets = new List <IGameBlockDestination>(temp.IntermediateBlocks);

                                sets.RemoveAt(j);
                                sets.Add(unusedBlock);
                                intermediateBlockSets.Add(sets);
                            }
                        }

                        do
                        {
                            if (gameBoard.IsUntouchedPuzzle())
                            {
                                lock (solutionGameBoards)
                                {
                                    // HACK: Test the solution in case it comes up with an invalid solution
                                    GameBoard testSolution = (GameBoard)gameBoard.Clone();
                                    testSolution.SolutionStartMove = temp.CloneFromGameBoard(testSolution, null);
                                    testSolution.NullZeroPlayers();

                                    string key = testSolution.ToString();

                                    if (!solutionGameBoards.ContainsKey(key))
                                    {
                                        if (testSolution.PlaySolution())
                                        {
                                            GameBoard solution = (GameBoard)gameBoard.Clone();
                                            solution.SolutionStartMove = temp.CloneFromGameBoard(solution, null);
                                            solution.NullZeroPlayers();
                                            solutionGameBoards.Add(key, solution);
                                            NotifySolutionFoundEvent();
                                        }
                                    }
                                }
                            }
                            else if (!gameBoard.HasOrphan())
                            {
                                List <IGameBlockDestination> destinations = new List <IGameBlockDestination>();

                                foreach (IGameBlock nextBlock in gameBoard.GameBlocks)
                                {
                                    IGameBlockDestination nextDestination = nextBlock as IGameBlockDestination;

                                    if (nextDestination != null && !nextDestination.IsFullyAvailable)
                                    {
                                        for (int j = 0; j < nextDestination.NumberUsed; j++)
                                        {
                                            destinations.Add(nextDestination);
                                        }
                                    }
                                }

                                Shuffle(destinations, destinations.Count);

                                foreach (IGameBlockDestination nextBlock in destinations)
                                {
                                    ReverseSolveMovements(
                                        gameBoard,
                                        nextBlock,
                                        null,
                                        maxCountAtPlayer,
                                        maxNumberOfSolutions,
                                        variability,
                                        ref stepsBack,
                                        temp,
                                        solutionGameBoards);

                                    if (solutionGameBoards.Count >= maxNumberOfSolutions)
                                    {
                                        allMovesUsed = true;
                                        break;
                                    }

                                    if (RequestAbort)
                                    {
                                        break;
                                    }
                                }
                            }

                            // Not all the moves were used, but no solution was found, so let's use one of the ones we took out
                            if (!allMovesUsed)
                            {
                                if (intermediateBlockSets.Count == 0)
                                {
                                    allMovesUsed = true;
                                }
                                else
                                {
                                    // Replace the block with one of the unused ones
                                    temp.IntermediateBlocks.ForEach(g => g.SetAvailability(true));

                                    List <IGameBlockDestination> intermediateBlockSet = intermediateBlockSets[0];
                                    intermediateBlockSets.RemoveAt(0);
                                    intermediateBlockSet.ForEach(g => g.SetAvailability(false));

                                    temp.IntermediateBlocks = intermediateBlockSet;
                                }
                            }
                            else
                            {
                                allMovesUsed = true;
                                NotifySolutionFailedEvent();
                            }
                        }while (!allMovesUsed && !RequestAbort);

                        if (removedCombination.Count > 0)
                        {
                            allMovesUsed = false;
                            temp.IntermediateBlocks.Clear();

                            foreach (IGameBlockDestination gameBlockDestination in originalIntermediateBlocks)
                            {
                                IGameBlockDestination blockDestination =
                                    gameBoard.GameBlocks[gameBlockDestination.IndexRow, gameBlockDestination.IndexColumn] as
                                    IGameBlockDestination;
                                blockDestination.Copy(gameBlockDestination);
                                temp.IntermediateBlocks.Add(blockDestination);
                            }

                            temp.SourceBlock.AvailableMoves = originalAvailableMoves;
                        }
                    }

                    BlockMovement blockMove = new BlockMovement(temp.SourceBlock, temp.Direction);
                    temp.SourceBlock.ApplyMove(null, temp.Direction, blockMove);
                }
            }
        }