// 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) { var sia = StateInfoArrayBroker.GetObject(); var stPos = 0; TTEntry tte; bool tteHasValue; int v, m = 0; var ply = 0; uint ttePos = 0; do { tteHasValue = TT.probe(pos.key(), ref ttePos, out tte); if ((!tteHasValue) || tte.move() != this.pv[ply]) // Don't overwrite existing correct entries { if (pos.in_check()) { v = m = ValueC.VALUE_NONE; } else { v = Evaluate.do_evaluate(false, pos, ref m); } TT.store(pos.key(), ValueC.VALUE_NONE, Bound.BOUND_NONE, DepthC.DEPTH_NONE, this.pv[ply], v, m); } Debug.Assert(pos.move_is_legal(pv[ply])); pos.do_move(this.pv[ply++], sia.state[stPos++]); } while (this.pv[ply] != MoveC.MOVE_NONE); while (ply != 0) { pos.undo_move(this.pv[--ply]); } StateInfoArrayBroker.Free(); }
/// move_to_san() takes a position and a legal Move as input and returns its /// short algebraic notation representation. internal static string move_to_san(Position pos, int m) { if (m == MoveC.MOVE_NONE) { return "(none)"; } if (m == MoveC.MOVE_NULL) { return "(null)"; } Debug.Assert(pos.move_is_legal(m)); Bitboard others, b; Color us = pos.sideToMove; var san = new StringBuilder(); Square from = from_sq(m); Square to = to_sq(m); Piece pc = pos.piece_on(from); PieceType pt = type_of(pc); if (type_of_move(m) == MoveTypeC.CASTLING) { san.Append(to > from ? "O-O" : "O-O-O"); } else { if (pt != PieceTypeC.PAWN) { san.Append(PieceToChar[ColorC.WHITE][pt]); // Upper case // Disambiguation if we have more then one piece of type 'pt' that can // reach 'to' with a legal move. others = b = (pos.attacks_from_PS(pc, to) & pos.pieces_PTC(pt, us)) ^ (ulong)from; while (others != 0) { Move move = make_move(pop_lsb(ref b), to); if (!pos.pl_move_is_legal(move, pos.pinned_pieces())) { others ^= (ulong)from_sq(move); } } if (others != 0) { if ((others & file_bb_S(from)) == 0) { san.Append(file_to_char(file_of(from))); } else if ((others & rank_bb_S(from)) == 0) { san.Append(rank_to_char(rank_of(from))); } else { san.Append(square_to_string(from)); } } } else if (pos.is_capture(m)) { san.Append(file_to_char(file_of(from))); } if (pos.is_capture(m)) { san.Append('x'); } san.Append(square_to_string(to)); if (type_of_move(m) == MoveTypeC.PROMOTION) { san.Append('='); san.Append(PieceToChar[ColorC.WHITE][promotion_type(m)]); } } var ci = CheckInfoBroker.GetObject(); ci.CreateCheckInfo(pos); if (pos.move_gives_check(m, ci)) { var st = new StateInfo(); pos.do_move(m, st); var mlist = MListBroker.GetObject(); mlist.pos = 0; Movegen.generate_legal(pos, mlist.moves, ref mlist.pos); san.Append(mlist.pos > 0 ? "+" : "#"); MListBroker.Free(); pos.undo_move(m); } CheckInfoBroker.Free(); return san.ToString(); }
/// 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(); }