public Eval Search(Draft wDraft, Eval mAlpha, Eval mBeta, Move moveExcluded = Move.Undefined) { var moves = PseudoMoves; BestMoves.Clear(); //[Required] #region Test for Draw if (IsDraw()) { //[Note]setDraw50() must be called after tryMove(), below. State.IncEvalType(EvalType.Exact); return eval(); } #endregion #region Test for entry into Quiet Search var bInCheck = InCheck(); if (bInCheck) { // Check Extension if (extended(ref wDraft, SearchExtensions.Check)) AtomicIncrement(ref State.CheckExtCount); } // // Depth is tested here, rather than in the PVS recursion case, // because search also recurses from the heuristic cases below. // var wDepth = depth(wDraft); // InCheck Adjusted Depth if (wDepth < 1) { #if Quiescence return quiet(mAlpha, mBeta); #else return boundValue(eval(), mAlpha, mBeta); #endif } #endregion #region Transposition Table Lookup #if TraceVal var bTrace = IsTrace(); if (IsTrace()) { //[Note]CurrentMove Undefined Display($"Search(Depth = {wDepth})"); } #endif Debug.Assert(mAlpha < mBeta, "Alpha must be less than Beta"); var goodMoves = new List<GoodMove>(nFirstCapacity); var bFoundValue = probeXP(wDepth, mAlpha, mBeta, moveExcluded, goodMoves, out Move moveFound, out Eval mValueFound, out EvalType etFound); // Variations updated iff bFoundValue if (bFoundValue) { // moveFound not always defined for EvalType.Upper [Fail Low] if (isDefinite(moveFound)) { //[Safe]Also prevent unexpected EmptyMove #if DebugMove unpackMove1(moveFound, out sq sqFrom, out sq sqTo, out Piece piece, out Piece promotion, out Boolean bCapture); //unpackMove2(moveFound, out sq sqFrom, out sq sqTo, out Piece piece, out Piece promotion, out Piece capture, out Boolean bCastles, out Boolean bCapture); #endif if (IsMovePosition) // Pass empty BestMoves, at top level AddPV(mAlpha, mValueFound, moveFound, BestMoves); #if AddBestMoves BestMoves.Add(moveFound); // Safe to update BestMoves now #endif } return mValueFound; } #endregion #region Heuristic Tests var bReduced = (FlagsMode & ModeFlags.Reduced) != 0; if (bReduced) AtomicIncrement(ref State.ReducedTotal); var bTestSingular = false; var bPruneQuiet = false; var bPVS = (FlagsMode & ModeFlags.ZWS) == 0; var bMoveExcluded = isDefined(moveExcluded); var wReducedDraft = reduceShallow(wDraft);// Draft for Heuristic Searches if (!bInCheck) { var mStand = standpatval(mValueFound, etFound); if (!bPVS) { if (prune(wDraft, wDepth, mAlpha, mBeta, mValueFound, etFound, bMoveExcluded, out Eval mPrunedValue)) return mPrunedValue; } if (!bReduced) { //[Conditional] threat(ref wDraft, ref wReducedDraft, ref wDepth); } // Determine whether Futility Pruning should be performed at Frontier Nodes: if (State.IsFutility && 0 < wDepth) { var bNonMateWindow = -MateMin < mAlpha && mBeta < MateMin; var bNonEndGame = (FlagsEG & EGFlags.EndGame) == 0; if (bNonMateWindow && bNonEndGame) { var nMargin = wDepth - 1; if (nMargin < FutilityMargin.Length) bPruneQuiet = mStand + FutilityMargin[nMargin] <= mAlpha; } } // Futility Pruning #if SingularExtension bTestSingular = wSingularDepthMin <= wDepth && EvalUndefined < mValueFound && //[Test]More inclusion performs better than less! Abs(mValueFound) < mQueenWeight && isDefined(moveFound) && !(bReduced || bMoveExcluded) && canExtend(vSingular); //[Ergo]child.canExtend(vSingular) below #endif } // !bInCheck #endregion #region Generate Moves // // The "go searchmoves" UCI command sets SearchMoves // to restrict the set of candidate moves at the Root: // if (SearchMoves is not null && SearchMoves.Count > 0) { moves.Clear(); moves.AddRange(SearchMoves); #if DebugSearchMoves var sb = new StringBuilder("SearchMoves:"); sb.MapMoves(Extension.AppendPACN, moves, State.Rule); LogLine(sb.ToString()); #endif }
protected Eval quiet(Eval mAlpha, Eval mBeta) { var moves = PseudoMoves; BestMoves.Clear(); //[Required] #region Test for Draw if (IsDraw()) //[Note]setDraw50() will not be called below { State.IncEvalType(EvalType.Exact); #if TransposeQuiet return(eval()); #else return(boundValue(eval(), mAlpha, mBeta)); #endif } #endregion #region Transposition Table Lookup #if TraceVal var bTrace = IsTrace(); if (bTrace) { const String sLabel = "quiet()"; Display(sLabel); //[Note]Undefined CurrentMove } #endif // BestMoves updated iff bFoundValue if (probeQxnt(mAlpha, mBeta, out Move moveFound, out Eval mValueFound, out EvalType etFound)) { // moveFound not always defined for EvalType.Upper [Fail Low] if (isDefinite(moveFound)) //[Safe]Also prevent unexpected EmptyMove { #if DebugMove unpackMove1(moveFound, out sq sqFrom, out sq sqTo, out Piece piece, out Piece promotion, out Boolean bCapture); //unpackMove2(moveFound, out sq sqFrom, out sq sqTo, out Piece piece, out Piece promotion, out Piece capture, out Boolean bCastles, out Boolean bCapture); #endif #if AddBestMoves BestMoves.Add(moveFound); #endif } return(mValueFound); } #endregion #region Move Loop Initializaton #if QuietCheck || QuietMate var bInCheck = InCheck(); #endif var et = EvalType.Upper; //[Init]Fail Low is the default assumption // Stand Pat (tests Draw Flags) var mStand = standpatval(mValueFound, etFound); var moveBest = Move.Undefined; //[Init] var mValue = EvalUndefined; var mBest = EvalUndefined; var bStandPat = mAlpha /*+ mStandPatWeight*/ < mStand; if (bStandPat) { mBest = mStand; if (mAlpha < mBest) { mAlpha = mBest; } } #endregion if (mBeta <= mAlpha) { //[Test]return boundValue(mBest, mAlpha, mBeta); } else { #region Generate Moves if (SearchMoves is not null && SearchMoves.Count > 0) { moves.Clear(); moves.AddRange(SearchMoves); #if DebugSearchMoves var sb = new StringBuilder("SearchMoves:"); sb.MapMoves(Extension.AppendPACN, moves, State.Rule); sb.FlushLine(); #endif }