예제 #1
0
        /// <summary>
        /// Returns the move specified by the given information.
        /// </summary>
        /// <param name="position">The position the move is to be played on.</param>
        /// <param name="from">The initial square of the move.</param>
        /// <param name="to">The final square of the move.</param>
        /// <returns>The move specified by the given information.</returns>
        private Int32 CreateMove(Position position, Int32 from, Int32 to)
        {
            foreach (Int32 move in position.LegalMoves())
            {
                if (from == Move.From(move) && to == Move.To(move))
                {
                    Int32 special = Move.Special(move);
                    if (Move.IsPromotion(move))
                    {
                        switch (SelectionBox.Show("What piece would you like to promote to?", "Queen", "Rook", "Bishop", "Knight"))
                        {
                        case "Queen":
                            special = position.SideToMove | Piece.Queen;
                            break;

                        case "Rook":
                            special = position.SideToMove | Piece.Rook;
                            break;

                        case "Bishop":
                            special = position.SideToMove | Piece.Bishop;
                            break;

                        case "Knight":
                            special = position.SideToMove | Piece.Knight;
                            break;
                        }
                    }
                    return(Move.Create(position, from, to, special));
                }
            }
            return(Move.Invalid);
        }
예제 #2
0
        /// <summary>
        /// Returns the estimated material exchange value of the given move on the
        /// given position as determined by static analysis.
        /// </summary>
        /// <param name="position">The position the move is to be played on.</param>
        /// <param name="move">The move to evaluate.</param>
        /// <returns>The estimated material exchange value of the move.</returns>
        private static Int32 EvaluateStaticExchange(Position position, Int32 move)
        {
            Int32 from    = Move.From(move);
            Int32 to      = Move.To(move);
            Int32 piece   = Move.Piece(move);
            Int32 capture = Move.Capture(move);

            position.Bitboard[piece]  ^= 1UL << from;
            position.OccupiedBitboard ^= 1UL << from;
            position.Square[to]        = piece;

            Int32 value = 0;

            if (Move.IsPromotion(move))
            {
                Int32 promotion = Move.Special(move);
                position.Square[to] = promotion;
                value += PieceValue[promotion] - PieceValue[Piece.Pawn];
            }
            value += PieceValue[capture] - EvaluateStaticExchange(position, 1 - position.SideToMove, to);

            position.Bitboard[piece]  ^= 1UL << from;
            position.OccupiedBitboard ^= 1UL << from;
            position.Square[to]        = capture;

            return(value);
        }
예제 #3
0
        /// <summary>
        /// Draws an arrow for the given move with the given pen. Optionally draws
        /// a label if given.
        /// </summary>
        /// <param name="g">The graphics surface to draw on.</param>
        /// <param name="pen">The pen for drawing the arrow.</param>
        /// <param name="move">The move to draw an arrow for.</param>
        /// <param name="labelBrush">The brush for drawing the label.</param>
        /// <param name="label">The label to draw at the move's from square.</param>
        public static void DrawArrow(Graphics g, Pen pen, Int32 move, Brush labelBrush = null, String label = "")
        {
            if (!DrawArrows)
            {
                return;
            }

            Int32 from    = Move.From(move);
            Int32 to      = Move.To(move);
            Point initial = new Point(
                RotateIfNeeded(Position.File(from)) * SquareWidth + SquareWidth / 2,
                RotateIfNeeded(Position.Rank(from)) * SquareWidth + SquareWidth / 2);
            Point final = new Point(
                RotateIfNeeded(Position.File(to)) * SquareWidth + SquareWidth / 2,
                RotateIfNeeded(Position.Rank(to)) * SquareWidth + SquareWidth / 2);

            pen.StartCap = LineCap.NoAnchor;
            pen.EndCap   = LineCap.ArrowAnchor;
            g.DrawLine(pen, initial, final);

            if (labelBrush != null && !String.IsNullOrEmpty(label))
            {
                Point  delta  = new Point(final.X - initial.X, final.Y - initial.Y);
                Single mag    = (Single)Math.Sqrt(delta.X * delta.X + delta.Y * delta.Y);
                Single factor = delta.Y > 0 ? LabelPullMagnitude : -LabelPullMagnitude;
                PointF pull   = new PointF(factor * delta.Y / mag, factor * -delta.X / mag);
                PointF mid    = new PointF((initial.X + final.X) / 2 + pull.X, (initial.Y + final.Y) / 2 + pull.Y);
                g.DrawString(label, LabelFont, labelBrush, mid, LabelFormat);
            }
        }
예제 #4
0
        /// <summary>
        /// Unmakes the given move on the visual position.
        /// </summary>
        /// <param name="move">The move to unmake.</param>
        public static void Unmake(Int32 move)
        {
            Int32 from    = Move.From(move);
            Int32 to      = Move.To(move);
            Point initial = new Point(Position.File(to) * SquareWidth, Position.Rank(to) * SquareWidth);
            Point final   = new Point(Position.File(from) * SquareWidth, Position.Rank(from) * SquareWidth);

            // Remove captured pieces.
            lock (PiecesLock)
                _pieces.Add(new VisualPiece(
                                Move.Capture(move),
                                Position.File(to) * SquareWidth,
                                Position.Rank(to) * SquareWidth));

            // Perform special moves.
            switch (Move.Special(move) & Piece.Mask)
            {
            case Piece.King:
                Point rookInitial = new Point((Position.File(to) / 2 + 2) * SquareWidth, Position.Rank(to) * SquareWidth);
                Point rookFinal   = new Point(7 * (Position.File(to) - 2) / 4 * SquareWidth, Position.Rank(to) * SquareWidth);
                Animate(move, rookInitial, rookFinal);
                break;

            case Piece.Pawn:
                lock (PiecesLock)
                    _pieces.Add(new VisualPiece(
                                    Move.Special(move),
                                    Position.File(to) * SquareWidth,
                                    Position.Rank(from) * SquareWidth));
                break;
            }
            Animate(move, initial, final);
        }
예제 #5
0
        /// <summary>
        /// Returns whether the given move puts the opponent in check.
        /// </summary>
        /// <param name="move">The move to test for check.</param>
        /// <returns>Whether the given move puts the opponent in check.</returns>
        public Boolean CausesCheck(Int32 move)
        {
            UInt64 fromBitboard         = 1UL << Move.From(move);
            UInt64 toBitboard           = 1UL << Move.To(move);
            Int32  piece                = Move.Piece(move);
            Int32  special              = Move.Special(move);
            UInt64 occupiedBitboardCopy = OccupiedBitboard;

            Boolean value = false;

            switch (special & Piece.Mask)
            {
            // Consider normal move.
            case Piece.Empty:
                Bitboard[piece]  ^= fromBitboard | toBitboard;
                OccupiedBitboard ^= fromBitboard;
                OccupiedBitboard |= toBitboard;
                value             = InCheck(1 - SideToMove);
                Bitboard[piece]  ^= fromBitboard | toBitboard;
                OccupiedBitboard  = occupiedBitboardCopy;
                break;

            // Consider castling.
            case Piece.King:
                UInt64 rookToBitboard = 1UL << ((toBitboard < fromBitboard ? 3 : 5) + Rank(Move.To(move)) * 8);
                Bitboard[SideToMove | Piece.Rook] ^= rookToBitboard;
                OccupiedBitboard ^= fromBitboard;
                value             = InCheck(1 - SideToMove);
                Bitboard[SideToMove | Piece.Rook] ^= rookToBitboard;
                OccupiedBitboard = occupiedBitboardCopy;
                break;

            // Consider en passant.
            case Piece.Pawn:
                UInt64 enPassantPawnBitboard = Move.Pawn(EnPassantSquare, 1 - SideToMove);
                Bitboard[piece]  ^= fromBitboard | toBitboard;
                OccupiedBitboard ^= fromBitboard | toBitboard | enPassantPawnBitboard;
                value             = InCheck(1 - SideToMove);
                Bitboard[piece]  ^= fromBitboard | toBitboard;
                OccupiedBitboard  = occupiedBitboardCopy;
                break;

            // Consider pawn promotion.
            default:
                Bitboard[SideToMove | Piece.Pawn] ^= fromBitboard;
                Bitboard[special] ^= toBitboard;
                OccupiedBitboard  ^= fromBitboard;
                OccupiedBitboard  |= toBitboard;
                value              = InCheck(1 - SideToMove);
                Bitboard[SideToMove | Piece.Pawn] ^= fromBitboard;
                Bitboard[special] ^= toBitboard;
                OccupiedBitboard   = occupiedBitboardCopy;
                break;
            }
            return(value);
        }
예제 #6
0
        /// <summary>
        /// Makes the given move on the visual position.
        /// </summary>
        /// <param name="move">The move to make.</param>
        public static void Make(Int32 move)
        {
            Int32 from    = Move.From(move);
            Int32 to      = Move.To(move);
            Point initial = new Point(Position.File(from) * SquareWidth, Position.Rank(from) * SquareWidth);
            Point final   = new Point(Position.File(to) * SquareWidth, Position.Rank(to) * SquareWidth);

            // Remove captured pieces.
            lock (PiecesLock)
                for (Int32 i = 0; i < _pieces.Count; i++)
                {
                    if (_pieces[i].IsAt(final))
                    {
                        _pieces.RemoveAt(i);
                        break;
                    }
                }

            // Perform special moves.
            switch (Move.Special(move) & Piece.Mask)
            {
            case Piece.King:
                Point rookInitial = new Point(7 * (Position.File(to) - 2) / 4 * SquareWidth, Position.Rank(to) * SquareWidth);
                Point rookFinal   = new Point((Position.File(to) / 2 + 2) * SquareWidth, Position.Rank(to) * SquareWidth);
                Animate(move, rookInitial, rookFinal);
                break;

            case Piece.Pawn:
                Point enPassant = new Point(Position.File(to) * SquareWidth, Position.Rank(from) * SquareWidth);
                lock (PiecesLock)
                    for (Int32 i = 0; i < _pieces.Count; i++)
                    {
                        if (_pieces[i].IsAt(enPassant))
                        {
                            _pieces.RemoveAt(i);
                            break;
                        }
                    }
                break;
            }
            Animate(move, initial, final);
        }
예제 #7
0
        /// <summary>
        /// Unmakes the given move from the position.
        /// </summary>
        /// <param name="move">The move to unmake.</param>
        public void Unmake(Int32 move)
        {
            Int32 from    = Move.From(move);
            Int32 to      = Move.To(move);
            Int32 piece   = Move.Piece(move);
            Int32 capture = Move.Capture(move);
            Int32 special = Move.Special(move);

            // Rewind core board state.
            SideToMove            = 1 - SideToMove;
            Square[from]          = piece;
            Square[to]            = capture;
            Bitboard[piece]      ^= (1UL << from) | (1UL << to);
            Bitboard[SideToMove] ^= (1UL << from) | (1UL << to);
            OccupiedBitboard     ^= (1UL << from) | (1UL << to);

            // Rewind metainformation.
            ZobristKey = ZobristKeyHistory[HalfMoves - 1];
            EnPassantHistory[HalfMoves] = InvalidSquare;
            EnPassantSquare             = EnPassantHistory[HalfMoves - 1];
            FiftyMovesClock             = FiftyMovesHistory[HalfMoves - 1];
            HalfMoves--;

            // Rewind capture if applicable.
            switch (capture & Piece.Mask)
            {
            case Piece.Empty:
                break;

            case Piece.Rook:
                if ((SideToMove == Colour.White && to == 0) || (SideToMove == Colour.Black && to == 56))
                {
                    CastleQueenside[1 - SideToMove]++;
                }
                else if ((SideToMove == Colour.White && to == 7) || (SideToMove == Colour.Black && to == 63))
                {
                    CastleKingside[1 - SideToMove]++;
                }
                goto default;

            default:
                Bitboard[capture]        ^= 1UL << to;
                Bitboard[1 - SideToMove] ^= 1UL << to;
                OccupiedBitboard         |= 1UL << to;
                Material[1 - SideToMove] += Engine.PieceValue[capture];
                break;
            }

            switch (special & Piece.Mask)
            {
            // Rewind regular move.
            case Piece.Empty:
                switch (piece & Piece.Mask)
                {
                // For rook move, restore castling on one side if applicable.
                case Piece.Rook:
                    if ((SideToMove == Colour.White && from == 56) || (SideToMove == Colour.Black && from == 0))
                    {
                        CastleQueenside[SideToMove]++;
                    }
                    else if ((SideToMove == Colour.White && from == 63) || (SideToMove == Colour.Black && from == 7))
                    {
                        CastleKingside[SideToMove]++;
                    }
                    break;

                // For king move, restore castling on both sides if applicable.
                case Piece.King:
                    CastleQueenside[SideToMove]++;
                    CastleKingside[SideToMove]++;
                    break;
                }
                break;

            // Rewind castling.
            case Piece.King:
                CastleQueenside[SideToMove]++;
                CastleKingside[SideToMove]++;
                Int32 rookFrom;
                Int32 rookTo;
                if (to < from)
                {
                    rookFrom = Rank(to) * 8;
                    rookTo   = 3 + Rank(to) * 8;
                }
                else
                {
                    rookFrom = 7 + Rank(to) * 8;
                    rookTo   = 5 + Rank(to) * 8;
                }
                Bitboard[SideToMove | Piece.Rook] ^= (1UL << rookFrom) | (1UL << rookTo);
                Bitboard[SideToMove] ^= (1UL << rookFrom) | (1UL << rookTo);
                OccupiedBitboard     ^= (1UL << rookFrom) | (1UL << rookTo);
                Square[rookFrom]      = SideToMove | Piece.Rook;
                Square[rookTo]        = Piece.Empty;
                break;

            // Rewind en passant.
            case Piece.Pawn:
                Square[File(to) + Rank(from) * 8] = special;
                Bitboard[special]        ^= 1UL << (File(to) + Rank(from) * 8);
                Bitboard[1 - SideToMove] ^= 1UL << (File(to) + Rank(from) * 8);
                OccupiedBitboard         ^= 1UL << (File(to) + Rank(from) * 8);
                Material[1 - SideToMove] += Engine.PieceValue[special];
                break;

            // Rewind pawn promotion.
            default:
                Bitboard[piece]      ^= 1UL << to;
                Bitboard[special]    ^= 1UL << to;
                Material[SideToMove] -= Engine.PieceValue[special] - Engine.PieceValue[piece];
                break;
            }
        }
예제 #8
0
        /// <summary>
        /// Makes the given move on the position.
        /// </summary>
        /// <param name="move">The move to make.</param>
        public void Make(Int32 move)
        {
            Int32 from    = Move.From(move);
            Int32 to      = Move.To(move);
            Int32 piece   = Move.Piece(move);
            Int32 capture = Move.Capture(move);
            Int32 special = Move.Special(move);

            // Update core board state.
            Square[to]            = piece;
            Square[from]          = Piece.Empty;
            Bitboard[piece]      ^= (1UL << from) | (1UL << to);
            Bitboard[SideToMove] ^= (1UL << from) | (1UL << to);
            OccupiedBitboard     ^= (1UL << from) | (1UL << to);

            // Update metainformation.
            ZobristKey ^= Zobrist.PiecePosition[piece][from] ^ Zobrist.PiecePosition[piece][to];
            ZobristKey ^= Zobrist.Colour;
            if (EnPassantSquare != InvalidSquare)
            {
                ZobristKey     ^= Zobrist.EnPassant[EnPassantSquare];
                EnPassantSquare = InvalidSquare;
            }
            FiftyMovesClock++;
            HalfMoves++;

            // Handle capture if applicable.
            switch (capture & Piece.Mask)
            {
            case Piece.Empty:
                break;

            case Piece.Rook:
                if ((SideToMove == Colour.White && to == 0) || (SideToMove == Colour.Black && to == 56))
                {
                    if (CastleQueenside[1 - SideToMove]-- > 0)
                    {
                        ZobristKey ^= Zobrist.CastleQueenside[1 - SideToMove];
                    }
                }
                else if ((SideToMove == Colour.White && to == 7) || (SideToMove == Colour.Black && to == 63))
                {
                    if (CastleKingside[1 - SideToMove]-- > 0)
                    {
                        ZobristKey ^= Zobrist.CastleKingside[1 - SideToMove];
                    }
                }
                goto default;

            default:
                Bitboard[capture]        ^= 1UL << to;
                Bitboard[1 - SideToMove] ^= 1UL << to;
                OccupiedBitboard         |= 1UL << to;
                ZobristKey ^= Zobrist.PiecePosition[capture][to];
                Material[1 - SideToMove] -= Engine.PieceValue[capture];
                FiftyMovesClock           = 0;
                break;
            }

            switch (special & Piece.Mask)
            {
            // Handle regular move (not en passant, castling, or pawn promotion).
            case Piece.Empty:
                switch (piece & Piece.Mask)
                {
                // For pawn move, update fifty moves clock and en passant state.
                case Piece.Pawn:
                    FiftyMovesClock = 0;
                    if ((from - to) * (from - to) == 256)
                    {
                        ZobristKey ^= Zobrist.EnPassant[from];
                        EnPassantHistory[HalfMoves] = EnPassantSquare = (from + to) / 2;
                    }
                    break;

                // For rook move, disable castling on one side.
                case Piece.Rook:
                    if ((SideToMove == Colour.White && from == 56) || (SideToMove == Colour.Black && from == 0))
                    {
                        if (CastleQueenside[SideToMove]-- > 0)
                        {
                            ZobristKey ^= Zobrist.CastleQueenside[SideToMove];
                        }
                    }
                    else if ((SideToMove == Colour.White && from == 63) || (SideToMove == Colour.Black && from == 7))
                    {
                        if (CastleKingside[SideToMove]-- > 0)
                        {
                            ZobristKey ^= Zobrist.CastleKingside[SideToMove];
                        }
                    }
                    break;

                // For king move, disable castling on both sides.
                case Piece.King:
                    if (CastleQueenside[SideToMove]-- > 0)
                    {
                        ZobristKey ^= Zobrist.CastleQueenside[SideToMove];
                    }
                    if (CastleKingside[SideToMove]-- > 0)
                    {
                        ZobristKey ^= Zobrist.CastleKingside[SideToMove];
                    }
                    break;
                }
                break;

            // Handle castling.
            case Piece.King:
                if (CastleQueenside[SideToMove]-- > 0)
                {
                    ZobristKey ^= Zobrist.CastleQueenside[SideToMove];
                }
                if (CastleKingside[SideToMove]-- > 0)
                {
                    ZobristKey ^= Zobrist.CastleKingside[SideToMove];
                }
                Int32 rookFrom;
                Int32 rookTo;
                if (to < from)
                {
                    rookFrom = Rank(to) * 8;
                    rookTo   = 3 + Rank(to) * 8;
                }
                else
                {
                    rookFrom = 7 + Rank(to) * 8;
                    rookTo   = 5 + Rank(to) * 8;
                }
                Bitboard[SideToMove | Piece.Rook] ^= (1UL << rookFrom) | (1UL << rookTo);
                Bitboard[SideToMove] ^= (1UL << rookFrom) | (1UL << rookTo);
                OccupiedBitboard     ^= (1UL << rookFrom) | (1UL << rookTo);
                ZobristKey           ^= Zobrist.PiecePosition[SideToMove | Piece.Rook][rookFrom];
                ZobristKey           ^= Zobrist.PiecePosition[SideToMove | Piece.Rook][rookTo];
                Square[rookFrom]      = Piece.Empty;
                Square[rookTo]        = SideToMove | Piece.Rook;
                break;

            // Handle en passant.
            case Piece.Pawn:
                Square[File(to) + Rank(from) * 8] = Piece.Empty;
                Bitboard[special]        ^= 1UL << (File(to) + Rank(from) * 8);
                Bitboard[1 - SideToMove] ^= 1UL << (File(to) + Rank(from) * 8);
                OccupiedBitboard         ^= 1UL << (File(to) + Rank(from) * 8);
                ZobristKey ^= Zobrist.PiecePosition[special][File(to) + Rank(from) * 8];
                Material[1 - SideToMove] -= Engine.PieceValue[special];
                break;

            // Handle pawn promotion.
            default:
                Bitboard[piece]      ^= 1UL << to;
                Bitboard[special]    ^= 1UL << to;
                ZobristKey           ^= Zobrist.PiecePosition[piece][to];
                ZobristKey           ^= Zobrist.PiecePosition[special][to];
                Material[SideToMove] += Engine.PieceValue[special] - Engine.PieceValue[piece];
                Square[to]            = special;
                break;
            }

            SideToMove = 1 - SideToMove;
            FiftyMovesHistory[HalfMoves] = FiftyMovesClock;
            ZobristKeyHistory[HalfMoves] = ZobristKey;
        }