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 PlayerSide GetThisPlayerSide(ChessMove instruction)
 {
     return(this.LocationChess[instruction.From].Side);
 }
        private static bool IsChecked(PlayerSide side, Dictionary <Point, Chess> locationChess, ChessMove after = null)
        {
            lock (SpinLock_IsChecked)
            {
                Chess killedChess = null;
                bool  isChecked   = false;
                if (after != null)
                {
                    if (locationChess.ContainsKey(after.To))
                    {
                        killedChess = locationChess[after.To];
                    }
                    locationChess[after.To] = locationChess[after.From];
                    locationChess.Remove(after.From);
                }

                Point kingLocation = GetKingLocation(side, locationChess);
                foreach ((Point location, Chess chess) in locationChess)
                {
                    if (chess.Side == side)
                    {
                        continue;
                    }
                    if (IsReachable(chess, location, kingLocation, locationChess))
                    {
                        isChecked = true;
                        break;
                    }
                }

                // restore
                if (after != null)
                {
                    locationChess[after.From] = locationChess[after.To];
                    locationChess.Remove(after.To);
                    if (killedChess != null)
                    {
                        locationChess[after.To] = killedChess;
                    }
                }

                return(isChecked);
            }
        }
        private static Point GetKingLocation(PlayerSide side, Dictionary <Point, Chess> locationChess, ChessMove after = null)
        {
            if (after != null && locationChess[after.From].Type == ChessType.King)
            {
                return(after.To);
            }
            Point kingLocation = locationChess.Single(xxxx =>
                                                      xxxx.Value.Type == ChessType.King &&
                                                      xxxx.Value.Side == side).Key;

            return(kingLocation);
        }
        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);
            }
        }