private static bool IsPawnReachable(Chess chess, Point from, Point to, Dictionary <Point, Chess> locationChess)
        {
            switch (chess.Side)
            {
            case PlayerSide.White:
                if (to.Y == from.Y - 1)
                {
                    if (to.X == from.X)
                    {
                        // pawn go straight forward
                        return(!locationChess.ContainsKey(to));
                    }
                    else if (to.X == from.X + 1 || to.X == from.X - 1)
                    {
                        return(IsOppositeChess(to, locationChess, chess.Side));
                    }
                    else
                    {
                        return(false);
                    }
                }
                else if (to.Y == from.Y - 2)
                {
                    return(!HasChess(new Point(from.X, from.Y - 1), locationChess) &&
                           !HasChess(to, locationChess) &&
                           from.Y == 6);
                }
                else
                {
                    return(false);
                }
                break;

            case PlayerSide.Black:
                if (to.Y == from.Y + 1)
                {
                    if (to.X == from.X)
                    {
                        // pawn go straight forward
                        return(!locationChess.ContainsKey(to));
                    }
                    else if (to.X == from.X + 1 || to.X == from.X - 1)
                    {
                        return(IsOppositeChess(to, locationChess, chess.Side));
                    }
                    else
                    {
                        return(false);
                    }
                }
                else if (to.Y == from.Y + 2)
                {
                    return(!HasChess(new Point(from.X, from.Y + 1), locationChess) &&
                           !HasChess(to, locationChess) &&
                           from.Y == 1);
                }
                else
                {
                    return(false);
                }
                break;

            default:
                return(false);
            }
        }
        private void PerformChessMove(ChessMove instruction)
        {
            PlayerSide thisSide = GetThisPlayerSide(instruction);

            // chess if there has a chess
            if (!HasChess(instruction.From, this.LocationChess))
            {
                throw new InvalidChessOperation();
            }
            // check who's turn
            if (thisSide != this.WhosTurn)
            {
                throw new InvalidChessOperation();
            }
            // check if during promotion
            if (this.IsDuringPromotion)
            {
                // only allow to perform chess change
                throw new InvalidChessOperation();
            }

            // if else:
            // basic movement
            //  if checked after
            //  update `FreshTwoStepAdvancePawnLocation`
            // en passant
            //  if checked after
            // castling
            //  if checked before
            //  if checked middle
            //  if checked after
            Chess chess = this.LocationChess[instruction.From];

            if (IsReachable(chess, instruction.From, instruction.To, this.LocationChess))
            {
                if (IsChecked(thisSide, this.LocationChess, instruction))
                {
                    throw new InvalidChessOperation();
                }
                UpdateFreshTwoStepAdvancePawnLocation(chess, instruction.From, instruction.To);
            }
            else if (IsEnPassant(chess, instruction.From, instruction.To))
            {
                if (IsChecked(thisSide, this.LocationChess, instruction))
                {
                    throw new InvalidChessOperation();
                }
                // remove the killed pawn
                switch (chess.Side)
                {
                case PlayerSide.White:
                    this.LocationChess.Remove(this.FreshTwoStepAdvanceBlackPawnLocation.Value);
                    break;

                case PlayerSide.Black:
                    this.LocationChess.Remove(this.FreshTwoStepAdvanceWhitePawnLocation.Value);
                    break;
                }
            }
            else if (IsCastling(chess, instruction.From, instruction.To))
            {
                // move rook
                Point rookDestination = new Point((instruction.From.X + instruction.To.X) / 2, instruction.From.Y);
                Point rookSource      = new Point(0, 0);
                switch (chess.Side)
                {
                case PlayerSide.White:
                    if (instruction.To.X > instruction.From.X)
                    {
                        rookSource = new Point(7, 7);
                    }
                    else
                    {
                        rookSource = new Point(0, 7);
                    }
                    break;

                case PlayerSide.Black:
                    if (instruction.To.X > instruction.From.X)
                    {
                        rookSource = new Point(7, 0);
                    }
                    else
                    {
                        rookSource = new Point(0, 0);
                    }
                    break;
                }
                this.LocationChess[rookDestination] = this.LocationChess[rookSource];
                this.LocationChess.Remove(rookSource);
            }
            else
            {
                throw new InvalidChessOperation();
            }

            // castling change availability
            if (chess.Type == ChessType.King)
            {
                switch (chess.Side)
                {
                case PlayerSide.White:
                    this.CouldWhiteCastlingLeft  = false;
                    this.CouldWhiteCastlingRight = false;
                    break;

                case PlayerSide.Black:
                    this.CouldBlackCastlingLeft  = false;
                    this.CouldBlackCastlingRight = false;
                    break;
                }
            }
            else if (chess.Type == ChessType.Rook)
            {
                switch (instruction.From.Y)
                {
                case 0:
                    switch (instruction.From.X)
                    {
                    case 0:
                        this.CouldBlackCastlingLeft = false;
                        break;

                    case 7:
                        this.CouldBlackCastlingRight = false;
                        break;
                    }
                    break;

                case 7:
                    switch (instruction.From.X)
                    {
                    case 0:
                        this.CouldWhiteCastlingLeft = false;
                        break;

                    case 7:
                        this.CouldWhiteCastlingRight = false;
                        break;
                    }
                    break;
                }
            }

            // promotion
            if (this.LocationChess[instruction.From].Type == ChessType.Pawn &&
                (instruction.To.Y == 7 || instruction.To.Y == 0))
            {
                this.IsDuringPromotion = true;
            }
            else
            {
                this.WhosTurn = GetOppositeSide(GetThisPlayerSide(instruction));
            }
            // ~~mark check~~
        }
        private bool IsCastling(Chess chess, Point from, Point to)
        {
            if (chess.Type != ChessType.King)
            {
                return(false);
            }
            if (Math.Abs(to.X - from.X) == 2 && from.X == 4)
            {
                // source -> destination: direction
                switch (to.X)
                {
                case 2:
                    // king goes left
                    if (!HasChess(new Point(1, from.Y), this.LocationChess) &&
                        !HasChess(new Point(2, from.Y), this.LocationChess) &&
                        !HasChess(new Point(3, from.Y), this.LocationChess) &&
                        (chess.Side == PlayerSide.Black && this.CouldBlackCastlingLeft ||
                         chess.Side == PlayerSide.White && this.CouldWhiteCastlingLeft
                        )
                        )
                    {
                        ChessMove moveOneStep = new ChessMove()
                        {
                            From = from,
                            // To = new Point(from.X - 1, from.Y)
                            To = new Point((from.X + to.X) / 2, from.Y)
                        };
                        ChessMove moveTwoSteps = new ChessMove()
                        {
                            From = from,
                            To   = to
                        };
                        return(!IsChecked(chess.Side, this.LocationChess) &&
                               !IsChecked(chess.Side, this.LocationChess, moveOneStep) &&
                               !IsChecked(chess.Side, this.LocationChess, moveTwoSteps));
                    }
                    else
                    {
                        return(false);
                    }

                case 6:
                    // king goes right
                    if (!HasChess(new Point(5, from.Y), this.LocationChess) &&
                        !HasChess(new Point(6, from.Y), this.LocationChess) &&
                        (chess.Side == PlayerSide.Black && this.CouldBlackCastlingRight ||
                         chess.Side == PlayerSide.White && this.CouldWhiteCastlingRight
                        )
                        )
                    {
                        ChessMove moveOneStep = new ChessMove()
                        {
                            From = from,
                            // To = new Point(from.X + 1, from.Y)
                            To = new Point((from.X + to.X) / 2, from.Y)
                        };
                        ChessMove moveTwoSteps = new ChessMove()
                        {
                            From = from,
                            To   = to
                        };
                        return(!IsChecked(chess.Side, this.LocationChess) &&
                               !IsChecked(chess.Side, this.LocationChess, moveOneStep) &&
                               !IsChecked(chess.Side, this.LocationChess, moveTwoSteps));
                    }
                    else
                    {
                        return(false);
                    }

                default:
                    return(false);
                }
            }
            else
            {
                return(false);
            }
        }