/// generate<QUIET_CHECKS> generates all pseudo-legal non-captures and knight /// underpromotions that give check. Returns a pointer to the end of the move list. public static int generate_quiet_checks(Position pos, ExtMove[] mlist, int mPos) { Debug.Assert(0 == pos.checkers()); Color us = pos.side_to_move(); CheckInfo ci = new CheckInfo(pos); Bitboard dc = ci.dcCandidates; while (dc != 0) { Square from = BitBoard.pop_lsb(ref dc); PieceType pt = Types.type_of_piece(pos.piece_on(from)); if (pt == PieceTypeS.PAWN) { continue; // Will be generated togheter with direct checks } Bitboard b = pos.attacks_from_piece_square((Piece)pt, from) & ~pos.pieces(); if (pt == PieceTypeS.KING) { b &= ~BitBoard.PseudoAttacks[PieceTypeS.QUEEN][ci.ksq]; } while (b != 0) { mlist[mPos++].move = Types.make_move(from, BitBoard.pop_lsb(ref b)); } } return(us == ColorS.WHITE ? generate_all(pos, mlist, mPos, ~pos.pieces(), ColorS.WHITE, GenTypeS.QUIET_CHECKS, ci) : generate_all(pos, mlist, mPos, ~pos.pieces(), ColorS.BLACK, GenTypeS.QUIET_CHECKS, ci)); }
// polyglot_key() returns the PolyGlot hash key of the given position public static Key polyglot_key(Position pos) { Key key = 0; Bitboard b = pos.pieces(); while (b != 0) { Square s = BitBoard.pop_lsb(ref b); Piece pc = pos.piece_on(s); // PolyGlot pieces are: BP = 0, WP = 1, BN = 2, ... BK = 10, WK = 11 int pieceOfs = 2 * (Types.type_of_piece(pc) - 1) + ((Types.color_of(pc) == ColorS.WHITE) ? 1 : 0); key ^= PG[psq + (64 * pieceOfs + s)]; } b = (ulong)pos.can_castle_castleright(CastlingRightS.ANY_CASTLING); while (b != 0) { key ^= PG[castle + BitBoard.pop_lsb(ref b)]; } if (pos.ep_square() != SquareS.SQ_NONE) { key ^= PG[enpassant + Types.file_of(pos.ep_square())]; } if (pos.side_to_move() == ColorS.WHITE) { key ^= PG[turn + 0]; } return(key); }
public void score_evasions() { // Try good captures ordered by MVV/LVA, then non-captures if destination square // is not under attack, ordered by history value, then bad-captures and quiet // moves with a negative SEE. This last group is ordered by the SEE value. Move m; int see; for (int it = 0; it != end; ++it) { m = moves[it].move; if ((see = pos.see_sign(m)) < ValueS.VALUE_ZERO) { moves[it].value = see - HistoryStats.Max; // At the bottom } else if (pos.capture(m)) { moves[it].value = Position.PieceValue[PhaseS.MG][pos.piece_on(Types.to_sq(m))] - Types.type_of_piece(pos.moved_piece(m)) + HistoryStats.Max; } else { moves[it].value = history[pos.moved_piece(m)][Types.to_sq(m)]; } } }
/// score() assign a numerical value to each move in a move list. The moves with /// highest values will be picked first. public void score_captures() { // Winning and equal captures in the main search are ordered by MVV/LVA. // Suprisingly, this appears to perform slightly better than SEE based // move ordering. The reason is probably that in a position with a winning // capture, capturing a more valuable (but sufficiently defended) piece // first usually doesn't hurt. The opponent will have to recapture, and // the hanging piece will still be hanging (except in the unusual cases // where it is possible to recapture with the hanging piece). Exchanging // big pieces before capturing a hanging piece probably helps to reduce // the subtree size. // In main search we want to push captures with negative SEE values to the // badCaptures[] array, but instead of doing it now we delay until the move // has been picked up in pick_move_from_list(). This way we save some SEE // calls in case we get a cutoff. Move m; for (int it = 0; it != end; ++it) { m = moves[it].move; moves[it].value = Position.PieceValue[PhaseS.MG][pos.piece_on(Types.to_sq(m))] - Types.type_of_piece(pos.moved_piece(m)); if (Types.type_of_move(m) == MoveTypeS.ENPASSANT) { moves[it].value += Position.PieceValue[PhaseS.MG][PieceTypeS.PAWN]; } else if (Types.type_of_move(m) == MoveTypeS.PROMOTION) { moves[it].value += Position.PieceValue[PhaseS.MG][Types.promotion_type(m)] - Position.PieceValue[PhaseS.MG][PieceTypeS.PAWN]; } } }
public static Bitboard attacks_bb_PSBB(Piece pc, Square s, Bitboard occ) { switch (Types.type_of_piece(pc)) { case PieceTypeS.BISHOP: return(attacks_bb_SBBPT(s, occ, PieceTypeS.BISHOP)); case PieceTypeS.ROOK: return(attacks_bb_SBBPT(s, occ, PieceTypeS.ROOK)); case PieceTypeS.QUEEN: return(attacks_bb_SBBPT(s, occ, PieceTypeS.BISHOP) | attacks_bb_SBBPT(s, occ, PieceTypeS.ROOK)); default: return(StepAttacksBB[pc][s]); } }
// evaluate_threats() assigns bonuses according to the type of attacking piece // and the type of attacked one. public static Score evaluate_threats(Position pos, EvalInfo ei, Color Us, bool Trace) { Color Them = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE); Bitboard b, weakEnemies; Score score = ScoreS.SCORE_ZERO; // Enemies not defended by a pawn and under our attack weakEnemies = pos.pieces_color(Them) & ~ei.attackedBy[Them][PieceTypeS.PAWN] & ei.attackedBy[Us][PieceTypeS.ALL_PIECES]; // Add a bonus according if the attacking pieces are minor or major if (weakEnemies != 0) { b = weakEnemies & (ei.attackedBy[Us][PieceTypeS.PAWN] | ei.attackedBy[Us][PieceTypeS.KNIGHT] | ei.attackedBy[Us][PieceTypeS.BISHOP]); if (b != 0) { score += Threat[0][Types.type_of_piece(pos.piece_on(BitBoard.lsb(b)))]; } b = weakEnemies & (ei.attackedBy[Us][PieceTypeS.ROOK] | ei.attackedBy[Us][PieceTypeS.QUEEN]); if (b != 0) { score += Threat[1][Types.type_of_piece(pos.piece_on(BitBoard.lsb(b)))]; } b = weakEnemies & ~ei.attackedBy[Them][PieceTypeS.ALL_PIECES]; if (b != 0) { score += BitBoard.more_than_one(b) ? Hanging[Us != pos.side_to_move()?1:0] * Bitcount.popcount_Max15(b) : Hanging[Us == pos.side_to_move()?1:0]; } } if (Trace) { Tracing.terms[Us][TermsS.THREAT] = score; } return(score); }
/// move_to_san() takes a position and a legal Move as input and returns its /// short algebraic notation representation. public static string move_to_san(Position pos, Move m) { if (m == MoveS.MOVE_NONE) { return("(none)"); } if (m == MoveS.MOVE_NULL) { return("(null)"); } Debug.Assert((new MoveList(pos, GenTypeS.LEGAL).contains(m))); Bitboard others, b; string san = ""; Color us = pos.side_to_move(); Square from = Types.from_sq(m); Square to = Types.to_sq(m); Piece pc = pos.piece_on(from); PieceType pt = Types.type_of_piece(pc); if (Types.type_of_move(m) == MoveTypeS.CASTLING) { san = to > from ? "O-O" : "O-O-O"; } else { if (pt != PieceTypeS.PAWN) { san = "" + PieceToChar[ColorS.WHITE][pt]; // Upper case // A disambiguation occurs if we have more then one piece of type 'pt' // that can reach 'to' with a legal move. others = b = (pos.attacks_from_piece_square(pc, to) & pos.pieces_color_piecetype(us, pt)) ^ BitBoard.SquareBB[from]; while (b != 0) { Square s = BitBoard.pop_lsb(ref b); if (!pos.legal(Types.make_move(s, to), pos.pinned_pieces(us))) { others ^= BitBoard.SquareBB[s]; } } if (0 == others) { /* Disambiguation is not needed */ } else if (0 == (others & BitBoard.file_bb_square(from))) { san += Types.file_to_char(Types.file_of(from)); } else if (0 == (others & BitBoard.rank_bb_square(from))) { san += Types.rank_to_char(Types.rank_of(from)); } else { san += Types.square_to_string(from); } } else if (pos.capture(m)) { san = "" + Types.file_to_char(Types.file_of(from)); } if (pos.capture(m)) { san += 'x'; } san += Types.square_to_string(to); if (Types.type_of_move(m) == MoveTypeS.PROMOTION) { san += "=" + PieceToChar[ColorS.WHITE][Types.promotion_type(m)]; } } if (pos.gives_check(m, new CheckInfo(pos))) { StateInfo st = new StateInfo(); pos.do_move(m, st); san += (new MoveList(pos, GenTypeS.LEGAL)).size() > 0 ? "+" : "#"; pos.undo_move(m); } return(san); }