/// RootMove::extract_pv_from_tt() builds a PV by adding moves from the TT table. /// We consider also failing high nodes and not only BOUND_EXACT nodes so to /// allow to always have a ponder move even when we fail high at root, and a /// long PV to print that is important for position analysis. internal void extract_pv_from_tt(Position pos) { StateInfoArray sia = StateInfoArrayBroker.GetObject(); int stPos = 0; TTEntry tte; int ply = 1; Move m = pv[0]; Debug.Assert(m != MoveC.MOVE_NONE && pos.is_pseudo_legal(m)); pv.Clear(); pv.Add(m); pos.do_move(m, sia.state[stPos++]); UInt32 ttePos = 0; while (TT.probe(pos.key(), ref ttePos, out tte) && (m = tte.move()) != MoveC.MOVE_NONE // Local copy, TT entry could change && pos.is_pseudo_legal(m) && pos.pl_move_is_legal(m, pos.pinned_pieces()) && ply < Constants.MAX_PLY && (!pos.is_draw(false) || ply < 2)) { pv.Add(m); pos.do_move(m, sia.state[stPos++]); ply++; } pv.Add(MoveC.MOVE_NONE); do pos.undo_move(pv[--ply]); while (ply != 0); StateInfoArrayBroker.Free(); }
// insert_pv_in_tt() is called at the end of a search iteration, and inserts // the PV back into the TT. This makes sure the old PV moves are searched // first, even if the old TT entries have been overwritten. internal void insert_pv_in_tt(Position pos) { StateInfoArray sia = StateInfoArrayBroker.GetObject(); int stPos = 0; TTEntry tte; bool tteHasValue; Key k; Value v, m = ValueC.VALUE_NONE; int ply = 0; UInt32 ttePos = 0; Debug.Assert(pv[ply] != MoveC.MOVE_NONE && pos.is_pseudo_legal(pv[ply])); do { k = pos.key(); tteHasValue = TT.probe(k, ref ttePos, out tte); // Don't overwrite existing correct entries if ((!tteHasValue) || tte.move() != pv[ply]) { v = (pos.in_check() ? ValueC.VALUE_NONE : Evaluate.do_evaluate(false, pos, ref m)); TT.store(k, ValueC.VALUE_NONE, Bound.BOUND_NONE, DepthC.DEPTH_NONE, pv[ply], v, m); } pos.do_move(pv[ply], sia.state[stPos++]); } while (pv[++ply] != MoveC.MOVE_NONE); do pos.undo_move(pv[--ply]); while (ply != 0); StateInfoArrayBroker.Free(); }
internal void MovePickerC(Position p, Move ttm, History h, PieceType pt) { pos = p; H = h; curMovePos = 0; lastMovePos = 0; Debug.Assert(!pos.in_check()); depth = 0; ttMove = 0; lastQuietPos = 0; lastBadCapturePos = 0; mpos = 0; phase = SequencerC.PROBCUT; // In ProbCut we generate only captures better than parent's captured piece captureThreshold = Position.PieceValueMidgame[pt]; ttMove = ((ttm != 0) && pos.is_pseudo_legal(ttm) ? ttm : MoveC.MOVE_NONE); if ((ttMove != 0) && (!pos.is_capture(ttMove) || pos.see(ttMove, false) <= captureThreshold)) ttMove = MoveC.MOVE_NONE; lastMovePos += ((ttMove != MoveC.MOVE_NONE) ? 1 : 0); }
internal void MovePickerC(Position p, Move ttm, Depth d, History h, Square sq) { pos = p; H = h; curMovePos = 0; lastMovePos = 0; Debug.Assert(d <= DepthC.DEPTH_ZERO); depth = 0; recaptureSquare = 0; captureThreshold = 0; lastQuietPos = 0; lastBadCapturePos = 0; mpos = 0; if (p.in_check()) phase = SequencerC.EVASION; else if (d > DepthC.DEPTH_QS_NO_CHECKS) phase = SequencerC.QSEARCH_0; else if (d > DepthC.DEPTH_QS_RECAPTURES) { phase = SequencerC.QSEARCH_1; // Skip TT move if is not a capture or a promotion, this avoids qsearch // tree explosion due to a possible perpetual check or similar rare cases // when TT table is full. if ((ttm != 0) && !pos.is_capture_or_promotion(ttm)) ttm = MoveC.MOVE_NONE; } else { phase = SequencerC.RECAPTURE; recaptureSquare = sq; ttm = MoveC.MOVE_NONE; } ttMove = ((ttm != 0) && pos.is_pseudo_legal(ttm) ? ttm : MoveC.MOVE_NONE); lastMovePos += ((ttMove != MoveC.MOVE_NONE) ? 1 : 0); }
/// Constructors of the MovePicker class. As arguments we pass information /// to help it to return the presumably good moves first, to decide which /// moves to return (in the quiescence search, for instance, we only want to /// search captures, promotions and some checks) and about how important good /// move ordering is at the current node. internal void MovePickerC(Position p, Move ttm, Depth d, History h, Stack ss, Value beta, MovePicker mpExt) { pos = p; H = h; depth = d; mpExternal = mpExt; Debug.Assert(d > DepthC.DEPTH_ZERO); captureThreshold = 0; curMovePos = lastMovePos = 0; lastBadCapturePos = Constants.MAX_MOVES - 1; recaptureSquare = 0; lastQuietPos = 0; mpos = 0; if (p.in_check()) { phase = SequencerC.EVASION; } else { phase = SequencerC.MAIN_SEARCH; ms[Constants.MAX_MOVES].move = ss.killers0; ms[Constants.MAX_MOVES + 1].move = ss.killers1; // Consider sligtly negative captures as good if at low depth and far from beta if (ss.eval < beta - Constants.PawnValueMidgame && d < 3 * DepthC.ONE_PLY) captureThreshold = -Constants.PawnValueMidgame; // Consider negative captures as good if still enough to reach beta else if (ss.eval > beta) captureThreshold = beta - ss.eval; } ttMove = (ttm != 0 && pos.is_pseudo_legal(ttm) ? ttm : MoveC.MOVE_NONE); lastMovePos += ((ttMove != MoveC.MOVE_NONE) ? 1 : 0); }
/// RootMove::extract_pv_from_tt() builds a PV by adding moves from the TT table. /// We consider also failing high nodes and not only BOUND_EXACT nodes so to /// allow to always have a ponder move even when we fail high at root, and a /// long PV to print that is important for position analysis. internal void extract_pv_from_tt(Position pos) { var sia = StateInfoArrayBroker.GetObject(); var stPos = 0; TTEntry tte; bool tteHasValue; var ply = 0; var m = this.pv[0]; this.pv.Clear(); uint ttePos = 0; do { this.pv.Add(m); Debug.Assert(pos.move_is_legal(pv[ply])); pos.do_move(pv[ply++], sia.state[stPos++]); tteHasValue = TT.probe(pos.key(), ref ttePos, out tte); } while (tteHasValue && pos.is_pseudo_legal(m = tte.move()) // Local copy, TT could change && pos.pl_move_is_legal(m, pos.pinned_pieces()) && ply < Constants.MAX_PLY && (!pos.is_draw(false) || ply < 2)); ; this.pv.Add(MoveC.MOVE_NONE); // Must be zero-terminating while (ply != 0) { pos.undo_move(this.pv[--ply]); } StateInfoArrayBroker.Free(); }