Example #1
0
        public BlockMovement CloneFromGameBoard(GameBoard gameBoard, BlockMovement previous)
        {
            BlockMovement clone =
                new BlockMovement(
                    gameBoard.GameBlocks[this.sourceBlock.IndexRow, this.sourceBlock.IndexColumn] as IGameBlockParent, this.direction);

            if (this.destinationBlock != null)
            {
                clone.destinationBlock =
                    gameBoard.GameBlocks[this.destinationBlock.IndexRow, this.destinationBlock.IndexColumn] as IGameBlockDestination;
            }

            foreach (IGameBlockDestination intermediateBlock in this.intermediateBlocks)
            {
                if (intermediateBlock != null)
                {
                    clone.intermediateBlocks.Add(
                        gameBoard.GameBlocks[intermediateBlock.IndexRow, intermediateBlock.IndexColumn] as IGameBlockDestination);
                }
            }

            clone.previousMove           = previous;
            clone.head                   = previous == null ? this : previous.head;
            clone.originalAvailableMoves = this.originalAvailableMoves;

            if (this.nextMove != null)
            {
                clone.nextMove = this.nextMove.CloneFromGameBoard(gameBoard, clone);
            }

            return(clone);
        }
Example #2
0
        public void Enqueue(BlockMovement blockMovement)
        {
            BlockMovement lastMovement = this.GetLastMovement();

            blockMovement.PreviousMove = lastMovement;
            lastMovement.NextMove      = blockMovement;
        }
Example #3
0
 public abstract bool ApplyReverseMoveForLoop(
     IGameBlockDestination destinationBlock,
     MovementDirection directionInReverse,
     int numberOfBlocksToMove,
     out BlockMovement move,
     IGameBlock previousBlock,
     IGameBlockDestination previousDestination,
     Queue <IGameBlock> blockHistory);
Example #4
0
        public BlockMovement GetLastMovement()
        {
            BlockMovement last = this;

            while (last.NextMove != null)
            {
                last = last.nextMove;
            }

            return(last);
        }
Example #5
0
        public override bool ApplyReverseMoveForLoop(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestination,
            Queue <IGameBlock> blockHistory)
        {
            move = null;

            return(false);
        }
Example #6
0
        public GameBoard(int rows, int columns)
        {
            this.gameBlocks = new IGameBlock[rows, columns];

            // Initialize the blocks to null blocks
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < columns; j++)
                {
                    this.CreateGameBlock(GameBlockType.Null, i, j);
                }
            }

            this.solutionStartMove = null;
        }
Example #7
0
        public object Clone()
        {
            BlockMovement clone = new BlockMovement(this.sourceBlock, this.direction);

            clone.intermediateBlocks.AddRange(this.intermediateBlocks);
            clone.destinationBlock       = this.destinationBlock;
            clone.previousMove           = this.previousMove;
            clone.head                   = this.head;
            clone.originalAvailableMoves = this.originalAvailableMoves;

            if (this.nextMove != null)
            {
                clone.nextMove = (BlockMovement)this.nextMove.Clone();
            }

            return(clone);
        }
Example #8
0
        public override bool ApplyReverseMove(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestinationBlock,
            Queue <IGameBlock> blockHistory)
        {
            // Already used
            if (this.AvailableMoves > 0)
            {
                move = null;
                return(false);
            }

            // This block is a valid "starting" point
            move = new BlockMovement(this, directionInReverse);
            return(true);
        }
Example #9
0
        /// <summary>
        /// Plays the solution.
        /// </summary>
        /// <returns>True if the solution solved it correctly.</returns>
        public bool PlaySolution()
        {
            BlockMovement current = this.solutionStartMove;

            while (current != null)
            {
                if (current.SourceBlock != null)
                {
                    BlockMovement move = new BlockMovement(current.SourceBlock, current.Direction);
                    if (!current.SourceBlock.ApplyMove(null, current.Direction, move))
                    {
                        // Invalid move?  Break out.
                        break;
                    }
                }

                current = current.NextMove;
            }

            // Finished applying all moves, so test if it's actually solved
            return(this.IsSolved());
        }
Example #10
0
        public string GetSolutionString()
        {
            StringBuilder stringBuilder = new StringBuilder();

            BlockMovement current = this.solutionStartMove;

            while (current != null)
            {
                if (current.SourceBlock != null)
                {
                    stringBuilder.AppendLine(
                        string.Format(
                            "Position: {0}, {1}  Number of Moves: {2}  Direction: {3}",
                            current.SourceBlock.IndexRow,
                            current.SourceBlock.IndexColumn,
                            current.SourceBlock.AvailableMoves,
                            current.Direction));
                }

                current = current.NextMove;
            }

            return(stringBuilder.ToString());
        }
Example #11
0
        public override bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, BlockMovement move)
        {
            // These blocks do the moves, so it has to be the first one selected.
            if (parentBlock != null)
            {
                return false;
            }

            // Out of moves
            if (this.availableMoves == 0)
            {
                return false;
            }

            BlockAnimationType animation;

            switch (direction)
            {
                default:
                case MovementDirection.Up:
                    animation = BlockAnimationType.RedGnomeSmashUp;
                    break;

                case MovementDirection.Down:
                    animation = BlockAnimationType.RedGnomeSmashDown;
                    break;

                case MovementDirection.Left:
                    animation = BlockAnimationType.RedGnomeSmashLeft;
                    break;

                case MovementDirection.Right:
                    animation = BlockAnimationType.RedGnomeSmashRight;
                    break;
            }

            this.NotifySetAnimation(animation, true, false);

            bool moveApplied;

            switch (direction)
            {
                default:
                case MovementDirection.Up:
                    if (this.Top == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Top.ApplyMove(this, direction, move);
                    }
                    break;

                case MovementDirection.Down:
                    if (this.Bottom == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Bottom.ApplyMove(this, direction, move);
                    }
                    break;

                case MovementDirection.Left:
                    if (this.Left == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Left.ApplyMove(this, direction, move);
                    }
                    break;

                case MovementDirection.Right:
                    if (this.Right == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Right.ApplyMove(this, direction, move);
                    }
                    break;
            }

            this.NotifySetAnimation(
                moveApplied ? BlockAnimationType.RedGnomeSmashSuccessful : BlockAnimationType.RedGnomeSmashFailed, false, false);

            return moveApplied;
        }
Example #12
0
        public override bool ApplyReverseMove(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestinationBlock,
            Queue<IGameBlock> blockHistory)
        {
            // Already used
            if (this.AvailableMoves > 0)
            {
                move = null;
                return false;
            }

            // This block is a valid "starting" point
            move = new BlockMovement(this, directionInReverse);
            return true;
        }
        public override bool ApplyReverseMoveForLoop(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestinationBlock,
            Queue<IGameBlock> blockHistory)
        {
            move = null;

            // This block can't be the destination
            if (destinationBlock == null)
            {
                return false;
            }

            // This block forces the next move to be a certain direction, so depending on what "forceDirection" is,
            // the next move is always going to be the one in that direction.  As a reverse move, previousBlock will
            // need to be the correct block based on this requirement.
            IGameBlock forcedPreviousBlock;
            switch (this.forceDirection)
            {
                default:
                case MovementDirection.Up:
                    forcedPreviousBlock = this.Top;
                    break;

                case MovementDirection.Down:
                    forcedPreviousBlock = this.Bottom;
                    break;

                case MovementDirection.Left:
                    forcedPreviousBlock = this.Left;
                    break;

                case MovementDirection.Right:
                    forcedPreviousBlock = this.Right;
                    break;
            }

            if (!ReferenceEquals(forcedPreviousBlock, previousBlock))
            {
                return false;
            }

            bool isPossibleLoopDirection;

            // This is trying to make a loop, so it has to be the opposite direction
            switch (this.forceDirection)
            {
                case MovementDirection.Up:
                    isPossibleLoopDirection = directionInReverse == MovementDirection.Down;
                    break;

                case MovementDirection.Down:
                    isPossibleLoopDirection = directionInReverse == MovementDirection.Up;
                    break;

                case MovementDirection.Left:
                    isPossibleLoopDirection = directionInReverse == MovementDirection.Right;
                    break;

                case MovementDirection.Right:
                    isPossibleLoopDirection = directionInReverse == MovementDirection.Left;
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
            }

            if (!isPossibleLoopDirection)
            {
                return false;
            }

            blockHistory.Enqueue(this);

            bool moveApplied;

            switch (directionInReverse)
            {
                default:
                case MovementDirection.Up:
                    if (this.Bottom == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Bottom.ApplyReverseMove(
                            destinationBlock,
                            directionInReverse,
                            numberOfBlocksToMove,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;

                case MovementDirection.Down:
                    if (this.Top == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Top.ApplyReverseMove(
                            destinationBlock,
                            directionInReverse,
                            numberOfBlocksToMove,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;

                case MovementDirection.Left:
                    if (this.Right == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Right.ApplyReverseMove(
                            destinationBlock,
                            directionInReverse,
                            numberOfBlocksToMove,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;

                case MovementDirection.Right:
                    if (this.Left == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Left.ApplyReverseMove(
                            destinationBlock,
                            directionInReverse,
                            numberOfBlocksToMove,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;
            }

            return moveApplied;
        }
Example #14
0
        public override bool ApplyReverseMoveForLoop(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestinationBlock,
            Queue<IGameBlock> blockHistory)
        {
            move = null;

            // This can't be the final destination block
            if (destinationBlock == null)
            {
                return false;
            }

            // It needs at least 2 previous blocks
            if (previousDestinationBlock == null)
            {
                return false;
            }

            if (destinationBlock == previousDestinationBlock)
            {
                return false;
            }

            bool moveApplied;
            switch (directionInReverse)
            {
                default:
                case MovementDirection.Down:
                    if (this.Bottom == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Bottom.ApplyReverseMoveForLoop(
                            destinationBlock,
                            directionInReverse,
                            numberOfBlocksToMove - 1,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;

                case MovementDirection.Up:
                    if (this.Top == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Top.ApplyReverseMoveForLoop(
                            destinationBlock,
                            directionInReverse,
                            numberOfBlocksToMove - 1,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;

                case MovementDirection.Right:
                    if (this.Right == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Right.ApplyReverseMoveForLoop(
                            destinationBlock,
                            directionInReverse,
                            numberOfBlocksToMove - 1,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;

                case MovementDirection.Left:
                    if (this.Left == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Left.ApplyReverseMoveForLoop(
                            destinationBlock,
                            directionInReverse,
                            numberOfBlocksToMove - 1,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;
            }

            if (moveApplied)
            {
                // It requires 1 less move if this block is used
                move.SourceBlock.AvailableMoves--;
            }

            return moveApplied;
        }
        public override bool ApplyReverseMove(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestinationBlock,
            Queue <IGameBlock> blockHistory)
        {
            move = null;

            // This block can't be the destination
            if (destinationBlock == null)
            {
                return(false);
            }

            // This block forces the next move to be a certain direction, so depending on what "forceDirection" is,
            // the next move is always going to be the one in that direction.  As a reverse move, previousBlock will
            // need to be the correct block based on this requirement.
            IGameBlock forcedPreviousBlock;

            switch (this.forceDirection)
            {
            default:
            case MovementDirection.Up:
                forcedPreviousBlock = this.Top;
                break;

            case MovementDirection.Down:
                forcedPreviousBlock = this.Bottom;
                break;

            case MovementDirection.Left:
                forcedPreviousBlock = this.Left;
                break;

            case MovementDirection.Right:
                forcedPreviousBlock = this.Right;
                break;
            }

            if (!ReferenceEquals(forcedPreviousBlock, previousBlock))
            {
                return(false);
            }

            blockHistory.Enqueue(this);

            // It can be any direction except for the forced direction, so try any one of the three others
            // until one of them works (at random)
            List <MovementDirection> directions = new List <MovementDirection>
            {
                MovementDirection.Down,
                MovementDirection.Up,
                MovementDirection.Left,
                MovementDirection.Right
            };

            switch (this.forceDirection)
            {
            case MovementDirection.Up:
                directions.Remove(MovementDirection.Down);
                break;

            case MovementDirection.Down:
                directions.Remove(MovementDirection.Up);
                break;

            case MovementDirection.Left:
                directions.Remove(MovementDirection.Right);
                break;

            case MovementDirection.Right:
                directions.Remove(MovementDirection.Left);
                break;
            }

            // Shuffle
            Random random = new Random();

            for (int i = 0; i < 3; i++)
            {
                MovementDirection remove = directions[random.Next(0, 2)];
                directions.Remove(remove);
                directions.Add(remove);
            }

            bool moveApplied = false;

            foreach (MovementDirection movementDirectionInReverse in directions)
            {
                switch (movementDirectionInReverse)
                {
                default:
                case MovementDirection.Up:
                    if (this.Bottom == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Bottom.ApplyReverseMove(
                            destinationBlock,
                            movementDirectionInReverse,
                            numberOfBlocksToMove,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;

                case MovementDirection.Down:
                    if (this.Top == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Top.ApplyReverseMove(
                            destinationBlock,
                            movementDirectionInReverse,
                            numberOfBlocksToMove,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;

                case MovementDirection.Left:
                    if (this.Right == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Right.ApplyReverseMove(
                            destinationBlock,
                            movementDirectionInReverse,
                            numberOfBlocksToMove,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;

                case MovementDirection.Right:
                    if (this.Left == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Left.ApplyReverseMove(
                            destinationBlock,
                            movementDirectionInReverse,
                            numberOfBlocksToMove,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;
                }

                // One of the moves worked, so break out
                if (moveApplied)
                {
                    break;
                }
            }

            return(moveApplied);
        }
        public override bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, BlockMovement move)
        {
            // If it's already applying the move, this is a loop
            if (this.applyingMove)
            {
                return false;
            }

            this.applyingMove = true;

            // Move to the next block, always in the forced direction
            bool moveApplied;

            switch (this.forceDirection)
            {
                default:
                case MovementDirection.Up:
                    this.NotifySetAnimation(BlockAnimationType.ChangeDirectionMoveStartedUp, true, false);
                    this.NotifySetAnimation(BlockAnimationType.ChangeDirectionUp, false, false);

                    if (this.Top == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Top.ApplyMove(parentBlock, this.forceDirection, move);
                    }
                    break;

                case MovementDirection.Down:
                    this.NotifySetAnimation(BlockAnimationType.ChangeDirectionMoveStartedDown, true, false);
                    this.NotifySetAnimation(BlockAnimationType.ChangeDirectionDown, false, false);

                    if (this.Bottom == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Bottom.ApplyMove(parentBlock, this.forceDirection, move);
                    }
                    break;

                case MovementDirection.Left:
                    this.NotifySetAnimation(BlockAnimationType.ChangeDirectionMoveStartedLeft, true, false);
                    this.NotifySetAnimation(BlockAnimationType.ChangeDirectionLeft, false, false);

                    if (this.Left == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Left.ApplyMove(parentBlock, this.forceDirection, move);
                    }
                    break;

                case MovementDirection.Right:
                    this.NotifySetAnimation(BlockAnimationType.ChangeDirectionMoveStartedRight, true, false);
                    this.NotifySetAnimation(BlockAnimationType.ChangeDirectionRight, false, false);

                    if (this.Right == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Right.ApplyMove(parentBlock, this.forceDirection, move);
                    }
                    break;
            }

            this.applyingMove = false;

            return moveApplied;
        }
Example #17
0
        public override bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, BlockMovement move)
        {
            // No moves available, so return false (it shouldn't even reach here under normal circumstances)
            if (parentBlock.AvailableMoves == 0)
            {
                return false;
            }

            bool moveApplied;

            // Add an extra move
            parentBlock.AvailableMoves++;

            this.NotifySetAnimation(BlockAnimationType.ExtraBlockMovedStarted, true, false);

            // Then try to apply the move
            switch (direction)
            {
                default:
                case MovementDirection.Up:
                    if (this.Top == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Top.ApplyMove(parentBlock, direction, move);
                    }
                    break;

                case MovementDirection.Down:
                    if (this.Bottom == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Bottom.ApplyMove(parentBlock, direction, move);
                    }
                    break;

                case MovementDirection.Left:
                    if (this.Left == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Left.ApplyMove(parentBlock, direction, move);
                    }
                    break;

                case MovementDirection.Right:
                    if (this.Right == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Right.ApplyMove(parentBlock, direction, move);
                    }
                    break;
            }

            // Undo the addition of the extra move if the move wasn't applied
            if (!moveApplied)
            {
                this.NotifySetAnimation(BlockAnimationType.ExtraBlockMovedCanceled, false, false);
                parentBlock.AvailableMoves--;
            }

            this.NotifySetAnimation(BlockAnimationType.ExtraBlockIdle, false, false);

            return moveApplied;
        }
Example #18
0
        private static void ReverseSolveMovements(
            GameBoard gameBoard,
            IGameBlockDestination gameBlock,
            IGameBlockDestination destinationBlock,
            int maxCountAtPlayer,
            int maxNumberOfSolutions,
            int variability,
            ref int stepsBack,
            BlockMovement nextMove,
            Dictionary <string, GameBoard> solutionGameBoards)
        {
            List <MovementDirection> movementDirections = GetRandomDirections();

            if (!gameBlock.IsFullyAvailable && !RequestAbort)
            {
                int    oldNumSolutions = solutionGameBoards.Count;
                string key             = gameBoard.GetBoardStringFull() + "_" + gameBlock.IndexRow + "_" + gameBlock.IndexColumn;

                lock (AlreadyTestedBoards)
                {
                    // Already tested this, so don't need to try it again
                    if (AlreadyTestedBoards.Contains(key))
                    {
                        return;
                    }

                    AlreadyTestedBoards.Add(key);
                }

                foreach (MovementDirection direction in movementDirections)
                {
                    ReverseSolveDirection(
                        gameBoard,
                        gameBlock,
                        destinationBlock,
                        direction,
                        maxCountAtPlayer,
                        maxNumberOfSolutions,
                        variability,
                        ref stepsBack,
                        nextMove,
                        solutionGameBoards);

                    // New solutions found so step back up the stack to get more variability in the solutions
                    if (oldNumSolutions != solutionGameBoards.Count)
                    {
                        if (variability > stepsBack)
                        {
                            stepsBack++;
                            break;
                        }
                        else
                        {
                            stepsBack = 0;
                        }
                    }

                    if (RequestAbort)
                    {
                        break;
                    }
                }
            }
        }
        public override bool ApplyReverseMove(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestinationBlock,
            Queue <IGameBlock> blockHistory)
        {
            move = null;

            // Starting with a non-filled block isn't valid
            if (destinationBlock != null && this.numberOfMovesApplied == 0)
            {
                return(false);
            }

            // If this is the destination
            bool thisIsFinalMove      = destinationBlock == null;
            int  availableBlocksToUse = this.CountUsedBlocks(directionInReverse, new Dictionary <IGameBlock, IGameBlock>());

            // See if there are enough blocks to do this move
            if (thisIsFinalMove && availableBlocksToUse < numberOfBlocksToMove - 1)
            {
                return(false);
            }

            bool isThisBlockUsedInLoop = ReferenceEquals(destinationBlock, this) || blockHistory.Contains(this);

            blockHistory.Enqueue(this);

            // Use this block as the destination block if destinationBlock is null
            IGameBlockDestination destination = destinationBlock ?? this;

            bool moveApplied;

            switch (directionInReverse)
            {
            default:
            case MovementDirection.Up:
                if (this.numberOfMovesApplied == numberOfMovesNeeded && !isThisBlockUsedInLoop)
                {
                    if (this.Top == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Top.ApplyReverseMoveForLoop(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }

                    // Loop failed, so try non-looped
                    if (!moveApplied && this.Bottom != null)
                    {
                        moveApplied = this.Bottom.ApplyReverseMove(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                }
                else
                {
                    if (this.Bottom == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Bottom.ApplyReverseMove(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                }

                break;

            case MovementDirection.Down:
                if (this.numberOfMovesApplied == numberOfMovesNeeded && !isThisBlockUsedInLoop)
                {
                    if (this.Bottom == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Bottom.ApplyReverseMoveForLoop(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }

                    // Loop failed, so try non-looped
                    if (!moveApplied && this.Top != null)
                    {
                        moveApplied = this.Top.ApplyReverseMove(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                }
                else
                {
                    if (this.Top == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Top.ApplyReverseMove(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                }

                break;

            case MovementDirection.Left:
                if (this.numberOfMovesApplied == numberOfMovesNeeded && !isThisBlockUsedInLoop)
                {
                    if (this.Left == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Left.ApplyReverseMoveForLoop(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }

                    // Loop failed, so try non-looped
                    if (!moveApplied && this.Right != null)
                    {
                        moveApplied = this.Right.ApplyReverseMove(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                }
                else
                {
                    if (this.Right == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Right.ApplyReverseMove(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                }

                break;

            case MovementDirection.Right:
                if (this.numberOfMovesApplied == numberOfMovesNeeded && !isThisBlockUsedInLoop)
                {
                    if (this.Right == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Right.ApplyReverseMoveForLoop(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }

                    // Loop failed, so try non-looped
                    if (!moveApplied && this.Left != null)
                    {
                        moveApplied = this.Left.ApplyReverseMove(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                }
                else
                {
                    if (this.Left == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Left.ApplyReverseMove(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                }

                break;
            }

            if (moveApplied && !this.IsFullyAvailable && move != null)
            {
                this.SetAvailability(true);
                move.InsertDestinationBlock(this);
                move.SourceBlock.AvailableMoves++;
            }

            return(moveApplied);
        }
Example #20
0
 public abstract bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, BlockMovement move);
Example #21
0
 public abstract bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, BlockMovement move);
Example #22
0
        public override bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, BlockMovement move)
        {
            // These blocks do the moves, so it has to be the first one selected.
            if (parentBlock != null)
            {
                return(false);
            }

            // Out of moves
            if (this.availableMoves == 0)
            {
                return(false);
            }

            BlockAnimationType animation;

            switch (direction)
            {
            default:
            case MovementDirection.Up:
                animation = BlockAnimationType.RedGnomeSmashUp;
                break;

            case MovementDirection.Down:
                animation = BlockAnimationType.RedGnomeSmashDown;
                break;

            case MovementDirection.Left:
                animation = BlockAnimationType.RedGnomeSmashLeft;
                break;

            case MovementDirection.Right:
                animation = BlockAnimationType.RedGnomeSmashRight;
                break;
            }

            this.NotifySetAnimation(animation, true, false);

            bool moveApplied;

            switch (direction)
            {
            default:
            case MovementDirection.Up:
                if (this.Top == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Top.ApplyMove(this, direction, move);
                }
                break;

            case MovementDirection.Down:
                if (this.Bottom == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Bottom.ApplyMove(this, direction, move);
                }
                break;

            case MovementDirection.Left:
                if (this.Left == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Left.ApplyMove(this, direction, move);
                }
                break;

            case MovementDirection.Right:
                if (this.Right == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Right.ApplyMove(this, direction, move);
                }
                break;
            }

            this.NotifySetAnimation(
                moveApplied ? BlockAnimationType.RedGnomeSmashSuccessful : BlockAnimationType.RedGnomeSmashFailed, false, false);

            return(moveApplied);
        }
Example #23
0
        public override bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, BlockMovement move)
        {
            // No moves available, so return false (it shouldn't even reach here under normal circumstances)
            if (parentBlock.AvailableMoves == 0)
            {
                return false;
            }

            bool moveApplied;

            // Add an extra move
            parentBlock.AvailableMoves++;

            this.NotifySetAnimation(BlockAnimationType.ExtraBlockMovedStarted, true, false);

            // Then try to apply the move
            switch (direction)
            {
                default:
                case MovementDirection.Up:
                    if (this.Top == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Top.ApplyMove(parentBlock, direction, move);
                    }
                    break;

                case MovementDirection.Down:
                    if (this.Bottom == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Bottom.ApplyMove(parentBlock, direction, move);
                    }
                    break;

                case MovementDirection.Left:
                    if (this.Left == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Left.ApplyMove(parentBlock, direction, move);
                    }
                    break;

                case MovementDirection.Right:
                    if (this.Right == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Right.ApplyMove(parentBlock, direction, move);
                    }
                    break;
            }

            // Undo the addition of the extra move if the move wasn't applied
            if (!moveApplied)
            {
                this.NotifySetAnimation(BlockAnimationType.ExtraBlockMovedCanceled, false, false);
                parentBlock.AvailableMoves--;
            }

            this.NotifySetAnimation(BlockAnimationType.ExtraBlockIdle, false, false);

            return moveApplied;
        }
Example #24
0
        public override bool ApplyReverseMoveForLoop(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestination,
            Queue<IGameBlock> blockHistory)
        {
            // Failed to find a looped reverse move
            move = null;

            return false;
        }
Example #25
0
        private static void SolveMovements(GameBoard gameBoard, IGameBlockParent sourceBlock, BlockMovement head)
        {
            string key = gameBoard.GetBoardStringFullHashed() + "_" + sourceBlock.IndexRow + "_" + sourceBlock.IndexColumn;

            lock (AlreadyTestedBoards)
            {
                // Already tested this, so don't need to try it again
                if (AlreadyTestedBoards.Contains(key))
                {
                    return;
                }

                AlreadyTestedBoards.Add(key);
            }

            List <MovementDirection> movementDirections = GetDirections();

            bool allFailures = true;

            foreach (MovementDirection direction in movementDirections)
            {
                BlockMovement currentMove = new BlockMovement(sourceBlock, direction);
                BlockMovement headMove;
                if (head != null)
                {
                    headMove = head.CloneFromGameBoard(gameBoard, head);
                    headMove.Enqueue(currentMove);
                }
                else
                {
                    currentMove.Head = currentMove;
                    headMove         = currentMove;
                }

                if (sourceBlock.ApplyMove(null, direction, headMove))
                {
                    allFailures = false;

                    List <IGameBlockParent> leftoverBlocks =
                        gameBoard.GameBlocks.OfType <IGameBlockParent>().Where(g => g.AvailableMoves > 0).ToList();

                    if (leftoverBlocks.Count == 0)
                    {
                        if (gameBoard.HasOrphan())
                        {
                            // failed
                            lock (MyLock)
                            {
                                Failures++;
                            }
                        }
                        else
                        {
                            // succeeded
                            lock (MyLock)
                            {
                                Successes++;
                            }
                        }
                    }
                    else
                    {
                        // Continue to the next move
                        foreach (IGameBlockParent gameBlockParent in leftoverBlocks)
                        {
                            SolveMovements(gameBoard, gameBlockParent, head);
                        }
                    }

                    // Undo move
                    headMove.UndoMove();
                }
            }

            if (allFailures)
            {
                // Any direction, doesn't matter
                BlockMovement currentMove = new BlockMovement(sourceBlock, MovementDirection.Right);
                BlockMovement headMove;
                if (head != null)
                {
                    headMove = head.CloneFromGameBoard(gameBoard, head);
                    headMove.Enqueue(currentMove);
                }
                else
                {
                    currentMove.Head = currentMove;
                    headMove         = currentMove;
                }

                lock (MyLock)
                {
                    Failures++;
                }
            }
        }
Example #26
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);
                }
            }
        }
        public override bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, BlockMovement move)
        {
            // No moves available, so return false (it shouldn't even reach here under normal circumstances)
            if (parentBlock.AvailableMoves == 0)
            {
                return false;
            }

            // If it's trying to do the same move again on this block, it's probably stuck in a loop.
            if (this.lastApplyMoveParentBlock == parentBlock && this.lastApplyMoveDirection == direction)
            {
                return false;
            }

            this.lastApplyMoveParentBlock = parentBlock;
            this.lastApplyMoveDirection = direction;

            bool usedThisBlock = false;

            // This block is available, so fill it
            if (this.IsAvailable)
            {
                this.NotifySetAnimation(this.GetCurrentMoveStartedAnimation(), true, false);

                this.SetAvailability(false);
                parentBlock.AvailableMoves--;
                usedThisBlock = true;

                // No more moves left, so we're done
                if (parentBlock.AvailableMoves == 0)
                {
                    this.NotifySetAnimation(this.GetCurrentMoveAppliedAnimation(), false, false);
                    this.lastApplyMoveParentBlock = null;
                    move.DestinationBlock = this;
                    return true;
                }
            }

            // Otherwise, move to the next block
            bool moveApplied;

            switch (direction)
            {
                default:
                case MovementDirection.Up:
                    if (!usedThisBlock)
                    {
                        this.NotifySetAnimation(SmashUpAnimation, true, false);
                    }

                    if (this.Top == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Top.ApplyMove(parentBlock, direction, move);
                    }
                    break;

                case MovementDirection.Down:
                    if (!usedThisBlock)
                    {
                        this.NotifySetAnimation(SmashDownAnimation, true, false);
                    }

                    if (this.Bottom == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Bottom.ApplyMove(parentBlock, direction, move);
                    }
                    break;

                case MovementDirection.Left:
                    if (!usedThisBlock)
                    {
                        this.NotifySetAnimation(SmashLeftAnimation, true, false);
                    }

                    if (this.Left == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Left.ApplyMove(parentBlock, direction, move);
                    }
                    break;

                case MovementDirection.Right:
                    if (!usedThisBlock)
                    {
                        this.NotifySetAnimation(SmashRightAnimation, true, false);
                    }

                    if (this.Right == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Right.ApplyMove(parentBlock, direction, move);
                    }
                    break;
            }

            // Used this block, but failed the child blocks, so undo the move
            if (usedThisBlock && !moveApplied)
            {
                this.SetAvailability(true);
                parentBlock.AvailableMoves++;
            }

            if (usedThisBlock)
            {
                // If it used this block, either show the block as applied, or as canceled
                if (moveApplied)
                {
                    move.IntermediateBlocks.Insert(0, this);

                    // Applied, so show the block as applied
                    this.NotifySetAnimation(this.GetCurrentMoveAppliedAnimation(), false, false);
                }
                else
                {
                    // If it was canceled, show the canceled animation, then back to the previous animation
                    this.NotifySetAnimation(MoveCanceledAnimation, false, false);
                    this.NotifySetAnimation(this.GetCurrentMoveAppliedAnimation(), false, true);
                }
            }
            else
            {
                this.NotifySetAnimation(this.GetCurrentMoveAppliedAnimation(), false, true);
            }

            this.lastApplyMoveParentBlock = null;
            return moveApplied;
        }
        public override bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, BlockMovement move)
        {
            // If it's already applying the move, this is a loop
            if (this.applyingMove)
            {
                return(false);
            }

            this.applyingMove = true;

            // Move to the next block, always in the forced direction
            bool moveApplied;

            switch (this.forceDirection)
            {
            default:
            case MovementDirection.Up:
                this.NotifySetAnimation(BlockAnimationType.ChangeDirectionMoveStartedUp, true, false);
                this.NotifySetAnimation(BlockAnimationType.ChangeDirectionUp, false, false);

                if (this.Top == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Top.ApplyMove(parentBlock, this.forceDirection, move);
                }
                break;

            case MovementDirection.Down:
                this.NotifySetAnimation(BlockAnimationType.ChangeDirectionMoveStartedDown, true, false);
                this.NotifySetAnimation(BlockAnimationType.ChangeDirectionDown, false, false);

                if (this.Bottom == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Bottom.ApplyMove(parentBlock, this.forceDirection, move);
                }
                break;

            case MovementDirection.Left:
                this.NotifySetAnimation(BlockAnimationType.ChangeDirectionMoveStartedLeft, true, false);
                this.NotifySetAnimation(BlockAnimationType.ChangeDirectionLeft, false, false);

                if (this.Left == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Left.ApplyMove(parentBlock, this.forceDirection, move);
                }
                break;

            case MovementDirection.Right:
                this.NotifySetAnimation(BlockAnimationType.ChangeDirectionMoveStartedRight, true, false);
                this.NotifySetAnimation(BlockAnimationType.ChangeDirectionRight, false, false);

                if (this.Right == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Right.ApplyMove(parentBlock, this.forceDirection, move);
                }
                break;
            }

            this.applyingMove = false;

            return(moveApplied);
        }
Example #29
0
        public override bool ApplyReverseMove(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestinationBlock,
            Queue <IGameBlock> blockHistory)
        {
            move = null;

            // Starting with a non-filled block isn't valid
            if (destinationBlock != null && this.isAvailable)
            {
                return(false);
            }

            // If this is the destination
            bool thisIsFinalMove      = destinationBlock == null;
            int  availableBlocksToUse = this.CountUsedBlocks(directionInReverse, new Dictionary <IGameBlock, IGameBlock>());

            // See if there are enough blocks to do this move
            if (thisIsFinalMove && availableBlocksToUse < numberOfBlocksToMove)
            {
                return(false);
            }
            else if (destinationBlock == this)
            {
                // If it came back around to this block again, then it's in a loop.  It needs to break out.
                return(false);
            }
            else if (blockHistory.Contains(this))
            {
                // If it came back around to this block again, then it's in a loop.  It needs to break out.
                return(false);
            }

            blockHistory.Enqueue(this);

            // Use this block as the destination block if destinationBlock is null
            IGameBlockDestination destination = destinationBlock ?? this;

            bool moveApplied;

            switch (directionInReverse)
            {
            default:
            case MovementDirection.Up:
                if (this.Bottom == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Bottom.ApplyReverseMove(
                        destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                }
                break;

            case MovementDirection.Down:
                if (this.Top == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Top.ApplyReverseMove(
                        destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                }
                break;

            case MovementDirection.Left:
                if (this.Right == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Right.ApplyReverseMove(
                        destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                }
                break;

            case MovementDirection.Right:
                if (this.Left == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Left.ApplyReverseMove(
                        destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                }
                break;
            }

            if (moveApplied && !this.isAvailable && move != null)
            {
                this.IsAvailable = true;
                move.InsertDestinationBlock(this);
                move.SourceBlock.AvailableMoves++;
            }

            return(moveApplied);
        }
        public override bool ApplyReverseMoveForLoop(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestinationBlock,
            Queue <IGameBlock> blockHistory)
        {
            move = null;

            // This block can't be the destination
            if (destinationBlock == null)
            {
                return(false);
            }

            // This block forces the next move to be a certain direction, so depending on what "forceDirection" is,
            // the next move is always going to be the one in that direction.  As a reverse move, previousBlock will
            // need to be the correct block based on this requirement.
            IGameBlock forcedPreviousBlock;

            switch (this.forceDirection)
            {
            default:
            case MovementDirection.Up:
                forcedPreviousBlock = this.Top;
                break;

            case MovementDirection.Down:
                forcedPreviousBlock = this.Bottom;
                break;

            case MovementDirection.Left:
                forcedPreviousBlock = this.Left;
                break;

            case MovementDirection.Right:
                forcedPreviousBlock = this.Right;
                break;
            }

            if (!ReferenceEquals(forcedPreviousBlock, previousBlock))
            {
                return(false);
            }

            bool isPossibleLoopDirection;

            // This is trying to make a loop, so it has to be the opposite direction
            switch (this.forceDirection)
            {
            case MovementDirection.Up:
                isPossibleLoopDirection = directionInReverse == MovementDirection.Down;
                break;

            case MovementDirection.Down:
                isPossibleLoopDirection = directionInReverse == MovementDirection.Up;
                break;

            case MovementDirection.Left:
                isPossibleLoopDirection = directionInReverse == MovementDirection.Right;
                break;

            case MovementDirection.Right:
                isPossibleLoopDirection = directionInReverse == MovementDirection.Left;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            if (!isPossibleLoopDirection)
            {
                return(false);
            }

            blockHistory.Enqueue(this);

            bool moveApplied;

            switch (directionInReverse)
            {
            default:
            case MovementDirection.Up:
                if (this.Bottom == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Bottom.ApplyReverseMove(
                        destinationBlock,
                        directionInReverse,
                        numberOfBlocksToMove,
                        out move,
                        this,
                        previousDestinationBlock,
                        blockHistory);
                }
                break;

            case MovementDirection.Down:
                if (this.Top == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Top.ApplyReverseMove(
                        destinationBlock,
                        directionInReverse,
                        numberOfBlocksToMove,
                        out move,
                        this,
                        previousDestinationBlock,
                        blockHistory);
                }
                break;

            case MovementDirection.Left:
                if (this.Right == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Right.ApplyReverseMove(
                        destinationBlock,
                        directionInReverse,
                        numberOfBlocksToMove,
                        out move,
                        this,
                        previousDestinationBlock,
                        blockHistory);
                }
                break;

            case MovementDirection.Right:
                if (this.Left == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Left.ApplyReverseMove(
                        destinationBlock,
                        directionInReverse,
                        numberOfBlocksToMove,
                        out move,
                        this,
                        previousDestinationBlock,
                        blockHistory);
                }
                break;
            }

            return(moveApplied);
        }
Example #31
0
 public override bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, BlockMovement move)
 {
     return(false);
 }
        public override bool ApplyReverseMove(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestinationBlock,
            Queue<IGameBlock> blockHistory)
        {
            move = null;

            // This block can't be the destination
            if (destinationBlock == null)
            {
                return false;
            }

            // This block forces the next move to be a certain direction, so depending on what "forceDirection" is,
            // the next move is always going to be the one in that direction.  As a reverse move, previousBlock will
            // need to be the correct block based on this requirement.
            IGameBlock forcedPreviousBlock;
            switch (this.forceDirection)
            {
                default:
                case MovementDirection.Up:
                    forcedPreviousBlock = this.Top;
                    break;

                case MovementDirection.Down:
                    forcedPreviousBlock = this.Bottom;
                    break;

                case MovementDirection.Left:
                    forcedPreviousBlock = this.Left;
                    break;

                case MovementDirection.Right:
                    forcedPreviousBlock = this.Right;
                    break;
            }

            if (!ReferenceEquals(forcedPreviousBlock, previousBlock))
            {
                return false;
            }

            blockHistory.Enqueue(this);

            // It can be any direction except for the forced direction, so try any one of the three others
            // until one of them works (at random)
            List<MovementDirection> directions = new List<MovementDirection>
                                                     {
                                                         MovementDirection.Down,
                                                         MovementDirection.Up,
                                                         MovementDirection.Left,
                                                         MovementDirection.Right
                                                     };

            switch (this.forceDirection)
            {
                case MovementDirection.Up:
                    directions.Remove(MovementDirection.Down);
                    break;
                case MovementDirection.Down:
                    directions.Remove(MovementDirection.Up);
                    break;
                case MovementDirection.Left:
                    directions.Remove(MovementDirection.Right);
                    break;
                case MovementDirection.Right:
                    directions.Remove(MovementDirection.Left);
                    break;
            }

            // Shuffle
            Random random = new Random();
            for (int i = 0; i < 3; i++)
            {
                MovementDirection remove = directions[random.Next(0, 2)];
                directions.Remove(remove);
                directions.Add(remove);
            }

            bool moveApplied = false;

            foreach (MovementDirection movementDirectionInReverse in directions)
            {
                switch (movementDirectionInReverse)
                {
                    default:
                    case MovementDirection.Up:
                        if (this.Bottom == null)
                        {
                            moveApplied = false;
                        }
                        else
                        {
                            moveApplied = this.Bottom.ApplyReverseMove(
                                destinationBlock,
                                movementDirectionInReverse,
                                numberOfBlocksToMove,
                                out move,
                                this,
                                previousDestinationBlock,
                                blockHistory);
                        }
                        break;

                    case MovementDirection.Down:
                        if (this.Top == null)
                        {
                            moveApplied = false;
                        }
                        else
                        {
                            moveApplied = this.Top.ApplyReverseMove(
                                destinationBlock,
                                movementDirectionInReverse,
                                numberOfBlocksToMove,
                                out move,
                                this,
                                previousDestinationBlock,
                                blockHistory);
                        }
                        break;

                    case MovementDirection.Left:
                        if (this.Right == null)
                        {
                            moveApplied = false;
                        }
                        else
                        {
                            moveApplied = this.Right.ApplyReverseMove(
                                destinationBlock,
                                movementDirectionInReverse,
                                numberOfBlocksToMove,
                                out move,
                                this,
                                previousDestinationBlock,
                                blockHistory);
                        }
                        break;

                    case MovementDirection.Right:
                        if (this.Left == null)
                        {
                            moveApplied = false;
                        }
                        else
                        {
                            moveApplied = this.Left.ApplyReverseMove(
                                destinationBlock,
                                movementDirectionInReverse,
                                numberOfBlocksToMove,
                                out move,
                                this,
                                previousDestinationBlock,
                                blockHistory);
                        }
                        break;
                }

                // One of the moves worked, so break out
                if (moveApplied)
                {
                    break;
                }
            }

            return moveApplied;
        }
Example #33
0
        public override bool ApplyReverseMoveForLoop(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestinationBlock,
            Queue<IGameBlock> blockHistory)
        {
            move = null;

            // This can't be the final destination block
            if (destinationBlock == null)
            {
                return false;
            }

            // It needs at least 2 previous blocks
            if (previousDestinationBlock == null)
            {
                return false;
            }

            if (destinationBlock == previousDestinationBlock)
            {
                return false;
            }

            bool moveApplied;
            switch (directionInReverse)
            {
                default:
                case MovementDirection.Down:
                    if (this.Bottom == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Bottom.ApplyReverseMoveForLoop(
                            destinationBlock,
                            directionInReverse,
                            numberOfBlocksToMove - 1,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;

                case MovementDirection.Up:
                    if (this.Top == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Top.ApplyReverseMoveForLoop(
                            destinationBlock,
                            directionInReverse,
                            numberOfBlocksToMove - 1,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;

                case MovementDirection.Right:
                    if (this.Right == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Right.ApplyReverseMoveForLoop(
                            destinationBlock,
                            directionInReverse,
                            numberOfBlocksToMove - 1,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;

                case MovementDirection.Left:
                    if (this.Left == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Left.ApplyReverseMoveForLoop(
                            destinationBlock,
                            directionInReverse,
                            numberOfBlocksToMove - 1,
                            out move,
                            this,
                            previousDestinationBlock,
                            blockHistory);
                    }
                    break;
            }

            if (moveApplied)
            {
                // It requires 1 less move if this block is used
                move.SourceBlock.AvailableMoves--;
            }

            return moveApplied;
        }
Example #34
0
        public override bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, BlockMovement move)
        {
            // No moves available, so return false (it shouldn't even reach here under normal circumstances)
            if (parentBlock.AvailableMoves == 0)
            {
                return(false);
            }

            // If it's trying to do the same move again on this block, it's probably stuck in a loop.
            if (this.lastApplyMoveParentBlock == parentBlock && this.lastApplyMoveDirection == direction)
            {
                return(false);
            }

            this.lastApplyMoveParentBlock = parentBlock;
            this.lastApplyMoveDirection   = direction;

            bool usedThisBlock = false;

            // This block is available, so fill it
            if (this.isAvailable)
            {
                this.NotifySetAnimation(MoveStartedAnimation, true, false);

                this.IsAvailable = false;
                parentBlock.AvailableMoves--;
                usedThisBlock = true;

                // No more moves left, so we're done
                if (parentBlock.AvailableMoves == 0)
                {
                    this.NotifySetAnimation(MoveAppliedAnimation, false, false);
                    this.lastApplyMoveParentBlock = null;
                    move.DestinationBlock         = this;
                    return(true);
                }
            }

            // Otherwise, move to the next block
            bool moveApplied;

            switch (direction)
            {
            default:
            case MovementDirection.Up:
                if (!usedThisBlock)
                {
                    this.NotifySetAnimation(SmashUpAnimation, true, false);
                }

                if (this.Top == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Top.ApplyMove(parentBlock, direction, move);
                }
                break;

            case MovementDirection.Down:
                if (!usedThisBlock)
                {
                    this.NotifySetAnimation(SmashDownAnimation, true, false);
                }

                if (this.Bottom == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Bottom.ApplyMove(parentBlock, direction, move);
                }
                break;

            case MovementDirection.Left:
                if (!usedThisBlock)
                {
                    this.NotifySetAnimation(SmashLeftAnimation, true, false);
                }

                if (this.Left == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Left.ApplyMove(parentBlock, direction, move);
                }
                break;

            case MovementDirection.Right:
                if (!usedThisBlock)
                {
                    this.NotifySetAnimation(SmashRightAnimation, true, false);
                }

                if (this.Right == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Right.ApplyMove(parentBlock, direction, move);
                }
                break;
            }

            // Used this block, but failed the child blocks, so undo the move
            if (usedThisBlock && !moveApplied)
            {
                this.IsAvailable = true;
                parentBlock.AvailableMoves++;
            }

            if (usedThisBlock)
            {
                // If it used this block, either show the block as applied, or as canceled
                this.NotifySetAnimation(moveApplied ? MoveAppliedAnimation : MoveCanceledAnimation, false, false);

                if (moveApplied)
                {
                    move.IntermediateBlocks.Insert(0, this);
                }
            }
            else
            {
                // It didn't use this block, so it was already applied.  Put back the applied animation.
                this.NotifySetAnimation(MoveAppliedAnimation, false, true);
            }

            this.lastApplyMoveParentBlock = null;
            return(moveApplied);
        }
Example #35
0
 public abstract bool ApplyReverseMoveForLoop(
     IGameBlockDestination destinationBlock,
     MovementDirection directionInReverse,
     int numberOfBlocksToMove,
     out BlockMovement move,
     IGameBlock previousBlock,
     IGameBlockDestination previousDestination,
     Queue<IGameBlock> blockHistory);
Example #36
0
        public override bool ApplyReverseMoveForLoop(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestination,
            Queue <IGameBlock> blockHistory)
        {
            move = null;

            // There should already be a destination block
            if (destinationBlock == null)
            {
                return(false);
            }

            blockHistory.Enqueue(this);

            bool moveApplied;

            switch (directionInReverse)
            {
            default:
            case MovementDirection.Down:
                if (this.Bottom == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Bottom.ApplyReverseMoveForLoop(
                        destinationBlock, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                }
                break;

            case MovementDirection.Up:
                if (this.Top == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Top.ApplyReverseMoveForLoop(
                        destinationBlock, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                }
                break;

            case MovementDirection.Right:
                if (this.Right == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Right.ApplyReverseMoveForLoop(
                        destinationBlock, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                }
                break;

            case MovementDirection.Left:
                if (this.Left == null)
                {
                    moveApplied = false;
                }
                else
                {
                    moveApplied = this.Left.ApplyReverseMoveForLoop(
                        destinationBlock, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                }
                break;
            }

            if (moveApplied && !this.isAvailable && move != null)
            {
                this.IsAvailable = true;
                move.InsertDestinationBlock(this);
                move.SourceBlock.AvailableMoves++;
            }

            return(moveApplied);
        }
Example #37
0
        public BlockMovement CloneFromGameBoard(GameBoard gameBoard, BlockMovement previous)
        {
            BlockMovement clone =
                new BlockMovement(
                    gameBoard.GameBlocks[this.sourceBlock.IndexRow, this.sourceBlock.IndexColumn] as IGameBlockParent, this.direction);

            if (this.destinationBlock != null)
            {
                clone.destinationBlock =
                    gameBoard.GameBlocks[this.destinationBlock.IndexRow, this.destinationBlock.IndexColumn] as IGameBlockDestination;
            }

            foreach (IGameBlockDestination intermediateBlock in this.intermediateBlocks)
            {
                if (intermediateBlock != null)
                {
                    clone.intermediateBlocks.Add(
                        gameBoard.GameBlocks[intermediateBlock.IndexRow, intermediateBlock.IndexColumn] as IGameBlockDestination);
                }
            }

            clone.previousMove = previous;
            clone.head = previous == null ? this : previous.head;
            clone.originalAvailableMoves = this.originalAvailableMoves;

            if (this.nextMove != null)
            {
                clone.nextMove = this.nextMove.CloneFromGameBoard(gameBoard, clone);
            }

            return clone;
        }
Example #38
0
        public override bool ApplyReverseMoveForLoop(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestination,
            Queue<IGameBlock> blockHistory)
        {
            move = null;

            // There should already be a destination block
            if (destinationBlock == null)
            {
                return false;
            }

            blockHistory.Enqueue(this);

            bool moveApplied;
            switch (directionInReverse)
            {
                default:
                case MovementDirection.Down:
                    if (this.Bottom == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Bottom.ApplyReverseMoveForLoop(
                            destinationBlock, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                    break;

                case MovementDirection.Up:
                    if (this.Top == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Top.ApplyReverseMoveForLoop(
                            destinationBlock, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                    break;

                case MovementDirection.Right:
                    if (this.Right == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Right.ApplyReverseMoveForLoop(
                            destinationBlock, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                    break;

                case MovementDirection.Left:
                    if (this.Left == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Left.ApplyReverseMoveForLoop(
                            destinationBlock, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                    break;
            }

            if (moveApplied && !this.isAvailable && move != null)
            {
                this.IsAvailable = true;
                move.InsertDestinationBlock(this);
                move.SourceBlock.AvailableMoves++;
            }

            return moveApplied;
        }
Example #39
0
 public void Enqueue(BlockMovement blockMovement)
 {
     BlockMovement lastMovement = this.GetLastMovement();
     blockMovement.PreviousMove = lastMovement;
     lastMovement.NextMove = blockMovement;
 }
        public override bool ApplyReverseMoveForLoop(
            IGameBlockDestination destinationBlock,
            MovementDirection directionInReverse,
            int numberOfBlocksToMove,
            out BlockMovement move,
            IGameBlock previousBlock,
            IGameBlockDestination previousDestination,
            Queue<IGameBlock> blockHistory)
        {
            move = null;

            // Starting with a non-filled block isn't valid
            if (destinationBlock != null && this.numberOfMovesApplied == 0)
            {
                return false;
            }

            // If this is the destination
            bool thisIsFinalMove = destinationBlock == null;
            int availableBlocksToUse = this.CountUsedBlocks(directionInReverse, new Dictionary<IGameBlock, IGameBlock>());

            // See if there are enough blocks to do this move
            if (thisIsFinalMove && availableBlocksToUse < numberOfBlocksToMove)
            {
                return false;
            }

            // Use this block as the destination block if destinationBlock is null
            IGameBlockDestination destination = destinationBlock ?? this;

            blockHistory.Enqueue(this);

            bool moveApplied;
            switch (directionInReverse)
            {
                default:
                case MovementDirection.Up:
                    if (this.Top == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Top.ApplyReverseMoveForLoop(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                    break;

                case MovementDirection.Down:
                    if (this.Bottom == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Bottom.ApplyReverseMoveForLoop(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                    break;

                case MovementDirection.Left:
                    if (this.Left == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Left.ApplyReverseMoveForLoop(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                    break;

                case MovementDirection.Right:
                    if (this.Right == null)
                    {
                        moveApplied = false;
                    }
                    else
                    {
                        moveApplied = this.Right.ApplyReverseMoveForLoop(
                            destination, directionInReverse, numberOfBlocksToMove, out move, this, this, blockHistory);
                    }
                    break;
            }

            if (moveApplied && !this.IsFullyAvailable && move != null)
            {
                this.SetAvailability(true);
                move.InsertDestinationBlock(this);
                move.SourceBlock.AvailableMoves++;
            }

            return moveApplied;
        }
Example #41
0
        public object Clone()
        {
            BlockMovement clone = new BlockMovement(this.sourceBlock, this.direction);
            clone.intermediateBlocks.AddRange(this.intermediateBlocks);
            clone.destinationBlock = this.destinationBlock;
            clone.previousMove = this.previousMove;
            clone.head = this.head;
            clone.originalAvailableMoves = this.originalAvailableMoves;

            if (this.nextMove != null)
            {
                clone.nextMove = (BlockMovement)this.nextMove.Clone();
            }

            return clone;
        }