public BoardState TryApplyMove(ChessMove newMove, out bool putsUserInCheck)
 {
     var newBoardState = new BoardState(this, newMove);
     if (newBoardState.KingIsCapturable())
     {
         putsUserInCheck = true;
         return this;
     }
     else
     {
         putsUserInCheck = false;
         return newBoardState;
     }
 }
        // Hypothetical board state where the turn color has not changed
        private BoardState(BoardState previousState, out bool isCheck, out bool isCheckMate)
        {
            BoardGrid = new ChessPiece[8, 8];
            // Copy elements.
            for (int row = 0; row < 8; row++)
            {
                for (int column = 0; column < 8; column++)
                {
                    Coordinate coordinate = new Coordinate(row, column);
                    SetPieceAtCoordinate(previousState.GetPieceAtCoordinate(coordinate), coordinate);
                }
            }

            // Copy other board state values.
            BlackKingsideCastling = previousState.BlackKingsideCastling;
            BlackKingsideCastling = previousState.BlackQueensideCastling;
            WhiteKingsideCastling = previousState.WhiteKingsideCastling;
            WhiteQueensideCastling = previousState.WhiteQueensideCastling;
            TurnColor = previousState.TurnColor == ChessPieceColor.White ? ChessPieceColor.Black : ChessPieceColor.White; ;
            FullMove = previousState.FullMove;
            HalfMove = previousState.HalfMove;
            EnPassantTarget = new Coordinate(-1, -1);
            ParseLongAlgebraicNotation("");

            InitializeAllPossibleMoves();

            isCheck = KingIsCapturable();

            isCheckMate = false;
            if (isCheck)
            {
                this.TurnColor = TurnColor == ChessPieceColor.White ? ChessPieceColor.Black : ChessPieceColor.White;

                InitializeAllPossibleMoves();

                isCheckMate = true;
                for (int row = 0; row < 8 && isCheckMate; row++)
                {
                    for (int column = 0; column < 8 && isCheckMate; column++)
                    {
                        var moves = PossibleMovesGrid[row, column];
                        if (moves != null)
                        {
                            foreach (var move in moves)
                            {
                                if (!new BoardState(this, move, false).KingIsCapturable())
                                {
                                    isCheckMate = false;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        // Make a new board state by applying a new move to an already existing board state.
        public BoardState(BoardState previousState, ChessMove newMove, bool lookForCheck = true)
        {
            BoardGrid = new ChessPiece[8, 8];
            if (!newMove.KingsideCastle && !newMove.QueensideCastle)
            {
                HashSet<ChessMove> previousPossibleMoves = previousState.GetPossibleMoves(newMove.From);
                if (!previousPossibleMoves.Contains(newMove))
                {
                    throw new BoardStateException("Illegal move.");
                }
            }
            // Copy elements.
            for (int row = 0; row < 8; row++)
            {
                for (int column = 0; column < 8; column++)
                {
                    Coordinate coordinate = new Coordinate(row, column);
                    SetPieceAtCoordinate(previousState.GetPieceAtCoordinate(coordinate), coordinate);
                }
            }
            // Copy other board state values.
            BlackKingsideCastling = previousState.BlackKingsideCastling;
            BlackQueensideCastling = previousState.BlackQueensideCastling;
            WhiteKingsideCastling = previousState.WhiteKingsideCastling;
            WhiteQueensideCastling = previousState.WhiteQueensideCastling;
            // Turn color will be flipped and fullmove/halfmove will be incremented after move is applied.
            TurnColor = previousState.TurnColor;
            FullMove = previousState.FullMove;
            HalfMove = previousState.HalfMove;
            // Reset En Passant.
            EnPassantTarget = new Coordinate(-1, -1);
            // Castling special case.
            if (newMove.KingsideCastle || newMove.QueensideCastle)
            {
                int row = TurnColor == ChessPieceColor.White ? FirstRowWhite : FirstRowBlack;
                int rookStartColumn = newMove.KingsideCastle ? KingsideRookColumn : QueensideRookColumn;
                int kingEndColumn = newMove.KingsideCastle ? KingsideCastledKingColumn : QueensideCastledKingColumn;
                int rookEndColumn = newMove.KingsideCastle ? KingsideCastledRookColumn : QueensideCastledRookColumn;
                var kingStart = new Coordinate(row, KingStartColumn);
                var kingEnd = new Coordinate(row, kingEndColumn);
                var rookStart = new Coordinate(row, rookStartColumn);
                var rookEnd = new Coordinate(row, rookEndColumn);
                SetPieceAtCoordinate(new ChessPiece(ChessPieceColor.None, ChessPieceType.None), kingStart);
                SetPieceAtCoordinate(new ChessPiece(ChessPieceColor.None, ChessPieceType.None), rookStart);
                SetPieceAtCoordinate(new ChessPiece(TurnColor, ChessPieceType.King), kingEnd);
                SetPieceAtCoordinate(new ChessPiece(TurnColor, ChessPieceType.Rook), rookEnd);
                if (TurnColor == ChessPieceColor.White)
                {
                    WhiteKingsideCastling = false;
                    WhiteQueensideCastling = false;
                }
                else
                {
                    BlackKingsideCastling = false;
                    BlackQueensideCastling = false;
                }
            }
            // All other move types.
            else
            {
                // If en passant
                if (newMove.PieceType == ChessPieceType.Pawn)
                {
                    if (previousState.EnPassantTarget.Equals(newMove.To))
                    {
                        if (TurnColor == ChessPieceColor.White)
                        {
                            SetPieceAtCoordinate(new ChessPiece(ChessPieceColor.None, ChessPieceType.None), new Coordinate(newMove.To, -1, 0));
                        }
                        else
                        {
                            SetPieceAtCoordinate(new ChessPiece(ChessPieceColor.None, ChessPieceType.None), new Coordinate(newMove.To, 1, 0));
                        }
                    }
                    // Mark if the new move triggers the possibilty of an En Passant from the following turn.

                    int pawnDoubleFromRow = TurnColor == ChessPieceColor.White ? 1 : 6;
                    int pawnDoubleToRow = TurnColor == ChessPieceColor.White ? 3 : 4;
                    int enPassantTargetTargetRow = TurnColor == ChessPieceColor.White ? 2 : 5;
                    if (newMove.From.Row == pawnDoubleFromRow && newMove.To.Row == pawnDoubleToRow)
                    {
                        EnPassantTarget = new Coordinate(enPassantTargetTargetRow, newMove.From.Column);
                    }
                }
                // King movements disable castling.
                else if (newMove.PieceType == ChessPieceType.King)
                {
                    if (TurnColor == ChessPieceColor.White)
                    {
                        WhiteKingsideCastling = false;
                        WhiteQueensideCastling = false;
                    }
                    else
                    {
                        BlackKingsideCastling = false;
                        BlackQueensideCastling = false;
                    }
                }
                // Rook movements disable on their side.
                else if (newMove.PieceType == ChessPieceType.Rook)
                {
                    if (TurnColor == ChessPieceColor.White)
                    {
                        if (newMove.From.Equals(new Coordinate(FirstRowWhite, KingsideRookColumn)))
                        {
                            WhiteKingsideCastling = false;
                        }
                        else if (newMove.From.Equals(new Coordinate(FirstRowWhite, QueensideRookColumn)))
                        {
                            WhiteQueensideCastling = false;
                        }
                    }
                    else
                    {
                        if (newMove.From.Equals(new Coordinate(FirstRowBlack, KingsideRookColumn)))
                        {
                            BlackKingsideCastling = false;
                        }
                        else if (newMove.From.Equals(new Coordinate(FirstRowBlack, QueensideRookColumn)))
                        {
                            BlackQueensideCastling = false;
                        }
                    }
                }
                // Set square that the piece is moving from to empty, and moving to to have the piece.
                SetPieceAtCoordinate(new ChessPiece(ChessPieceColor.None, ChessPieceType.None), newMove.From);
                SetPieceAtCoordinate(new ChessPiece(TurnColor, newMove.IsPromotionToQueen ? ChessPieceType.Queen : newMove.PieceType), newMove.To);
            }

            // Reset or increment halfMove.
            if (newMove.IsCapture || newMove.PieceType == ChessPieceType.Pawn)
            {
                HalfMove = 0;
            }
            else
            {
                HalfMove++;
            }

            // Set applied move to be the previous move.
            PreviousMove = newMove;

            // Increment fullMove after blacks turn;
            if (TurnColor == ChessPieceColor.Black)
            {
                FullMove++;
            }

            // Switch turns.
            TurnColor = previousState.TurnColor == ChessPieceColor.White ? ChessPieceColor.Black : ChessPieceColor.White;

            bool isCheck = false;
            bool isCheckMate = false;
            if (lookForCheck)
            {
                new BoardState(this, out isCheck, out isCheckMate);
                PreviousMove = new ChessMove(PreviousMove.From, PreviousMove.To, PreviousMove.PieceType, PreviousMove.IsCapture, PreviousMove.IsPromotionToQueen, PreviousMove.DrawOfferExtended, isCheck, isCheckMate, PreviousMove.KingsideCastle, PreviousMove.QueensideCastle);
            }
            // Finally, determine the list of legal moves.
            InitializeAllPossibleMoves();
        }
 public MatchState(PlayerInfo opponent, BoardState boardState, bool selfIsWhite, string identifier)
 {
     this.Opponent = opponent;
     this.BoardState = boardState;
     this.SelfIsWhite = selfIsWhite;
     this.Identifier = identifier;
 }
        void RefreshBoard(GameState.MatchState matchState, BoardState.Coordinate? selected)
        {
            CurrentMatchState = matchState;
            StatusText.text = string.Format("{0} ({1})",
                matchState.IsSelfTurn() ? "Your Turn" : "Their Turn",
                matchState.BoardState.TurnColor == BoardState.ChessPieceColor.White ? "white" : "black");

            for (int r = 0; r < 8; r++)
            {
                for (int c = 0; c < 8; c++)
                {
                    foreach (Transform child in TransformGrid[r, c])
                    {
                        Destroy(child.gameObject);
                    }
                }
            }

            if (matchState.BoardState.PreviousMove.IsCheckMate)
            {
                TitleText.text = "Game Finished";
                StatusText.text = string.Format("{0} won!", matchState.IsSelfTurn() ? "They" : "You");
                return;
            }

            HashSet<BoardState.ChessMove> moves;
            var moveDestinations = new HashSet<BoardState.Coordinate>();
            if (selected.HasValue)
            {
                moves = matchState.BoardState.GetPossibleMoves(selected.Value);
            }
            else
            {
                moves = new HashSet<BoardState.ChessMove>();
            }
            foreach (var move in moves)
            {
                moveDestinations.Add(move.To);
            }

            // Fill in pieces, except those that are move destinations
            for (int c = 0; c < 8; c++)
            {
                for (int r = 0; r < 8; r++)
                {
                    var coordinate = new BoardState.Coordinate(r, c);
                    bool isSelectedCoordinate = selected.HasValue && selected.Value.Equals(coordinate);
                    bool isMoveDestination = moveDestinations.Contains(coordinate);

                    BoardState.ChessPiece piece = matchState.BoardState.GetPieceAtCoordinate(coordinate);
                    // pieces that are move destinations are handled later because clicking on them has movement behavior.
                    if (piece.Type != BoardState.ChessPieceType.None && !isMoveDestination)
                    {
                        Color pieceHighlight = isSelectedCoordinate ? Color.green : Color.white;
                        Image pieceImage = prefabToPieceImage(piece, pieceHighlight);
                        pieceImage.transform.SetParent(TransformGrid[r, c], false);
                        // Only allow player to make moves if it is their turn. Games against local
                        // player allow both players to make a move on the same device.
                        if (matchState.IsSelfTurn() || matchState.Opponent.IsLocalOpponent())
                        {
                            pieceImage.GetComponent<Button>().onClick.AddListener(delegate
                            {
                                if (selected == null)
                                {
                                    RefreshBoard(matchState, coordinate);
                                }
                                else if (selected.Value.Equals(coordinate))
                                {
                                    RefreshBoard(matchState, null);
                                }
                                else
                                {
                                    RefreshBoard(matchState, coordinate);
                                }
                            });
                        }
                    }
                }
            }

            // Fill in pieces that are move destinations
            foreach (var move in moves)
            {
                bool putsUserInCheck;
                var newMatchState = new GameState.MatchState(
                    matchState.Opponent,
                    matchState.BoardState.TryApplyMove(move, out putsUserInCheck),
                    matchState.SelfIsWhite,
                    matchState.Identifier);

                if (!putsUserInCheck)
                {
                    bool isOpponentPiece = matchState.BoardState.GetPieceAtCoordinate(move.To).Type != BoardState.ChessPieceType.None;
                    Color pieceHighlight = isOpponentPiece ? Color.red : Color.blue;
                    BoardState.ChessPiece fromPiece = matchState.BoardState.GetPieceAtCoordinate(move.From);
                    Image pieceImage = prefabToPieceImage(fromPiece, pieceHighlight);
                    pieceImage.transform.SetParent(TransformGrid[move.To.Row, move.To.Column], false);

                    // Only allow player to make moves if it is their turn. Games against local
                    // player allow both players to make a move on the same device.
                    if (matchState.IsSelfTurn() || matchState.Opponent.IsLocalOpponent())
                    {
                        pieceImage.GetComponent<Button>().onClick.AddListener(delegate
                        {
                            // GameManager will handler whether or not we are saving a local or multiplayer
                            // game, and will notify us of the updated state via our
                            // CurrentMatchStateAvailableHandler
                            StatusText.text = "Saving Match...";
                            GameManager.Instance.UpdateMatchState(newMatchState);
                        });
                    }
                }
            }
        }
        public Image prefabToPieceImage(BoardState.ChessPiece piece, Color color)
        {
            Image pieceSpritePrefab = null;
            switch (piece.Type)
            {
                case BoardState.ChessPieceType.Rook:
                    pieceSpritePrefab = piece.Color == BoardState.ChessPieceColor.White ? WhiteRookPrefab : BlackRookPrefab;
                    break;
                case BoardState.ChessPieceType.Knight:
                    pieceSpritePrefab = piece.Color == BoardState.ChessPieceColor.White ? WhiteKnightPrefab : BlackKnightPrefab;
                    break;
                case BoardState.ChessPieceType.Bishop:
                    pieceSpritePrefab = piece.Color == BoardState.ChessPieceColor.White ? WhiteBishopPrefab : BlackBishopPrefab;
                    break;
                case BoardState.ChessPieceType.Queen:
                    pieceSpritePrefab = piece.Color == BoardState.ChessPieceColor.White ? WhiteQueenPrefab : BlackQueenPrefab;
                    break;
                case BoardState.ChessPieceType.King:
                    pieceSpritePrefab = piece.Color == BoardState.ChessPieceColor.White ? WhiteKingPrefab : BlackKingPrefab;
                    break;
                case BoardState.ChessPieceType.Pawn:
                    pieceSpritePrefab = piece.Color == BoardState.ChessPieceColor.White ? WhitePawnPrefab : BlackPawnPrefab;
                    break;
            }

            var pieceImage = Instantiate(pieceSpritePrefab) as Image;
            float pieceWScale = 50 / pieceImage.rectTransform.rect.width;
            float pieceHScale = 50 / pieceImage.rectTransform.rect.height;
            pieceImage.rectTransform.localScale = new Vector3(pieceWScale, pieceHScale);
            pieceImage.rectTransform.localPosition = new Vector3();
            pieceImage.color = color;
            return pieceImage;
        }