Example #1
0
        static DifferBy MoveDifferFromAllOthersBy(List <MGMove> moves, MGMove thisMove)
        {
            bool differByRank = true;
            bool differByFile = true;

            foreach (MGMove move in moves)
            {
                if (move != thisMove)
                {
                    if (move.FromSquare.File == thisMove.FromSquare.File)
                    {
                        differByFile = false;
                    }

                    if (move.FromSquare.Rank == thisMove.FromSquare.Rank)
                    {
                        differByRank = false;
                    }
                }
            }

            if (differByFile)
            {
                return(DifferBy.File); // takes precedence
            }
            else if (differByRank)
            {
                return(DifferBy.Rank);
            }
            else
            {
                return(DifferBy.RankFileComo);
            }
        }
Example #2
0
        /// <summary>
        /// Copy constructor.
        /// </summary>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <param name="flags"></param>
        public MGMove(MGMove otherMove, bool flip)
        {
            if (!flip)
            {
                FromSquareIndex = otherMove.FromSquareIndex;
                ToSquareIndex   = otherMove.ToSquareIndex;
                Flags           = otherMove.Flags;
            }
            else
            {
                FromSquareIndex = FlipSquare(otherMove.FromSquareIndex);
                ToSquareIndex   = FlipSquare(otherMove.ToSquareIndex);
                Flags           = otherMove.Flags ^ MGChessMoveFlags.BlackToMove;
            }

            // Obviate requirement of definite assignment to all fields
            Unsafe.SkipInit <short>(out FromAndToCombined);
        }
Example #3
0
        /// <summary>
        /// Attempts to parse a move string in coordinate or long algebraic format.
        /// </summary>
        /// <param name="pos"></param>
        /// <param name="moveStr"></param>
        /// <param name="move"></param>
        /// <returns></returns>
        private static bool TryParseMoveCoordinateOrAlgebraic(MGPosition pos, string moveStr, out MGMove move)
        {
            moveStr = moveStr.ToLower();

            // Sometimes promotions to Knight use the "k" instead of expected "n"
            if (moveStr.EndsWith("k"))
            {
                moveStr = moveStr.Substring(0, moveStr.Length - 1) + "n";
            }

            MGMoveList moves = new MGMoveList();

            MGMoveGen.GenerateMoves(in pos, moves);
            foreach (MGMove moveTry in moves.MovesArray)
            {
                // Accept moves in any of multiple formats, including Chess 960 (for castling variation)
                if (String.Equals(moveTry.MoveStr(MGMoveNotationStyle.LC0Coordinate), moveStr, StringComparison.OrdinalIgnoreCase) ||
                    String.Equals(moveTry.MoveStr(MGMoveNotationStyle.LC0Coordinate960Format), moveStr, StringComparison.OrdinalIgnoreCase) ||
                    String.Equals(moveTry.MoveStr(MGMoveNotationStyle.LongAlgebraic), moveStr, StringComparison.OrdinalIgnoreCase))
                {
                    move = moveTry;
                    return(true);
                }
            }

            move = default;
            return(false);
        }
Example #4
0
        /// <summary>
        /// Worker method to make the move (but not switch sides).
        /// </summary>
        /// <param name="M"></param>
        void DoMakeMove(MGMove M)
        {
            Debug.Assert(M.Piece != MGPositionConstants.MCChessPositionPieceEnum.None);

            BitBoard O, To;

            To = 1UL << M.ToSquareIndex;
            O  = ~((1UL << M.FromSquareIndex) | To);
            ulong nFromSquare = M.FromSquareIndex;
            ulong nToSquare   = M.ToSquareIndex;

            // Increment ply count
            MoveNumber++;

            // Update Rule 50 count (upon any pawn move or capture)
            if (M.Capture || (byte)M.Piece == MGPositionConstants.WPAWN || (byte)M.Piece == MGPositionConstants.BPAWN)
            {
                Rule50Count = 0;
            }
            else
            {
                Rule50Count++;
            }

            // clear any enpassant squares
            BitBoard EnPassant = A & B & (~C);

            if (EnPassant != 0)
            {
                A &= ~EnPassant;
                B &= ~EnPassant;
                C &= ~EnPassant;
                D &= ~EnPassant;

#if MG_USE_HASH
                ulong nEPSquare;
                nEPSquare = MGMoveGenFillFunctions.GetSquareIndex(EnPassant);
                if (BlackToMove)
                {
                    HK ^= MGZobristKeySet.zkPieceOnSquare[MGChessPositionConstants.WENPASSANT][nEPSquare]; // Remove EP from nEPSquare
                }
                else
                {
                    HK ^= MGZobristKeySet.zkPieceOnSquare[MGChessPositionConstants.BENPASSANT][nEPSquare]; // Remove EP from nEPSquare
                }
#endif
            }


            // APPLY CASTLING MOVES:
            // we use magic XOR-tricks to do the job ! :

            // The following is for O-O:
            //
            //    K..R          .RK.
            // A: 1000 ^ 1010 = 0010
            // B: 1000 ^ 1010 = 0010
            // C: 1001 ^ 1111 = 0110
            // For Black:
            // D: 1001 ^ 1111 = 0110
            // For White:
            // D &= 0xfffffffffffffff0 (ie clear colour of affected squares from K to KR)

            // The following is for O-O-O:
            //
            //    R... K...                      ..KR ....
            // A: 0000 1000 ^ 0010 1000 (0x28) = 0010 0000
            // B: 0000 1000 ^ 0010 1000 (0x28) = 0010 0000
            // C: 1000 1000 ^ 1011 1000 (0xB8) = 0011 0000
            // For Black:
            // D: 1000 1000 ^ 1011 1000 (0xB8) = 0011 0000
            // For White:
            // D &= 0xffffffffffffff07 (ie clear colour of affected squares from QR to K)

            if ((byte)M.Piece == MGPositionConstants.BKING)
            {
                if (M.CastleShort)
                {
                    A ^= 0x0a00000000000000;
                    B ^= 0x0a00000000000000;
                    C ^= 0x0f00000000000000;
                    D ^= 0x0f00000000000000;

#if MG_USE_HASH
                    HK ^= MGZobristKeySet.zkDoBlackCastle;
                    if (BlackCanCastleLong)
                    {
                        HK ^= MGZobristKeySet.zkBlackCanCastleLong;                         // conditionally flip black castling long
                    }
#endif
                    Flags |= FlagsEnum.BlackDidCastle;

                    //  bf = bf &= ~BitFields.DrawerPresenceSw; //attackType &= ~ AttackType.Fire;

                    Flags &= ~FlagsEnum.BlackCanCastle;
                    Flags &= ~FlagsEnum.BlackCanCastleLong;
                    return;
                }
                else if (M.CastleLong)
                {
                    A ^= 0x2800000000000000;
                    B ^= 0x2800000000000000;
                    C ^= 0xb800000000000000;
                    D ^= 0xb800000000000000;

#if MG_USE_HASH
                    HK ^= MGZobristKeySet.zkDoBlackCastleLong;
                    if (BlackCanCastle)
                    {
                        HK ^= MGZobristKeySet.zkBlackCanCastle;                       // conditionally flip black castling
                    }
#endif
                    BlackDidCastleLong = true;
                    BlackCanCastle     = false;
                    BlackCanCastleLong = false;
                    return;
                }
                else
                {
                    // ordinary king move
                    if (BlackCanCastle || BlackCanCastleLong)
                    {
                        // Black could have castled, but chose to move the King in a non-castling move
#if MG_USE_HASH
                        if (BlackCanCastle)
                        {
                            HK ^= MGZobristKeySet.zkBlackCanCastle;                             // conditionally flip black castling
                        }
                        if (BlackCanCastleLong)
                        {
                            HK ^= MGZobristKeySet.zkBlackCanCastleLong;                              // conditionally flip black castling long
                        }
#endif
                        BlackForfeitedCastle     = true;
                        BlackForfeitedCastleLong = true;
                        BlackCanCastle           = false;
                        BlackCanCastleLong       = false;
                    }
                }
            }

            else if ((byte)M.Piece == MGPositionConstants.WKING)
            {
                // White
                if (M.CastleShort)
                {
                    A ^= 0x000000000000000a;
                    B ^= 0x000000000000000a;
                    C ^= 0x000000000000000f;
                    D &= 0xfffffffffffffff0; // clear colour of e1,f1,g1,h1 (make white)

#if MG_USE_HASH
                    HK ^= MGZobristKeySet.zkDoWhiteCastle;
                    if (WhiteCanCastleLong)
                    {
                        HK ^= MGZobristKeySet.zkWhiteCanCastleLong;                         // conditionally flip white castling long
                    }
#endif
                    WhiteDidCastle     = true;
                    WhiteCanCastle     = false;
                    WhiteCanCastleLong = false;
                    return;
                }

                if (M.CastleLong)
                {
                    A ^= 0x0000000000000028;
                    B ^= 0x0000000000000028;
                    C ^= 0x00000000000000b8;
                    D &= 0xffffffffffffff07; // clear colour of a1,b1,c1,d1,e1 (make white)
#if MG_USE_HASH
                    HK ^= MGZobristKeySet.zkDoWhiteCastleLong;
                    if (WhiteCanCastle)
                    {
                        HK ^= MGZobristKeySet.zkWhiteCanCastle;                     // conditionally flip white castling
                    }
#endif
                    WhiteDidCastleLong = true;
                    WhiteCanCastle     = false;
                    WhiteCanCastleLong = false;
                    return;
                }

                else
                {
                    // ordinary king move
                    if (WhiteCanCastle)
                    {
#if MG_USE_HASH
                        HK ^= MGZobristKeySet.zkWhiteCanCastle;         // flip white castling
#endif
                        WhiteForfeitedCastle = true;
                        WhiteCanCastle       = false;
                    }
                    if (WhiteCanCastleLong)
                    {
#if MG_USE_HASH
                        HK ^= MGZobristKeySet.zkWhiteCanCastleLong;             // flip white castling long
#endif
                        WhiteForfeitedCastleLong = true;
                        WhiteCanCastleLong       = false;
                    }
                }
            }

            // LOOK FOR FORFEITED CASTLING RIGHTS DUE to ROOK MOVES:
            else if ((byte)M.Piece == MGPositionConstants.BROOK)
            {
                //	if((1LL<<nFromSquare) & BLACKKRPOS)
                if (nFromSquare == 56)
                {
                    // Black moved K-side Rook and forfeits right to castle K-side
                    if (BlackCanCastle)
                    {
                        BlackForfeitedCastle = true;
#if MG_USE_HASH
                        HK ^= MGZobristKeySet.zkBlackCanCastle;                 // flip black castling
#endif
                        BlackCanCastle = false;
                    }
                }
                //else if ((1LL<<nFromSquare) & BLACKQRPOS)
                else if (nFromSquare == 63)
                {
                    // Black moved the QS Rook and forfeits right to castle Q-side
                    if (BlackCanCastleLong)
                    {
                        BlackForfeitedCastleLong = true;
#if MG_USE_HASH
                        HK ^= MGZobristKeySet.zkBlackCanCastleLong;             // flip black castling long
#endif
                        BlackCanCastleLong = false;
                    }
                }
            }

            else if ((byte)M.Piece == MGPositionConstants.WROOK)
            {
                //if((1LL<<nFromSquare) & WHITEKRPOS)
                if (nFromSquare == 0)
                {
                    // White moved K-side Rook and forfeits right to castle K-side
                    if (WhiteCanCastle)
                    {
                        WhiteForfeitedCastle = true;
#if MG_USE_HASH
                        HK ^= MGZobristKeySet.zkWhiteCanCastle;         // flip white castling BROKEN !!!
#endif
                        WhiteCanCastle = false;
                    }
                }
                //	else if((1LL<<nFromSquare) & WHITEQRPOS)
                else if (nFromSquare == 7)
                {
                    // White moved the QSide Rook and forfeits right to castle Q-side
                    if (WhiteCanCastleLong)
                    {
                        WhiteForfeitedCastleLong = true;
#if MG_USE_HASH
                        HK ^= MGZobristKeySet.zkWhiteCanCastleLong;             // flip white castling long
#endif
                        WhiteCanCastleLong = false;
                    }
                }
            }

            // Ordinary Captures	////
            if (M.Capture)
            {
                ulong capturedpiece;

#if NOWAY
                //defined (_WIN64) && defined (_USE_BITTEST_INSTRUCTION)
                const long long d = D;
                const long long c = C;
                const long long b = B;
                const long long a = A;

                // using BitTest Intrinsic:
                capturedpiece = _bittest64(&d, nToSquare) << 3
                                | _bittest64(&c, nToSquare) << 2
                                | _bittest64(&b, nToSquare) << 1
                                | _bittest64(&a, nToSquare);
#else
                // find out which piece has been captured:

                // Branchless version:
                BitBoard bbCap = ((D & To) >> (int)nToSquare) << 3
                                 | ((C & To) >> (int)nToSquare) << 2
                                 | ((B & To) >> (int)nToSquare) << 1
                                 | ((A & To) >> (int)nToSquare);
                capturedpiece = (ulong)bbCap;
#endif

#if MG_USE_HASH
                // Update Hash
                HK ^= MGZobristKeySet.zkPieceOnSquare[capturedpiece][nToSquare];   // Remove captured Piece
#endif
            }

            // Render "ordinary" moves:
            A &= O;
            B &= O;
            C &= O;
            D &= O;

            // Populate new square (Branchless method):
            A |= (BitBoard)(((ulong)M.Piece & 1) << M.ToSquareIndex);
            B |= (BitBoard)((((ulong)M.Piece & 2) >> 1) << M.ToSquareIndex);
            C |= (BitBoard)((((ulong)M.Piece & 4) >> 2) << M.ToSquareIndex);
            D |= (BitBoard)((((ulong)M.Piece & 8) >> 3) << M.ToSquareIndex);

#if MG_USE_HASH
            // Update Hash
            HK ^= MGZobristKeySet.zkPieceOnSquare[(int)M.Piece][nFromSquare]; // Remove piece at From square
            HK ^= MGZobristKeySet.zkPieceOnSquare[(int)M.Piece][nToSquare];   // Place piece at To Square
#endif

            // Promotions - Change the piece:

            if (M.PromoteBishop)
            {
                A &= ~To;
                B |= To;
#if MG_USE_HASH
                HK ^= MGZobristKeySet.zkPieceOnSquare[M.BlackToMove ? MGChessPositionConstants.BPAWN : MGChessPositionConstants.WPAWN][nToSquare];     // Remove pawn at To square
                HK ^= MGZobristKeySet.zkPieceOnSquare[M.BlackToMove ? MGChessPositionConstants.BBISHOP : MGChessPositionConstants.WBISHOP][nToSquare]; // place Bishop at To square
#endif
                M.Piece = M.BlackToMove ? MGPositionConstants.MCChessPositionPieceEnum.BlackBishop : MGPositionConstants.MCChessPositionPieceEnum.WhiteBishop;
                //
                return;
            }

            else if (M.PromoteKnight)
            {
                C |= To;
#if MG_USE_HASH
                HK ^= MGZobristKeySet.zkPieceOnSquare[M.BlackToMove ? MGChessPositionConstants.BPAWN : MGChessPositionConstants.WPAWN][nToSquare];     // Remove pawn at To square
                HK ^= MGZobristKeySet.zkPieceOnSquare[M.BlackToMove ? MGChessPositionConstants.BKNIGHT : MGChessPositionConstants.WKNIGHT][nToSquare]; // place Knight at To square
#endif
                M.Piece = M.BlackToMove ? MGPositionConstants.MCChessPositionPieceEnum.BlackKnight : MGPositionConstants.MCChessPositionPieceEnum.WhiteKnight;
                //
                return;
            }

            else if (M.PromoteRook)
            {
                A &= ~To;
                C |= To;
#if MG_USE_HASH
                HK ^= MGZobristKeySet.zkPieceOnSquare[M.BlackToMove ? MGChessPositionConstants.BPAWN : MGChessPositionConstants.WPAWN][nToSquare]; // Remove pawn at To square
                HK ^= MGZobristKeySet.zkPieceOnSquare[M.BlackToMove ? MGChessPositionConstants.BROOK : MGChessPositionConstants.WROOK][nToSquare]; // place Rook at To square
#endif
                M.Piece = M.BlackToMove ? MGPositionConstants.MCChessPositionPieceEnum.BlackRook : MGPositionConstants.MCChessPositionPieceEnum.WhiteRook;
                //
                return;
            }

            else if (M.PromoteQueen)
            {
                A &= ~To;
                B |= To;
                C |= To;
#if MG_USE_HASH
                HK ^= MGZobristKeySet.zkPieceOnSquare[M.BlackToMove ? MGChessPositionConstants.BPAWN : MGChessPositionConstants.WPAWN][nToSquare];   // Remove pawn at To square
                HK ^= MGZobristKeySet.zkPieceOnSquare[M.BlackToMove ? MGChessPositionConstants.BQUEEN : MGChessPositionConstants.WQUEEN][nToSquare]; // place Queen at To square
#endif
                M.Piece = M.BlackToMove ? MGPositionConstants.MCChessPositionPieceEnum.BlackQueen : MGPositionConstants.MCChessPositionPieceEnum.WhiteQueen;
                //
                return;
            }

            // For Double-Pawn Moves, set EP square:	////
            else if (M.DoublePawnMove)
            {
                // Set EnPassant Square
                if (M.BlackToMove)
                {
                    To <<= 8;
                    A   |= To;
                    B   |= To;
                    C   &= ~To;
                    D   |= To;

#if MG_USE_HASH
                    HK ^= MGZobristKeySet.zkPieceOnSquare[MGChessPositionConstants.BENPASSANT][nToSquare + 8];          // Place Black EP at (To+8)
#endif
                }
                else
                {
                    To >>= 8;
                    A   |= To;
                    B   |= To;
                    C   &= ~To;
                    D   &= ~To;

#if MG_USE_HASH
                    HK ^= MGZobristKeySet.zkPieceOnSquare[MGChessPositionConstants.WENPASSANT][nToSquare - 8]; // Place White EP at (To-8)
#endif
                }
                //
                return;
            }

            // En-Passant Captures	////
            else if (M.EnPassantCapture)
            {
                // remove the actual pawn (it is different to the capture square)
                if (M.BlackToMove)
                {
                    To <<= 8;
                    A   &= ~To; // clear the pawn's square
                    B   &= ~To;
                    C   &= ~To;
                    D   &= ~To;
                    //	material -= 100; // perft doesn't care
#if MG_USE_HASH
                    HK ^= MGZobristKeySet.zkPieceOnSquare[MGChessPositionConstants.WPAWN][nToSquare + 8]; // Remove WHITE Pawn at (To+8)
#endif
                }
                else
                {
                    To >>= 8;
                    A   &= ~To;
                    B   &= ~To;
                    C   &= ~To;
                    D   &= ~To;
                    //	material += 100; // perft doesn't care
#if MG_USE_HASH
                    HK ^= MGZobristKeySet.zkPieceOnSquare[MGChessPositionConstants.BPAWN][nToSquare - 8]; // Remove BLACK Pawn at (To-8)
#endif
                }
            }
        }
Example #5
0
 /// <summary>
 /// Modifies this position to reflect a specified move having been made.
 /// </summary>
 /// <param name="M"></param>
 public void MakeMove(MGMove M)
 {
     DoMakeMove(M);
     SwitchSides();
 }
Example #6
0
        public static string AlgebraicMoveString(MGMove mgMove, Position pos)
        {
            string ret = null;

            bool white = pos.MiscInfo.SideToMove == SideType.White;

            MGPosition curPosition = MGChessPositionConverter.MGChessPositionFromFEN(pos.FEN);

            // Generate moves
            MGMoveList moves = new MGMoveList();

            MGMoveGen.GenerateMoves(in curPosition, moves);

            //if (white) mgMove = new MGMove(mgMove, true);
            MGPosition newPosition = MGChessPositionConverter.MGChessPositionFromFEN(pos.FEN);

            newPosition.MakeMove(mgMove);

            bool isCheck = MGMoveGen.IsInCheck(newPosition, white);

            if (mgMove.CastleShort)
            {
                ret = "O-O";
            }
            else if (mgMove.CastleLong)
            {
                ret = "O-O-O";
            }

            else
            {
                Square fromSquare = mgMove.FromSquare;
                Square toSquare   = mgMove.ToSquare;

                Piece fromType = pos.PieceOnSquare(fromSquare);
                Piece toPiece  = pos.PieceOnSquare(toSquare);

                if (fromType.Type == PieceType.Pawn)
                {
                    string promoteChar = "";
                    if (mgMove.PromoteQueen)
                    {
                        promoteChar = "Q";
                    }
                    if (mgMove.PromoteBishop)
                    {
                        promoteChar = "B";
                    }
                    if (mgMove.PromoteRook)
                    {
                        promoteChar = "R";
                    }
                    if (mgMove.PromoteKnight)
                    {
                        promoteChar = "N";
                    }

                    if (mgMove.EnPassantCapture)
                    {
                        int  newRank = white ? 6 : 3;
                        char newFile = char.ToLower(toSquare.FileChar);
                        ret = fromSquare.ToString().Substring(0, 1).ToLower() + "x" +
                              newFile + newRank;
                    }
                    else if (toPiece.Type == PieceType.None)
                    {
                        ret = toSquare.ToString().ToLower() + promoteChar;
                    }
                    else
                    {
                        ret = fromSquare.ToString().Substring(0, 1).ToLower() + "x" +
                              toSquare.ToString().ToLower() + promoteChar;
                    }
                }
                else
                {
                    string captureChar = toPiece.Type == PieceType.None ? "" : "x";

                    List <MGMove> matchingCaptures = MovesByPieceTypeThatTakeOnSquare(mgMove.Piece, mgMove.ToSquareIndex, moves);
                    if (matchingCaptures.Count == 1)
                    {
                        ret = char.ToUpper(fromType.Char) + captureChar + toSquare.ToString().ToLower();
                    }
                    else
                    {
                        // Disambiguate
                        DifferBy differBy = MoveDifferFromAllOthersBy(matchingCaptures, mgMove);
                        string   fileChar = fromSquare.FileChar.ToString().ToLower();
                        string   rankChar = fromSquare.RankChar.ToString().ToLower();

                        if (differBy == DifferBy.File)
                        {
                            ret = char.ToUpper(fromType.Char) + fileChar + captureChar + toSquare.ToString().ToLower();
                        }
                        else if (differBy == DifferBy.Rank)
                        {
                            ret = char.ToUpper(fromType.Char) + rankChar + captureChar + toSquare.ToString().ToLower();
                        }
                        else
                        {
                            ret = char.ToUpper(fromType.Char) + fileChar + rankChar + captureChar + toSquare.ToString().ToLower();
                        }
                    }
                }
            }

            if (isCheck)
            {
                return(ret + "+");
            }
            else
            {
                return(ret);
            }
        }
Example #7
0
        /// <summary>
        /// Attempts to parse a move string in coordinate or long algebraic format.
        /// </summary>
        /// <param name="pos"></param>
        /// <param name="moveStr"></param>
        /// <param name="move"></param>
        /// <returns></returns>
        private static bool TryParseMoveCoordinateOrAlgebraic(MGPosition pos, string moveStr, out MGMove move)
        {
            moveStr = moveStr.ToLower();

            // Sometimes promotions to Knight use the "k" instead of expected "n"
            if (moveStr.EndsWith("k"))
            {
                moveStr = moveStr.Substring(0, moveStr.Length - 1) + "n";
            }

            MGMoveList moves = new MGMoveList();

            MGMoveGen.GenerateMoves(in pos, moves);
            foreach (MGMove moveTry in moves.MovesArray)
            {
                if (moveTry.MoveStr(MGMoveNotationStyle.LC0Coordinate).ToLower() == moveStr ||
                    (moveTry.MoveStr(MGMoveNotationStyle.LongAlgebraic).ToLower() == moveStr))
                {
                    move = moveTry;
                    return(true);
                }
            }

            move = default;
            return(false);
        }