internal void CreateCheckInfo(Position pos) { Color them = pos.sideToMove ^ 1; ksq = pos.pieceList[them][PieceTypeC.KING][0]; pinned = pos.pinned_pieces(); dcCandidates = pos.discovered_check_candidates(); checkSq[PieceTypeC.PAWN] = Utils.StepAttacksBB[((them << 3) | PieceTypeC.PAWN)][ksq]; checkSq[PieceTypeC.KNIGHT] = Utils.StepAttacksBB_KNIGHT[ksq]; #if X64 checkSq[PieceTypeC.BISHOP] = Utils.BAttacks[ksq][(((pos.occupied_squares & Utils.BMasks[ksq]) * Utils.BMagics[ksq]) >> Utils.BShifts[ksq])]; checkSq[PieceTypeC.ROOK] = Utils.RAttacks[ksq][(((pos.occupied_squares & Utils.RMasks[ksq]) * Utils.RMagics[ksq]) >> Utils.RShifts[ksq])]; #else checkSq[PieceTypeC.BISHOP] = pos.attacks_from_BISHOP(ksq); checkSq[PieceTypeC.ROOK] = pos.attacks_from_ROOK(ksq); #endif checkSq[PieceTypeC.QUEEN] = checkSq[PieceTypeC.BISHOP] | checkSq[PieceTypeC.ROOK]; checkSq[PieceTypeC.KING] = 0; }
/// 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(); }
/// move_to_san() takes a position and a move as input, where it is assumed /// that the move is a legal move for the position. The return value is /// a string containing the move in short algebraic notation. internal static string move_to_san(Position pos, Move m) { if (m == MoveC.MOVE_NONE) return "(none)"; if (m == MoveC.MOVE_NULL) return "(null)"; Debug.Assert(is_ok_M(m)); Bitboard attackers; bool ambiguousMove, ambiguousFile, ambiguousRank; Square sq, from = from_sq(m); Square to = to_sq(m); PieceType pt = type_of(pos.piece_moved(m)); StringBuilder san = new StringBuilder(); if (is_castle(m)) san.Append((to_sq(m) < from_sq(m) ? "O-O-O" : "O-O")); else { if (pt != PieceTypeC.PAWN) { san.Append(piece_type_to_char(pt).ToString()); // Disambiguation if we have more then one piece with destination 'to' // note that for pawns is not needed because starting file is explicit. attackers = pos.attackers_to(to) & pos.pieces_PTC(pt, pos.sideToMove); xor_bit(ref attackers, from); ambiguousMove = ambiguousFile = ambiguousRank = false; while (attackers != 0) { sq = pop_1st_bit(ref attackers); // Pinned pieces are not included in the possible sub-set if (!pos.pl_move_is_legal(make_move(sq, to), pos.pinned_pieces())) continue; if (file_of(sq) == file_of(from)) ambiguousFile = true; if (rank_of(sq) == rank_of(from)) ambiguousRank = true; ambiguousMove = true; } if (ambiguousMove) { if (!ambiguousFile) san.Append(file_to_char(file_of(from))); else if (!ambiguousRank) san.Append(rank_to_char(rank_of(from))); else san.Append(square_to_string(from)); } } if (pos.is_capture(m)) { if (pt == PieceTypeC.PAWN) san.Append(file_to_char(file_of(from))); san.Append('x'); } san.Append(square_to_string(to)); if (is_promotion(m)) { san.Append('='); san.Append(piece_type_to_char(promotion_type(m))); } } CheckInfo ci = CheckInfoBroker.GetObject(); ci.CreateCheckInfo(pos); if (pos.move_gives_check(m, ci)) { StateInfo st = new StateInfo(); pos.do_move(m, st); MList 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) { 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(); }
internal static void generate_legal(Position pos, MoveStack[] ms, ref int mpos) { /// generate<LEGAL> generates all the legal moves in the given position var pinned = pos.pinned_pieces(); Square ksq = pos.king_square(pos.sideToMove); if (pos.in_check()) { generate_evasion(pos, ms, ref mpos); } else { generate_non_evasion(pos, ms, ref mpos); } var last = mpos; var cur = 0; while (cur != last) { var curMove = ms[cur].move; //if (!pos.pl_move_is_legal(ms[cur].move, pinned)) if ((pinned != 0 || Utils.from_sq(curMove) == ksq || Utils.type_of_move(curMove) == MoveTypeC.ENPASSANT) && !pos.pl_move_is_legal(curMove, pinned)) { ms[cur].move = ms[--last].move; } else { cur++; } } mpos = last; }
/// 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(); }
internal static void generate_legal(Position pos, MoveStack[] ms, ref int mpos) { /// generate<MV_LEGAL> generates all the legal moves in the given position Bitboard pinned = pos.pinned_pieces(); if (pos.in_check()) { generate_evasion(pos, ms, ref mpos); } else { generate_non_evasion(pos, ms, ref mpos); } int last = mpos; int cur = 0; while (cur != last) { if (!pos.pl_move_is_legal(ms[cur].move, pinned)) { ms[cur].move = ms[--last].move; } else { cur++; } } mpos = last; }