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); }
public void Enqueue(BlockMovement blockMovement) { BlockMovement lastMovement = this.GetLastMovement(); blockMovement.PreviousMove = lastMovement; lastMovement.NextMove = blockMovement; }
public abstract bool ApplyReverseMoveForLoop( IGameBlockDestination destinationBlock, MovementDirection directionInReverse, int numberOfBlocksToMove, out BlockMovement move, IGameBlock previousBlock, IGameBlockDestination previousDestination, Queue <IGameBlock> blockHistory);
public BlockMovement GetLastMovement() { BlockMovement last = this; while (last.NextMove != null) { last = last.nextMove; } return(last); }
public override bool ApplyReverseMoveForLoop( IGameBlockDestination destinationBlock, MovementDirection directionInReverse, int numberOfBlocksToMove, out BlockMovement move, IGameBlock previousBlock, IGameBlockDestination previousDestination, Queue <IGameBlock> blockHistory) { move = null; return(false); }
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; }
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); }
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); }
/// <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()); }
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()); }
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; }
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; }
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; }
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; }
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); }
public abstract bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, BlockMovement move);
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); }
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; }
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++; } } }
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); }
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); }
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; }
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); }
public abstract bool ApplyReverseMoveForLoop( IGameBlockDestination destinationBlock, MovementDirection directionInReverse, int numberOfBlocksToMove, out BlockMovement move, IGameBlock previousBlock, IGameBlockDestination previousDestination, Queue<IGameBlock> blockHistory);
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); }
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; }
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; }
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; }
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; }