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 OnCancelMove() { IGameBlockParent gameBlockParent = this.GameBlock as IGameBlockParent; if (gameBlockParent != null) { this.LoadImage(); } this.lastDirection = null; }
public void NullZeroPlayers() { for (int i = 0; i < this.gameBlocks.GetLength(0); i++) { for (int j = 0; j < this.gameBlocks.GetLength(1); j++) { IGameBlockParent gameBlockParent = this.gameBlocks[i, j] as IGameBlockParent; if (gameBlockParent != null && gameBlockParent.AvailableMoves == 0) { this.gameBlocks[i, j] = null; } } } }
public void OnMoving(MovementDirection direction, float pixels) { if (this.lastDirection == null || this.lastDirection != direction) { this.lastDirection = direction; IGameBlockParent gameBlockParent = this.GameBlock as IGameBlockParent; if (gameBlockParent != null) { if (gameBlockParent.AvailableMoves > 0) { BlockAnimationType animationType = gameBlockParent.GetPreparingMoveAnimation(direction); GameObject animationObject = this.animationMappingsDictionary[animationType]; this.SetAnimation(animationObject, true, false); } } } }
public bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, out BlockMovement move) { if (this.GameBlock == null) { move = null; return(false); } move = new BlockMovement(this.GameBlock as IGameBlockParent, direction); bool appliedMove = this.GameBlock.ApplyMove(parentBlock, direction, move); // Disable the TutorialAnimation once the move is applied foreach (Transform child in transform) { if (child.tag.Equals("TutorialAnimation")) { child.gameObject.SetActive(false); } } return(appliedMove); }
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 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) { // 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) { // 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 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; }
public static void Solve(GameBoard gameBoard, int milliSecondsTimeout, out int failures, out int successes) { Failures = 0; Successes = 0; AlreadyTestedBoards = new HashSet <string>(); List <Thread> threads = new List <Thread>(); foreach (IGameBlockParent gameBlock in gameBoard.GameBlocks.OfType <IGameBlockParent>()) { GameBoard gameBoardClone = (GameBoard)gameBoard.Clone(); IGameBlockParent gameBlockClone = gameBoardClone.GameBlocks[gameBlock.IndexRow, gameBlock.IndexColumn] as IGameBlockParent; // Parallel process the solutions ThreadStart threadStart = () => SolveMovements(gameBoardClone, gameBlockClone, null); Thread threadFunction = new Thread(threadStart); threads.Add(threadFunction); } List <Thread> runningThreads = new List <Thread>(); while (threads.Count > 0) { // Limit running threads to 8 for (int i = 0; i < 8 - runningThreads.Count && i < threads.Count; i++) { threads[i].Start(); runningThreads.Add(threads[i]); threads.Remove(threads[i]); } List <Thread> finishedThreads = new List <Thread>(); // Remove any threads that finished foreach (Thread runningThread in runningThreads) { bool joined = runningThread.Join(1000); if (joined) { finishedThreads.Add(runningThread); } } foreach (Thread finishedThread in finishedThreads) { runningThreads.Remove(finishedThread); } } // Wait for the threads to finish foreach (Thread thread in runningThreads) { thread.Join(milliSecondsTimeout); // Took too long so abort it if (thread.IsAlive) { thread.Abort(); } } failures = Failures; successes = Successes; AlreadyTestedBoards = new HashSet <string>(); GC.Collect(); }
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++; } } }
public abstract bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, BlockMovement move);
public override bool ApplyMove(IGameBlockParent parentBlock, MovementDirection direction, BlockMovement move) { return(false); }
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 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; }