public abstract bool ApplyReverseMoveForLoop( IGameBlockDestination destinationBlock, MovementDirection directionInReverse, int numberOfBlocksToMove, out BlockMovement move, IGameBlock previousBlock, IGameBlockDestination previousDestination, Queue <IGameBlock> blockHistory);
public BlockMovement(IGameBlockParent sourceBlock, MovementDirection direction) { this.sourceBlock = sourceBlock; this.destinationBlock = null; this.direction = direction; this.intermediateBlocks = new List <IGameBlockDestination>(); this.originalAvailableMoves = sourceBlock == null ? 0 : sourceBlock.AvailableMoves; }
public BlockMovement(IGameBlockParent sourceBlock, MovementDirection direction) { this.sourceBlock = sourceBlock; this.destinationBlock = null; this.direction = direction; this.intermediateBlocks = new List<IGameBlockDestination>(); this.originalAvailableMoves = sourceBlock == null ? 0 : sourceBlock.AvailableMoves; }
public void InsertDestinationBlock(IGameBlockDestination destination) { // Move the destinationBlock into the intermediateBlocks if (this.destinationBlock != null) { this.intermediateBlocks.Add(this.destinationBlock); } this.destinationBlock = destination; }
public override bool ApplyReverseMoveForLoop( IGameBlockDestination destinationBlock, MovementDirection directionInReverse, int numberOfBlocksToMove, out BlockMovement move, IGameBlock previousBlock, IGameBlockDestination previousDestination, Queue <IGameBlock> blockHistory) { move = null; return(false); }
private static void Shuffle(List <IGameBlockDestination> numbers, int timesToShuffle) { int maxIndex = numbers.Count - 1; for (int i = 0; i < timesToShuffle; i++) { int index1 = RandomGenerator.Next(0, maxIndex); int index2 = RandomGenerator.Next(0, maxIndex); IGameBlockDestination temp = numbers[index1]; numbers[index1] = numbers[index2]; numbers[index2] = temp; } }
public bool HasOrphan() { bool hasOrphan = false; foreach (IGameBlock gameBlock in this.gameBlocks) { IGameBlockDestination gameBlockNormal = gameBlock as IGameBlockDestination; if (gameBlockNormal != null && gameBlockNormal.IsOrphaned()) { hasOrphan = true; break; } } return(hasOrphan); }
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 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 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 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); }
/// <summary> /// Reverses the solve. /// </summary> /// <param name="gameBoard">The game board.</param> /// <param name="maxCountAtPlayer">The max count at player.</param> /// <param name="maxNumberOfSolutions">The max number of solutions.</param> /// <param name="variability">The variability.</param> /// <param name="milliSecondsTimeout">The milli seconds timeout.</param> /// <param name="aborted">if set to <c>true</c> [aborted].</param> /// <returns></returns> public static List <GameBoard> ReverseSolve( GameBoard gameBoard, int maxCountAtPlayer, int maxNumberOfSolutions, int variability, int milliSecondsTimeout, out bool aborted) { RequestAbort = false; AlreadyTestedBoards = new HashSet <string>(); Dictionary <string, GameBoard> solutionGameBoards = new Dictionary <string, GameBoard>(); List <Thread> threads = new List <Thread>(); List <IGameBlockDestination> destinations = new List <IGameBlockDestination>(); foreach (IGameBlock gameBlock in gameBoard.GameBlocks) { IGameBlockDestination nextDestination = gameBlock as IGameBlockDestination; if (nextDestination != null) { destinations.Add(gameBlock as IGameBlockDestination); } } Shuffle(destinations, destinations.Count); foreach (IGameBlockDestination gameBlock in destinations) { GameBoard gameBoardClone = (GameBoard)gameBoard.Clone(); IGameBlockDestination gameBlockClone = gameBoardClone.GameBlocks[gameBlock.IndexRow, gameBlock.IndexColumn] as IGameBlockDestination; // Parallel process the solutions ThreadStart threadStart = () => { int stepsBack = 0; ReverseSolveMovements( gameBoardClone, gameBlockClone, null, maxCountAtPlayer, maxNumberOfSolutions, variability, ref stepsBack, null, solutionGameBoards); }; Thread threadFunction = new Thread(threadStart); threads.Add(threadFunction); threadFunction.Start(); } // Wait for the threads to finish foreach (Thread thread in threads) { thread.Join(milliSecondsTimeout); // Took too long so abort it if (thread.IsAlive) { thread.Abort(); } } NotifySolveSolutionStartedEvent(); // Clear it to take back memory AlreadyTestedBoards = new HashSet <string>(); GC.Collect(); if (AnalyzeImmediately) { foreach (KeyValuePair <string, GameBoard> solutionGameBoard in solutionGameBoards) { int fails; int successes; GameBoardSolver.Solve(solutionGameBoard.Value, milliSecondsTimeout * 4, out fails, out successes); solutionGameBoard.Value.Failures = fails; solutionGameBoard.Value.Successes = successes; NotifyAnalyzedSolutionEvent(); } } NotifySolveSolutionEndedEvent(); aborted = RequestAbort; RequestAbort = false; return(solutionGameBoards.Values.ToList()); }
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; }
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; } } } }
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 abstract bool ApplyReverseMoveForLoop( IGameBlockDestination destinationBlock, MovementDirection directionInReverse, int numberOfBlocksToMove, out BlockMovement move, IGameBlock previousBlock, IGameBlockDestination previousDestination, Queue<IGameBlock> blockHistory);
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 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 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 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 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 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 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; }