// init_eval_info() initializes king bitboards for given color adding // pawn attacks. To be done at the beginning of the evaluation. public static void init_eval_info(Position pos, EvalInfo ei, Color Us) { Color Them = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE); Square Down = (Us == ColorS.WHITE ? SquareS.DELTA_S : SquareS.DELTA_N); ei.pinnedPieces[Us] = pos.pinned_pieces(Us); Bitboard b = ei.attackedBy[Them][PieceTypeS.KING] = pos.attacks_from_square_piecetype(pos.king_square(Them), PieceTypeS.KING); ei.attackedBy[Us][PieceTypeS.ALL_PIECES] = ei.attackedBy[Us][PieceTypeS.PAWN] = ei.pi.pawn_attacks(Us); // Init king safety tables only if we are going to use them if (pos.count(Us, PieceTypeS.QUEEN) != 0 && pos.non_pawn_material(Us) > ValueS.QueenValueMg + ValueS.PawnValueMg) { ei.kingRing[Them] = b | BitBoard.shift_bb(b, Down); b &= ei.attackedBy[Us][PieceTypeS.PAWN]; ei.kingAttackersCount[Us] = (b != 0) ? Bitcount.popcount_Max15(b) : 0; ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0; } else { ei.kingRing[Them] = 0; ei.kingAttackersCount[Us] = 0; } }
public static int generate_promotions(ExtMove[] mlist, int mPos, Bitboard pawnsOn7, Bitboard target, CheckInfo ci, GenType Type, Square Delta) { Bitboard b = BitBoard.shift_bb(pawnsOn7, Delta) & target; while (b != 0) { Square to = BitBoard.pop_lsb(ref b); if (Type == GenTypeS.CAPTURES || Type == GenTypeS.EVASIONS || Type == GenTypeS.NON_EVASIONS) { mlist[mPos++].move = Types.make(to - Delta, to, MoveTypeS.PROMOTION, PieceTypeS.QUEEN); } if (Type == GenTypeS.QUIETS || Type == GenTypeS.EVASIONS || Type == GenTypeS.NON_EVASIONS) { mlist[mPos++].move = Types.make(to - Delta, to, MoveTypeS.PROMOTION, PieceTypeS.ROOK); mlist[mPos++].move = Types.make(to - Delta, to, MoveTypeS.PROMOTION, PieceTypeS.BISHOP); mlist[mPos++].move = Types.make(to - Delta, to, MoveTypeS.PROMOTION, PieceTypeS.KNIGHT); } // Knight promotion is the only promotion that can give a direct check // that's not already included in the queen promotion. if (Type == GenTypeS.QUIET_CHECKS && (BitBoard.StepAttacksBB[PieceS.W_KNIGHT][to] & BitBoard.SquareBB[ci.ksq]) != 0) { mlist[mPos++].move = Types.make(to - Delta, to, MoveTypeS.PROMOTION, PieceTypeS.KNIGHT); } } return(mPos); }
public static Score evaluate(Position pos, Pawns.Entry e, Color Us) { Color Them = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE); Square Up = (Us == ColorS.WHITE ? SquareS.DELTA_N : SquareS.DELTA_S); Square Right = (Us == ColorS.WHITE ? SquareS.DELTA_NE : SquareS.DELTA_SW); Square Left = (Us == ColorS.WHITE ? SquareS.DELTA_NW : SquareS.DELTA_SE); Bitboard b, p, doubled; Square s; File f; Rank r; bool passed, isolated, opposed, connected, backward, candidate, unsupported; Score value = ScoreS.SCORE_ZERO; Square[] pl = pos.list(Us, PieceTypeS.PAWN); int plPos = 0; Bitboard ourPawns = pos.pieces_color_piecetype(Us, PieceTypeS.PAWN); Bitboard theirPawns = pos.pieces_color_piecetype(Them, PieceTypeS.PAWN); e.passedPawns[Us] = e.candidatePawns[Us] = 0; e.kingSquares[Us] = SquareS.SQ_NONE; e.semiopenFiles[Us] = 0xFF; e.pawnAttacks[Us] = BitBoard.shift_bb(ourPawns, Right) | BitBoard.shift_bb(ourPawns, Left); e.pawnsOnSquares[Us][ColorS.BLACK] = Bitcount.popcount_Max15(ourPawns & BitBoard.DarkSquares); e.pawnsOnSquares[Us][ColorS.WHITE] = pos.count(Us, PieceTypeS.PAWN) - e.pawnsOnSquares[Us][ColorS.BLACK]; // Loop through all pawns of the current color and score each pawn while ((s = pl[plPos++]) != SquareS.SQ_NONE) { Debug.Assert(pos.piece_on(s) == Types.make_piece(Us, PieceTypeS.PAWN)); f = Types.file_of(s); // This file cannot be semi-open e.semiopenFiles[Us] &= ~(1 << f); // Previous rank p = BitBoard.rank_bb_square(s - Types.pawn_push(Us)); // Our rank plus previous one b = BitBoard.rank_bb_square(s) | p; // Flag the pawn as passed, isolated, doubled, // unsupported or connected (but not the backward one). connected = (ourPawns & BitBoard.adjacent_files_bb(f) & b) != 0; unsupported = (0 == (ourPawns & BitBoard.adjacent_files_bb(f) & p)); isolated = (0 == (ourPawns & BitBoard.adjacent_files_bb(f))); doubled = ourPawns & BitBoard.forward_bb(Us, s); opposed = (theirPawns & BitBoard.forward_bb(Us, s)) != 0; passed = (0 == (theirPawns & BitBoard.passed_pawn_mask(Us, s))); // Test for backward pawn. // If the pawn is passed, isolated, or connected it cannot be // backward. If there are friendly pawns behind on adjacent files // or if it can capture an enemy pawn it cannot be backward either. if ((passed | isolated | connected) || (ourPawns & BitBoard.pawn_attack_span(Them, s)) != 0 || (pos.attacks_from_pawn(s, Us) & theirPawns) != 0) { backward = false; } else { // We now know that there are no friendly pawns beside or behind this // pawn on adjacent files. We now check whether the pawn is // backward by looking in the forward direction on the adjacent // files, and picking the closest pawn there. b = BitBoard.pawn_attack_span(Us, s) & (ourPawns | theirPawns); b = BitBoard.pawn_attack_span(Us, s) & BitBoard.rank_bb_square(BitBoard.backmost_sq(Us, b)); // If we have an enemy pawn in the same or next rank, the pawn is // backward because it cannot advance without being captured. backward = ((b | BitBoard.shift_bb(b, Up)) & theirPawns) != 0; } Debug.Assert(opposed | passed | (BitBoard.pawn_attack_span(Us, s) & theirPawns) != 0); // A not-passed pawn is a candidate to become passed, if it is free to // advance and if the number of friendly pawns beside or behind this // pawn on adjacent files is higher than or equal to the number of // enemy pawns in the forward direction on the adjacent files. candidate = !(opposed | passed | backward | isolated) && (b = BitBoard.pawn_attack_span(Them, s + Types.pawn_push(Us)) & ourPawns) != 0 && Bitcount.popcount_Max15(b) >= Bitcount.popcount_Max15(BitBoard.pawn_attack_span(Us, s) & theirPawns); // Passed pawns will be properly scored in evaluation because we need // full attack info to evaluate passed pawns. Only the frontmost passed // pawn on each file is considered a true passed pawn. if (passed && 0 == doubled) { e.passedPawns[Us] |= BitBoard.SquareBB[s]; } // Score this pawn if (isolated) { value -= Isolated[opposed ? 1 : 0][f]; } if (unsupported && !isolated) { value -= UnsupportedPawnPenalty; } if (doubled != 0) { value -= Types.divScore(Doubled[f], BitBoard.rank_distance(s, BitBoard.lsb(doubled))); } if (backward) { value -= Backward[opposed ? 1 : 0][f]; } if (connected) { value += Connected[f][Types.relative_rank_square(Us, s)]; } if (candidate) { value += CandidatePassed[Types.relative_rank_square(Us, s)]; if (0 == doubled) { e.candidatePawns[Us] |= BitBoard.SquareBB[s]; } } } // In endgame it's better to have pawns on both wings. So give a bonus according // to file distance between left and right outermost pawns. if (pos.count(Us, PieceTypeS.PAWN) > 1) { b = (Bitboard)(e.semiopenFiles[Us] ^ 0xFF); value += PawnsFileSpan * (BitBoard.msb(b) - BitBoard.lsb(b)); } return(value); }
public static int generate_pawn_moves(Position pos, ExtMove[] mlist, int mPos, Bitboard target, CheckInfo ci, Color Us, GenType Type) { // Compute our parametrized parameters at compile time, named according to // the point of view of white side. Color Them = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE); Bitboard TRank8BB = (Us == ColorS.WHITE ? BitBoard.Rank8BB : BitBoard.Rank1BB); Bitboard TRank7BB = (Us == ColorS.WHITE ? BitBoard.Rank7BB : BitBoard.Rank2BB); Bitboard TRank3BB = (Us == ColorS.WHITE ? BitBoard.Rank3BB : BitBoard.Rank6BB); Square Up = (Us == ColorS.WHITE ? SquareS.DELTA_N : SquareS.DELTA_S); Square Right = (Us == ColorS.WHITE ? SquareS.DELTA_NE : SquareS.DELTA_SW); Square Left = (Us == ColorS.WHITE ? SquareS.DELTA_NW : SquareS.DELTA_SE); Bitboard b1, b2, dc1, dc2, emptySquares = 0; Bitboard pawnsOn7 = pos.pieces_color_piecetype(Us, PieceTypeS.PAWN) & TRank7BB; Bitboard pawnsNotOn7 = pos.pieces_color_piecetype(Us, PieceTypeS.PAWN) & ~TRank7BB; Bitboard enemies = (Type == GenTypeS.EVASIONS ? pos.pieces_color(Them) & target : Type == GenTypeS.CAPTURES ? target : pos.pieces_color(Them)); // Single and double pawn pushes, no promotions if (Type != GenTypeS.CAPTURES) { emptySquares = (Type == GenTypeS.QUIETS || Type == GenTypeS.QUIET_CHECKS ? target : ~pos.pieces()); b1 = BitBoard.shift_bb(pawnsNotOn7, Up) & emptySquares; b2 = BitBoard.shift_bb(b1 & TRank3BB, Up) & emptySquares; if (Type == GenTypeS.EVASIONS) // Consider only blocking squares { b1 &= target; b2 &= target; } if (Type == GenTypeS.QUIET_CHECKS) { b1 &= pos.attacks_from_pawn(ci.ksq, Them); b2 &= pos.attacks_from_pawn(ci.ksq, Them); // Add pawn pushes which give discovered check. This is possible only // if the pawn is not on the same file as the enemy king, because we // don't generate captures. Note that a possible discovery check // promotion has been already generated among captures. if ((pawnsNotOn7 & ci.dcCandidates) != 0) { dc1 = BitBoard.shift_bb(pawnsNotOn7 & ci.dcCandidates, Up) & emptySquares & ~BitBoard.file_bb_square(ci.ksq); dc2 = BitBoard.shift_bb(dc1 & TRank3BB, Up) & emptySquares; b1 |= dc1; b2 |= dc2; } } while (b1 != 0) { Square to = BitBoard.pop_lsb(ref b1); mlist[mPos++].move = Types.make_move(to - Up, to); } while (b2 != 0) { Square to = BitBoard.pop_lsb(ref b2); mlist[mPos++].move = Types.make_move(to - Up - Up, to); } } // Promotions and underpromotions if (pawnsOn7 != 0 && (Type != GenTypeS.EVASIONS || (target & TRank8BB) != 0)) { if (Type == GenTypeS.CAPTURES) { emptySquares = ~pos.pieces(); } if (Type == GenTypeS.EVASIONS) { emptySquares &= target; } mPos = generate_promotions(mlist, mPos, pawnsOn7, enemies, ci, Type, Right); mPos = generate_promotions(mlist, mPos, pawnsOn7, enemies, ci, Type, Left); mPos = generate_promotions(mlist, mPos, pawnsOn7, emptySquares, ci, Type, Up); } // Standard and en-passant captures if (Type == GenTypeS.CAPTURES || Type == GenTypeS.EVASIONS || Type == GenTypeS.NON_EVASIONS) { b1 = BitBoard.shift_bb(pawnsNotOn7, Right) & enemies; b2 = BitBoard.shift_bb(pawnsNotOn7, Left) & enemies; while (b1 != 0) { Square to = BitBoard.pop_lsb(ref b1); mlist[mPos++].move = Types.make_move(to - Right, to); } while (b2 != 0) { Square to = BitBoard.pop_lsb(ref b2); mlist[mPos++].move = Types.make_move(to - Left, to); } if (pos.ep_square() != SquareS.SQ_NONE) { Debug.Assert(Types.rank_of(pos.ep_square()) == Types.relative_rank_rank(Us, RankS.RANK_6)); // An en passant capture can be an evasion only if the checking piece // is the double pushed pawn and so is in the target. Otherwise this // is a discovery check and we are forced to do otherwise. if (Type == GenTypeS.EVASIONS && (target & BitBoard.SquareBB[(pos.ep_square() - Up)]) == 0) { return(mPos); } b1 = pawnsNotOn7 & pos.attacks_from_pawn(pos.ep_square(), Them); Debug.Assert(b1 != 0); while (b1 != 0) { mlist[mPos++].move = Types.make(BitBoard.pop_lsb(ref b1), pos.ep_square(), MoveTypeS.ENPASSANT); } } } return(mPos); }