Пример #1
0
        //
        // Determine whether a Draw should be sought or avoided, by adding
        // the estimated handicap to an equal evaluation of Zero depending
        // on the game phase, and the relative strength of the two players.
        //
        protected Eval contempt()
        {
            GameState.AtomicIncrement(ref State.DrawTotal);
            var mDrawValue = (Eval)(-State.Contempt);   // Strength advantage of White over Black

            return(mDrawValue);
        }
Пример #2
0
        // ~2.3 MHz: slowed mostly by IsLegal() and only slightly by resetMove()
        protected Boolean tryMove(ref Move move, Boolean bFindRepetition = true, Boolean bQxnt = false)
        {
            CurrentMove = move;         // Current Pseudo Move
            (bool bPrevented, bool bRestricted) = isPinned(move);
            if (bPrevented)             // Skip moves which violate known pins
            {
                GameState.AtomicIncrement(ref State.PinSkipTotal);
                return(false);
            }
            //[Timer]timeMove(move);

            //
            //[Note]resetMove() is called here because it is needed for every subsequent move.  This leaves
            // a window between the time initNode() initializes a node and when resetMove() is first called.
            //
            resetMove();
            this.move(ref move);

            if (IsDraw0())
            {
                clrEval();              // Captures and Pawn moves invalidate staticEval()
            }
            //[Note]If En Passant was possible, any move ends a Transposition Group
            if (Parent.IsPassed())
            {
                setDraw0();
            }

            testHash();                 // Conditional
            var bLegal = IsLegal(bFindRepetition, bRestricted);

            if (isDefined(move))
            {
                if (bLegal)
                {
                    CurrentMove = move = annotateEarly(move);
                }
                else
                {
                    restrictPiece(move);
                }
            }

            State.IncMove(bLegal, bQxnt);
            State.MonitorBound(this);   // Pass position so heartbeat() can build getCurrentMoves()
            return(bLegal);
        }
Пример #3
0
        protected void findRepetition()
        {
            GameState.AtomicIncrement(ref State.RepetitionSearches);
            clrRepetition();
            if (IsDraw0())
            {
                return;
            }
            var bNullMade = IsNullMade();

            //
            //[Note]This search for 3-fold repetition extends to the initial position;
            // not just to State.MovePosition where the current search began.
            //
            for (var position = Parent; position is not null; position = position.Parent)
            {
                GameState.AtomicIncrement(ref State.RepetitionPlies);

                //
                // Include Positions for both sides, stopping when the Transposition Group ends.
                //
                if (Equals(position))
                {
                    if (bNullMade)
                    {
                        //
                        // Null Moves do not count as repetition of the position; but the
                        // Draw3 and Draw2 flags are copied to expedite subsequent search:
                        //
                        FlagsDraw |= position.fdr();
                    }
                    else
                    {
                        setRepetition(position.fdr() != 0);
                    }

                    break;
                }
                else if (position.IsDraw0())
                {
                    break;              // End of Transposition Group
                }
            }
#if DebugDraw2
            validateDraw2();
#endif
        }
Пример #4
0
        //
        // Lazy Capture avoids calling getPieceIndex() until it becomes necessary.
        // The purpose of the following method is to update the move and to avoid
        // calling getPieceIndex() again.
        //
        // SaveCapture is required to show captures in AppendAN() if bExpandFrom.
        //
        protected Byte captureIndex(Int32 nTo, ref Move move, out Boolean bEnPassant)
        {
            bEnPassant = false;
            var vCapture = vPieceNull;
            var uCapture = captured(move);
            var capture  = (Piece)uCapture;

            if (capture == Piece.Capture)
            {
#if CountCapturedPiece
                GameState.AtomicIncrement(ref State.CapturedPieceTotal);
#endif
                //
                // Between 2% and 20% of all Pseudo Moves require a call to getPieceIndex().
                // At the rate of 72 MHz when a Pawn is found; 68 MHz otherwise, the 1.5%
                // cost would be quite low even were it incurred for every generated move.
                //
                vCapture = getPieceIndex(nTo);

                Debug.Assert(vCapture != vPieceNull, "vCapture == vPieceNull",
                             $"There is no piece to capture on {(sq)nTo}.");
#if SaveCapture
                var captive = indexPiece(vCapture);
                move &= ~Move.CaptiveMask;
                move |= (Move)((UInt32)captive << nCaptiveBit);
#endif
            }
            else if (capture == Piece.EP)
            {
                bEnPassant = true;
                vCapture   = vP6;
            }
            else if (capture == Piece.None)
            {
                Debug.Assert(capture != Piece.None, "Unexpected Non-Capture");
            }
            else
            {
                vCapture = pieceIndex(uCapture);
            }

            Debug.Assert(vCapture != vK6, "Unknown Captive",
                         $"No captive found for {(sq)nTo}.");

            return(vCapture);
        }
Пример #5
0
        protected Eval final()
        {
            //
            // The game is over if the side to move has no move.
            // If the King is in Check, this is a Checkmate and
            // the lowest possible evaluation is given.
            //
            if (InCheck())
            {
                GameState.AtomicIncrement(ref State.MateTotal);
                return(debitMate(-MateMax, SearchPly));
            }

            //
            // If the King is not in Check, this is a Stalemate
            // and an equal evaluation is returned.
            //
            var bWTM   = WTM();
            var mValue = contempt();

            return(reflectValue(bWTM, mValue));
        }
Пример #6
0
        protected Boolean nullMove()
        {
            CurrentMove = Move.NullMove; // Current Pseudo Move
            resetMove();
            skipTurn();

            //[Note]If En Passant was possible, any move ends a Transposition Group
            if (Parent.IsPassed())
            {
                setDraw0();
            }
            testHash();                 // Conditional
            var bLegal = !InCheck();

            if (!bLegal)
            {
                throw new BoardException("Illegal Null Move");
            }

            GameState.AtomicIncrement(ref State.NullMoveTotal);
            State.MonitorBound(this);
            return(bLegal);
        }
Пример #7
0
        private Eval fullEval()
        {
            //
            //[Note]StaticEvaluations = TotalEvaluations - FullEvaluations
            // Draws are included; because they exit early.
            //
            GameState.AtomicIncrement(ref State.FullEvals);

            var mValue = staticEval(out PawnPosition pp);

            //
            // Load PawnFeature Deltas from the PawnPositions hash table,
            // based on HashPawn, the Zobrist Hashcode summed over Pawns.
            //
            if (Pawn == 0)              // PawnHash == default(Hashcode)}
            {
#if EvalKBNvKMateCorner
                if ((FlagsEG & EGFlags.KBNvK) != 0)
                {
                    var mReward = rewardKBNvKMateCorner();
                    mValue += mReward;
                }
#endif
            }
            else
            {
#if EvalOutsideSquare
                if ((FlagsEG & EGFlags.OutsideSquare) != 0)
                {
                    var mReward = punishOutsideSquare();
                    mValue += mReward;
                }
#endif
#if EvalKQvKPDistance
                if ((FlagsEG & EGFlags.KQvKP) != 0)
                {
                    var mReward = rewardKQvKPProximity();
                    mValue += mReward;
                }
#endif
#if EvalRookBehindPasser
                if (Rook != 0)
                {
#if PawnPositionByValue
                    var bDefault = (pp.BlackPRP & PRPFlags.IsValid) == 0;
#else
                    var bDefault = pp == default(PawnPosition);
#endif
                    if (bDefault)
                    {
                        pp = State.GetPXP(this);
                    }
                    const Boolean bWhiteRook        = true;
                    var           mRooksBehindBlack = rookBehindPasser(!bWhiteRook, pp.BlackPassers);
                    var           mRooksBehindWhite = rookBehindPasser(bWhiteRook, pp.WhitePassers);
#if TestRookBehindPasser
                    if (mRooksBehindBlack != 0 ||
                        mRooksBehindWhite != 0)
                    {
                        DisplayCurrent("pieceval()");
                    }
#endif
                    mValue += mRooksBehindWhite;
                    mValue -= mRooksBehindBlack;
                }
#endif
            }

            var mAbs = Abs(mValue);
            Debug.Assert(mAbs < MateMin, "Mate value returned by staticEval()");
            if (mAbs <= mDeltaBaseWeight) //[ToDo]Define a new threshold
            {
#if BuildAtxTo
                buildAtxTo(RankPiece);
#endif
#if Mobility
                mValue += mobility();
#endif
            }

            //
            // The following helps find Draw3
            //
            if (IsDraw2() && mAbs < MateMin)
            {
                mValue /= 4;            //[IBV]Care will be needed to protect the EvalType here
            }
            return(mValue);
        }
Пример #8
0
        //
        //[ToDo]Add evaluation of practical Draws where helpmate is possible:
        //
        // KKNN or KNKNN
        // KBKB opposite color
        // KNKBN, KBKBN. KBKBB pair [Note: KNKBB pair can be won; but perhaps not in 50 moves]
        //
        // More Complex Draws, assuming weaker side in time to defend:
        //
        // KKP if weaker side maintains opposition
        // Distant Opposition vs. Key/Critical Squares vs Corresponding or Relative Squares!?
        //
        // KBKBP of opposite color
        // KPKQ if P to queen on ACFH-file and sronger K too far to help
        //

        //
        // Development [initial move per piece, delaying heavy pieces]
        // Control of the Center by Pawns
        // Control of Squares around King
        // Castling and King Safety [Corner Squares] vs King Activity in the Endgame
        //
        // Rooks on Open Files
        // Rook or Queen on 7th [or 2nd] Rank
        // Protected Piece and Connected Rook Bonus
        // Knight Scope and Outpost [free of Pawn harrassment]
        // Bishop Scope [and Bad Bishop Detection]
        //
        // Bonus for Bishop with color of Promotion Square for any Passed Pawns, especially
        // Rook Pawns.  Applies to defense and Passed Opposing Pawns, as well as to offense.
        //
        // Attack Pawn Chains at the base
        // Bonus for Passed Pawn Couples
        //
        // Piece Values depending on Opening, Middle, End Game Phase and Relative Advantage:
        // Stronger side favors [vice versa Weaker side is averse to]
        // Bishops of Opposite Colors in Middle Game; and Bishops of Same Color in Endgame.
        //

        //
        // Technical and Tablebase Draws:
        // KRKRP if weaker side can attain Philidor Position
        //
        // EGTB Alternatives: Syzygy by Ronald de Man, Gaviota EGTB by Miguel A. Ballicora,
        // Nalimov by Eugene Nalimov.  Syzygy is preferred by Houdini.  It is compact; but
        // does not provide Distance to Mate (DTM).  They provide Wind-Draw-Loss (WDL) and
        // Distance to Zero (DTZ).
        //
        // The Syzygy 6-man EGTB is available at http://tablebase.sesse.net/syzygy, where
        // the (290) 3-4-5-men files require 938 MB; and (730) 6-men files require 149 GB.
        //
        protected Eval staticEval(out PawnPosition pp)  //[New]~9.666 MHz vs ~13.333 MHz w/o EvalRookBehindPasser
        {
            pp = default;
            if (IsInsufficient())
            {
                return(contempt());
            }

            GameState.AtomicIncrement(ref State.TotalEvals); // vs. FullEvaluations

            setEndGameFlags();

            if (EvalUndefined < StaticDelta)
            {
                return(StaticDelta);
            }

            //
            // Retrieve material balance from the Composition:
            //
            getValue(out Eval mDelta, out Eval mTotal);

            if (Pawn != 0)              // Else PawnHash == default(Hashcode)
            {
                pp = State.GetPXP(this);

                mDelta += pp.Delta;
                mTotal += pp.Total;
#if EvalWrongBishop
                if (punishWrongBishop(pp.BlackPRP & PRPFlags.Both, Side[Black].FlagsHi))
                {
                    mDelta += mWrongBishopWeight; // Black has Wrong Bishop
                }
                if (punishWrongBishop(pp.WhitePRP & PRPFlags.Both, Side[White].FlagsHi))
                {
                    mDelta -= mWrongBishopWeight; // White has Wrong Bishop
                }
#endif
            }
#if TradePieces
            if (mTotal > 0)
            {
                //
                // The following provides an incentive for the stronger
                // side to exchange material and for the weaker side to
                // avoid such exchanges.  The value is Zero in an equal
                // position, and grows to a maximum of one centipawn if
                // the weaker side has been stripped of all material.
                //
                // Intuitively: Exchanges reduce the Total material but
                // leave the Delta unaffected; and Delta can range from
                // Zero to the Total.  Thus, their quotient ranges from
                // Zero to One.
                //
                //[Note]A refinement is needed to prefer trading Pieces
                // over Pawns in the endgame.
                //
                var mIncentive = (Eval)(mPawnWeight * mDelta / mTotal);
                mDelta += mIncentive;
            }
#endif
            //
            //[Note]staticEval() prepares StaticTotal for any isEndgame() tests
            //
            StaticTotal = mTotal;       // Update for isEndgame()
            StaticDelta = mDelta;
            return(mDelta);
        }