private List <Vector2> CalcDestinations(
            PieceEV pieceEV,
            List <PieceEV> allPieces,
            IEntitiesDB entitiesDB,
            bool excludeCheckViolations        = false,
            bool excludeObstructedDestinations = true)
        {
            bool       useGoldMovement = IsOpponentPieceDirectlyBelow(pieceEV, allPieces);
            IPieceData pieceData       = CreatePieceData(pieceEV, useGoldMovement);

            List <Vector2> returnValue = AdjustAndExcludeSingleDestinations(
                pieceData,
                pieceEV,
                allPieces,
                excludeObstructedDestinations);

            returnValue.AddRange(AdjustJumpDestinations(
                                     pieceData,
                                     pieceEV,
                                     allPieces
                                     ));

            returnValue.AddRange(AdjustAndExcludeLineDestinations(
                                     pieceData,
                                     pieceEV,
                                     allPieces,
                                     excludeObstructedDestinations));

            if (excludeCheckViolations) // Should only happen for turn player
            {
                ExcludeCheckViolations(pieceEV, returnValue, allPieces, entitiesDB);
            }

            return(returnValue);
        }
        private IEnumerable <Vector2> AdjustAndExcludeLineDestinations(
            IPieceData pieceData,
            PieceEV pieceEV,
            List <PieceEV> allPieces,
            bool excludeObstructedDestinations)
        {
            int            tier        = CalcTierToUse(pieceEV, allPieces);
            List <Vector2> vectors     = pieceData.Tiers[tier - 1].Line;
            List <Vector2> returnValue = new List <Vector2>();

            foreach (Vector2 vector in vectors)
            {
                List <Vector2> line = ExpandLineVector(vector);
                AdjustRawDataWithPieceLocationAndDirection(pieceEV, line);
                ExcludeOutOfBoard(line);

                if (excludeObstructedDestinations) // Do NOT allow destinations other pieces in the way
                {
                    ExcludeDestinationsWithObstructingPieces(pieceEV, line, allPieces);
                }

                // Always exclude these scenarios
                ExcludeDestinationsAtCannotBeStackedPieces(line, allPieces);
                ExcludeTowerDestinationsWithSameTypeAndTeam(pieceEV, line, allPieces);

                returnValue.AddRange(line);
            }

            return(returnValue);
        }
        public bool ForcedRearrangementCanResolveThreats(
            PieceEV commander, PieceEV pieceToDrop, List <PieceEV> actualThreats, List <PieceEV> allPieces, IEntitiesDB entitiesDB)
        {
            bool returnValue = false;

            // Test drop each valid location to see if threats resolved
            for (int rank = turnService.GetMinRankWithinTerritory(commander.PlayerOwner.PlayerColor); rank <= turnService.GetMaxRankWithinTerritory(commander.PlayerOwner.PlayerColor); ++rank)
            {
                for (int file = 0; file < BoardConst.NUM_FILES_RANKS; ++file)
                {
                    Vector2        location         = new Vector2(file, rank);
                    List <PieceEV> piecesAtLocation = pieceFindService.FindPiecesByLocation(location, entitiesDB);

                    if (IsValidDrop(piecesAtLocation, entitiesDB) &&
                        DoesDropResolveCheck(
                            commander, pieceToDrop, location, piecesAtLocation, actualThreats, allPieces, entitiesDB))
                    {
                        returnValue = true;
                        break;
                    }
                }
            }

            return(returnValue);
        }
        private bool CheckDropToken(ref HandPieceEV handPiece, ref TileEV destinationTile, PieceSide?sideToCheck)
        {
            TurnEV  currentTurn = turnService.GetCurrentTurnEV(entitiesDB);
            PieceEV pieceToDrop = pieceFindService.FindFirstPieceByLocationAndType(
                BoardConst.HAND_LOCATION, handPiece.HandPiece.PieceType, handPiece.HandPiece.Back, entitiesDB);
            bool returnValue = !currentTurn.Check.CommanderInCheck;

            if (!returnValue) // Commander is in check
            {
                bool singleSideValid = sideToCheck.HasValue && checkService.DropReleasesCheck(
                    pieceToDrop,
                    destinationTile.Location.Location,
                    currentTurn,
                    sideToCheck.Value,
                    entitiesDB);

                bool eitherSideValid = !sideToCheck.HasValue && (
                    checkService.DropReleasesCheck(
                        pieceToDrop,
                        destinationTile.Location.Location,
                        currentTurn,
                        PieceSide.FRONT,
                        entitiesDB) ||
                    checkService.DropReleasesCheck(
                        pieceToDrop,
                        destinationTile.Location.Location,
                        currentTurn,
                        PieceSide.BACK,
                        entitiesDB));

                returnValue = singleSideValid || eitherSideValid;
            }

            return(returnValue);
        }
Пример #5
0
        private bool IsValidEarthLinkDrop(List <PieceEV> piecesAtLocation, PieceSide?side)
        {
            // Since this is called after IsEmptyTile with an OR condition, we know there is at least one piece on the tile
            PieceEV topPiece = piecesAtLocation[piecesAtLocation.Count - 1];

            return(topPiece.Tier.Tier < 3 && AbilityToPiece.HasAbility(GetEarthLinkAbilityType(side), topPiece.Piece.PieceType));
        }
        private List <PieceEV> FindEnemyThreats(PieceEV commander, PieceEV pieceToMove, List <PieceEV> allPieces, IEntitiesDB entitiesDB)
        {
            List <PieceEV> enemyPieces = allPieces.Where(piece =>
                                                         piece.PlayerOwner.PlayerColor != commander.PlayerOwner.PlayerColor).ToList();
            List <PieceEV> piecesAtCurrentLocation = allPieces.Where(piece => // Min size one
                                                                     piece.Location.Location == pieceToMove.Location.Location).ToList();

            List <PieceEV> returnValue = enemyPieces.Where(piece =>
                                                           piece.Tier.TopOfTower &&
                                                           (piece.Location.Location == commander.Location.Location ||
                                                            CalcUnobstructedDestinationTiles(piece, allPieces, entitiesDB).Contains(commander.Location.Location))
                                                           )
                                         .ToList();

            // One more scenario: Moving the pieceToMove could expose the underlying enemy piece that could check the Commander
            // That piece is UNABLE check the commander if other pieces obstruct it
            if (piecesAtCurrentLocation.Count > 1)
            {
                PieceEV pieceToEvaluate = piecesAtCurrentLocation[piecesAtCurrentLocation.Count - 2];

                if (pieceToEvaluate.PlayerOwner.PlayerColor != commander.PlayerOwner.PlayerColor &&
                    CalcUnobstructedDestinationTiles(pieceToEvaluate, allPieces, entitiesDB).Contains(commander.Location.Location))
                {
                    returnValue.Add(pieceToEvaluate);
                }
            }

            return(returnValue);
        }
Пример #7
0
        private void OnPressed(int entityId, int pieceReferenceId)
        {
            PieceEV          piece      = FindAssociatedPiece(pieceReferenceId);
            TowerAnswerState nextAction = DecideNextAction(piece);

            PerformNextAction(nextAction, piece);
        }
        public int CalcNumCommanderThreats(PlayerColor commanderColor, IEntitiesDB entitiesDB)
        {
            int            returnValue          = 0;
            PieceEV        commander            = pieceFindService.FindCommander(commanderColor, entitiesDB);
            List <PieceEV> allPieces            = pieceFindService.FindAllBoardPieces(entitiesDB).ToList();
            List <PieceEV> commanderTowerPieces = pieceFindService.FindPiecesByLocation(commander.Location.Location, entitiesDB);

            if (IsCommanderBuried(commander, commanderTowerPieces))
            {
                // Commander cannot be captured this turn
                return(returnValue);
            }

            if (IsCommanderInDangerFromBelow(commander, commanderTowerPieces))
            {
                returnValue++;
            }

            if (commander.Tier.TopOfTower)
            {
                List <PieceEV> enemyPieces = allPieces.Where(piece =>
                                                             piece.PlayerOwner.PlayerColor != commanderColor && piece.Tier.TopOfTower).ToList();

                foreach (PieceEV enemy in enemyPieces)
                {
                    if (CalcDestinationTileLocations(enemy, entitiesDB, allPieces, false).Contains(commander.Location.Location))
                    {
                        returnValue++;
                    }
                }
            }

            return(returnValue);
        }
        private bool ShouldRemoveDestination(
            PieceEV pieceToCalc, Vector2 destination, List <PieceEV> allPieces, bool canIgnoreFriendlyPieces)
        {
            bool    returnValue   = false;
            Vector2 pieceLocation = pieceToCalc.Location.Location;

            Vector2 increment = new Vector2(
                pieceLocation.x == destination.x ?
                0 : (pieceLocation.x - destination.x) / Math.Abs(pieceLocation.x - destination.x),
                pieceLocation.y == destination.y ?
                0 : (pieceLocation.y - destination.y) / Math.Abs(pieceLocation.y - destination.y)
                );

            Vector2 evalLocation = pieceLocation - increment;

            while (evalLocation != destination)
            {
                int numPiecesBarringPath = allPieces.Where(piece =>
                                                           evalLocation == piece.Location.Location &&
                                                           (!canIgnoreFriendlyPieces ||
                                                            (piece.PlayerOwner.PlayerColor != pieceToCalc.PlayerOwner.PlayerColor ||
                                                             (piece.Tier.TopOfTower && AbilityToPiece.HasAbility(PreMoveAbility.CANNOT_BE_STACKED, piece.Piece.PieceType)))
                                                           )).Count();

                if (numPiecesBarringPath > 0)
                {
                    returnValue = true;
                    break;
                }

                evalLocation -= increment;
            }

            return(returnValue);
        }
        /**
         * Potentially modify param destinations, by removing locations with piece(s) in the way
         *
         * Some destinations are in different rank AND file as pieceToCalc's current location
         */
        private void ExcludeDestinationsWithObstructingPieces(
            PieceEV pieceToCalc,
            List <Vector2> destinations,
            List <PieceEV> allPieces,
            bool canIgnoreFriendlyPieces = false)
        {
            List <Vector2> destinationsToRemove = new List <Vector2>();

            /*
             * Types of destinations
             * * One tile away, horizontally, vertically, or diagonally
             * More than one tile away,
             * * Same rank, different file
             * * Same file, different rank
             * * Different rank, different file
             */

            // for loop hopLocations, since that count will often be less than allPiece's count
            foreach (Vector2 destination in destinations)
            {
                if (ShouldRemoveDestination(pieceToCalc, destination, allPieces, canIgnoreFriendlyPieces))
                {
                    destinationsToRemove.Add(destination);
                }
            }

            foreach (Vector2 removeDestination in destinationsToRemove)
            {
                destinations.Remove(removeDestination);
            }
        }
 private int CalcTierToUse(PieceEV piece, List <PieceEV> allPieces)
 {
     return(CanMobileRangeExpansion(piece) &&
            (IsAffectedByMobileRangeExpansionRadial(piece.PlayerOwner.PlayerColor, piece.Location.Location, allPieces) ||
             IsAffectedByMobileRangeExpansionLine(piece.PlayerOwner.PlayerColor, piece.Location.Location, allPieces))
         ? Math.Min(piece.Tier.Tier + 1, 3) : piece.Tier.Tier);
 }
        private void MovePawnToHand(PieceEV piece)
        {
            pieceSetService.SetPieceLocationToHandLocation(piece, entitiesDB);
            piece.Visibility.IsVisible.value = false;

            handService.AddPieceToHand(piece, entitiesDB);
        }
Пример #13
0
        public bool IsSubstitutionPossible(PieceEV?clickedPiece, TileEV?clickedTile, IEntitiesDB entitiesDB)
        {
            // Remember, Commander cannot run to Samurai during check, b/c that's a violation of a different rule

            /* Conditions:
             *      piece clicked
             *      not a destination tile (user is clicking this piece to access substitution ability or click-highlight it)
             *      commander in check
             *      samurai (has substitution ability)
             *      piece is topOfTower
             *      piece tier == 1
             *      piece is adjacent to Commander vertically or horizontally
             *      substitution would resolve check
             */

            TurnEV  currentTurn = turnService.GetCurrentTurnEV(entitiesDB);
            PieceEV commander   = pieceFindService.FindCommander(currentTurn.TurnPlayer.PlayerColor, entitiesDB);

            return(currentTurn.Check.CommanderInCheck &&
                   clickedPiece.HasValue &&
                   clickedTile.HasValue &&
                   (!clickedTile.Value.Tile.PieceRefEntityId.HasValue || clickedTile.Value.Tile.PieceRefEntityId.Value == 0) &&
                   AbilityToPiece.HasAbility(OtherMoveAbility.SUBSTITUTION, clickedPiece.Value.Piece.PieceType) &&
                   clickedPiece.Value.Tier.Tier == 1 &&
                   clickedPiece.Value.Tier.TopOfTower &&
                   IsAdjacentLocationToCommander(clickedPiece.Value, commander) &&
                   DoesSubstitutionResolveCheck(clickedPiece.Value, commander, entitiesDB));
        }
        private bool DropPossible(
            HandPieceEV handPiece, Vector2 location, PlayerColor playerColor, DropCheckmateLevel recursionLevel, IEntitiesDB entitiesDB)
        {
            List <PieceEV> piecesAtLocation = pieceFindService.FindPiecesByLocation(location, entitiesDB);
            bool           isFrontValid     = preDropService.IsValidFrontDrop(ref handPiece, location, piecesAtLocation, entitiesDB);
            bool           isBackValid      = preDropService.IsValidBackDrop(ref handPiece, location, piecesAtLocation, entitiesDB);
            PieceEV        pieceToDrop      = pieceFindService.FindFirstPieceByLocationAndType(
                BoardConst.HAND_LOCATION, handPiece.HandPiece.PieceType, handPiece.HandPiece.Back, entitiesDB);

            return((isFrontValid && DropReleasesCheck(
                        pieceToDrop,
                        location,
                        playerColor,
                        PieceSide.FRONT,
                        handPiece,
                        recursionLevel,
                        entitiesDB)) ||
                   (isBackValid && DropReleasesCheck(
                        pieceToDrop,
                        location,
                        playerColor,
                        PieceSide.BACK,
                        handPiece,
                        recursionLevel,
                        entitiesDB)));
        }
Пример #15
0
        public void Step(ref CapturePieceStepState token, int condition)
        {
            PieceEV pieceToCapture = token.PieceToCapture;

            pieceSetService.SetPieceLocationToHandLocation(pieceToCapture, entitiesDB);
            pieceToCapture.Visibility.IsVisible.value = false;
        }
Пример #16
0
        private void ChangeTileColor(List <TileEV> tilesToChange, ref PressStepState token)
        {
            bool           isClicked                   = token.PiecePressState == PiecePressState.CLICKED;
            PieceEV        piece                       = pieceFindService.FindPieceEV(token.PieceEntityId, entitiesDB);
            int            pieceIdtoken                = token.PieceEntityId;
            HighlightState newHighlightState           = HighlightService.CalcClickHighlightState(piece.PlayerOwner.PlayerColor);
            TurnEV         currentTurn                 = turnService.GetCurrentTurnEV(entitiesDB);
            bool           doesPieceBelongToTurnPlayer = currentTurn.TurnPlayer.PlayerColor == piece.PlayerOwner.PlayerColor;

            foreach (TileEV tileEV in tilesToChange)
            {
                entitiesDB.ExecuteOnEntity(
                    tileEV.ID,
                    (ref TileEV tileToChange) =>
                {
                    tileToChange.Highlight.IsHighlighted = isClicked;

                    if (doesPieceBelongToTurnPlayer)
                    {
                        tileToChange.Tile.PieceRefEntityId = isClicked ? (int?)pieceIdtoken : null;
                    }

                    if (isClicked)
                    {
                        tileToChange.Highlight.CurrentColorStates.Add(newHighlightState);
                    }
                    else
                    {
                        tileToChange.Highlight.CurrentColorStates.Remove(newHighlightState);
                    }
                });

                tileEV.ChangeColorTrigger.PlayChangeColor = true;
            }
        }
        private bool ImmobileCapturePossible(PieceEV piece, PlayerColor playerColor, IEntitiesDB entitiesDB)
        {
            List <PieceEV> towerPieces = pieceFindService.FindPiecesByLocation(piece.Location.Location, entitiesDB);

            return(immobileCaptureService.ImmobileCapturePossible(towerPieces, playerColor, entitiesDB) &&
                   immobileCaptureService.NoCheckViolationsExist(towerPieces, true, entitiesDB));
        }
Пример #18
0
        public bool DropReleasesCheck(
            PieceEV pieceToDrop,
            Vector2 location,
            TurnEV turn,
            PieceSide side,
            IEntitiesDB entitiesDB)
        {
            bool returnValue = false;

            PieceEV?topPieceAtLocation = pieceFindService.FindTopPieceByLocation(location, entitiesDB);

            pieceSetService.SetTopOfTowerToFalse(topPieceAtLocation, entitiesDB);

            int tier = topPieceAtLocation.HasValue ? topPieceAtLocation.Value.Tier.Tier + 1 : 1;

            pieceSetService.SetPieceLocationAndTier(pieceToDrop, location, tier, entitiesDB);
            pieceSetService.SetPiecePlayerOwner(pieceToDrop, turn.TurnPlayer.PlayerColor, entitiesDB);
            pieceSetService.SetPieceSide(pieceToDrop, side, entitiesDB);

            returnValue = !IsCommanderInCheck(turn.TurnPlayer.PlayerColor, entitiesDB);

            pieceSetService.SetPieceLocationToHandLocation(pieceToDrop, entitiesDB);

            if (topPieceAtLocation.HasValue)
            {
                pieceSetService.SetTopOfTower(topPieceAtLocation.Value, entitiesDB);
            }

            return(returnValue);
        }
Пример #19
0
        public bool DoesLowerTierThreatenCommander(
            PieceEV commander, PieceEV enemyPiece, PieceEV secondFromTopEnemyPiece, List <PieceEV> towerPieces, IEntitiesDB entitiesDB)
        {
            // If middle piece is lance, Forced Rearrangement could potentially resolve or prevent check
            // NOTE: Below foreach loop causes invalid tier values, I'm just too lazy too deal with it right now
            foreach (PieceEV piece in towerPieces)
            {
                piece.Tier.Tier--;
            }

            bool returnValue = commander.Tier.TopOfTower &&
                               destinationTileService.CalcDestinationTileLocations(enemyPiece, entitiesDB, null, false).Contains(commander.Location.Location);

            if (returnValue && IsForcedRearrangementPossible(secondFromTopEnemyPiece))
            {
                returnValue = DoesForcedRearrangementResolveOrPreventCheck(
                    secondFromTopEnemyPiece, commander, towerPieces, entitiesDB);
            }

            foreach (PieceEV piece in towerPieces)
            {
                piece.Tier.Tier++;
            }

            return(returnValue);
        }
        private void LoadSavedGame()
        {
            string fileName = "saved_game.txt";

            if (isMobile)
            {
                fileName = Path.Combine(persistentDataPath, fileName);
            }

            // For simplicity, I'm not error checking this file.
            string[] lines = File.ReadAllLines(fileName);
            SetTurnStatus(lines[0]);

            int index = 1;

            while (index < lines.Length && IsHandPieceLine(lines[index]))
            {
                string[] data = lines[index].Split(',');
                MovePiecesToHand(data);

                index++;
            }

            List <PieceEV> pieces = pieceFindService.FindAllBoardPieces(entitiesDB).ToList();

            for (; index < lines.Length; ++index)
            {
                string[] data = lines[index].Split(',');
                PieceEV  pieceToRemoveFromList = PositionPiece(data, pieces);
                pieces.Remove(pieceToRemoveFromList); // Prevent future line from re-position already-positioned piece
            }
        }
        private bool IsImmobileCapturePossible(PieceEV piece, List <PieceEV> piecesAtLocation, TurnEV currentTurn)
        {
            // TODO Immobile capture issues should only be a potential problem if the pieceToCapture has Mobile Range Expansion (since top piece is friendly)
            bool immobileCapturePossible = immobileCaptureService.ImmobileCapturePossible(piecesAtLocation, currentTurn.TurnPlayer.PlayerColor, entitiesDB);
            bool noCheckViolationsExist  = immobileCaptureService.NoCheckViolationsExist(piecesAtLocation, immobileCapturePossible, entitiesDB);

            return(immobileCapturePossible && noCheckViolationsExist);
        }
 private bool HasSameTypeAndTeamInTower(
     PieceEV pieceToCalc, Vector2 destination, List <PieceEV> allPieces)
 {
     return(allPieces.Where(piece =>
                            piece.Location.Location == destination &&
                            piece.PlayerOwner.PlayerColor == pieceToCalc.PlayerOwner.PlayerColor &&
                            piece.Piece.PieceType == pieceToCalc.Piece.PieceType).Count() > 0);
 }
Пример #23
0
        private PieceSideState CheckDropToken(ref HandPieceEV handPiece, ref TileEV destinationTile, PieceSide?sideToCheck)
        {
            TurnEV currentTurn = turnService.GetCurrentTurnEV(entitiesDB);

            if (currentTurn.InitialArrangement.IsInitialArrangementInEffect)
            {
                return(PieceSideState.FRONT);
            }

            PieceEV pieceToDrop = pieceFindService.FindFirstPieceByLocationAndType(
                BoardConst.HAND_LOCATION, handPiece.HandPiece.PieceType, handPiece.HandPiece.Back, entitiesDB);

            bool singleSideValid = sideToCheck.HasValue && checkmateService.DropReleasesCheck(
                pieceToDrop,
                destinationTile.Location.Location,
                currentTurn.TurnPlayer.PlayerColor,
                sideToCheck.Value,
                handPiece,
                entitiesDB);

            bool frontSideValid = !sideToCheck.HasValue &&
                                  checkmateService.DropReleasesCheck(
                pieceToDrop,
                destinationTile.Location.Location,
                currentTurn.TurnPlayer.PlayerColor,
                PieceSide.FRONT,
                handPiece,
                entitiesDB);
            bool backSideValid = !sideToCheck.HasValue &&
                                 checkmateService.DropReleasesCheck(
                pieceToDrop,
                destinationTile.Location.Location,
                currentTurn.TurnPlayer.PlayerColor,
                PieceSide.BACK,
                handPiece,
                entitiesDB);

            if (singleSideValid)
            {
                return(sideToCheck.Value == PieceSide.FRONT ? PieceSideState.FRONT : PieceSideState.BACK);
            }
            else if (frontSideValid && backSideValid)
            {
                return(PieceSideState.BOTH);
            }
            else if (frontSideValid)
            {
                return(PieceSideState.FRONT);
            }
            else if (backSideValid)
            {
                return(PieceSideState.BACK);
            }
            else
            {
                return(PieceSideState.NONE);
            }
        }
Пример #24
0
 public void SetTopOfTower(PieceEV pieceEV, IEntitiesDB entitiesDB, bool topOfTower = true)
 {
     entitiesDB.ExecuteOnEntity(
         pieceEV.ID,
         (ref PieceEV pieceToChange) =>
     {
         pieceToChange.Tier.TopOfTower = topOfTower;
     });
 }
Пример #25
0
 public void SetPieceSide(PieceEV pieceEV, PieceSide side, IEntitiesDB entitiesDB)
 {
     entitiesDB.ExecuteOnEntity(
         pieceEV.ID,
         (ref PieceEV pieceToChange) =>
     {
         pieceToChange.Piece.PieceType = side == PieceSide.FRONT ? pieceToChange.Piece.Front : pieceToChange.Piece.Back;
     });
 }
Пример #26
0
 private void FlipPiece(PieceEV piece, PlayerColor turnPlayerColor)
 {
     pieceSetService.SetPiecePlayerOwner(piece, turnPlayerColor, entitiesDB);
     pieceSetService.SetPieceSide(
         piece,
         piece.Piece.PieceType == piece.Piece.Front ? PieceSide.BACK : PieceSide.FRONT,
         entitiesDB);
     piece.ChangeColorTrigger.PlayChangeColor = true;
 }
 private bool IsOpponentPieceDirectlyBelow(PieceEV pieceEV, List <PieceEV> allPieces)
 {
     return(pieceEV.Tier.Tier != 1 &&
            allPieces.Where(piece =>
                            piece.Location.Location == pieceEV.Location.Location &&
                            piece.PlayerOwner.PlayerColor != pieceEV.PlayerOwner.PlayerColor &&
                            piece.Tier.Tier + 1 == pieceEV.Tier.Tier)
            .Count() > 0);
 }
Пример #28
0
        private void NextActionClickHighlightCapture(PieceEV piece)
        {
            var clickPieceStepState = new ClickPieceStepState
            {
                ClickedPiece = piece
            };

            towerModalConfirmSequence.Next(this, ref clickPieceStepState, (int)TowerAnswerState.DECIDE_CLICK_HIGHLIGHT_CAPTURE);
        }
        private void RestoreSingleState(PreviousPieceState previousState)
        {
            PieceEV pieceToRestore = previousState.Piece;

            pieceToRestore.PlayerOwner.PlayerColor = previousState.PlayerColor;
            pieceToRestore.Piece.PieceType         = previousState.PieceType;
            pieceToRestore.Location.Location       = previousState.Location;
            pieceToRestore.Tier.Tier       = previousState.Tier;
            pieceToRestore.Tier.TopOfTower = previousState.TopOfTower;
        }
        public void Step(ref SubstitutionStepState token, int condition)
        {
            TurnEV  currentTurn = turnService.GetCurrentTurnEV(entitiesDB);
            PieceEV commander   = pieceFindService.FindCommander(currentTurn.TurnPlayer.PlayerColor, entitiesDB);
            PieceEV ninja       = token.SubstitutionPiece;

            SwitchCommanderAndNinjaPiece(commander, ninja);

            NextActionTurnEnd();
        }