uint8_t PopCnt16[1 << 16];
uint8_t SquareDistance[SQUARE_NB][SQUARE_NB];
- Bitboard BoardSizeBB[FILE_NB][RANK_NB];
- Bitboard SquareBB[SQUARE_NB];
- Bitboard ForwardRanksBB[COLOR_NB][RANK_NB];
Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
Bitboard LineBB[SQUARE_NB][SQUARE_NB];
-Bitboard DistanceRingBB[SQUARE_NB][8];
-Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
-Bitboard PawnAttacks[COLOR_NB][SQUARE_NB];
+Bitboard DistanceRingBB[SQUARE_NB][FILE_NB];
+Bitboard PseudoAttacks[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
+Bitboard PseudoMoves[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
+Bitboard LeaperAttacks[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
+Bitboard LeaperMoves[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
+ Bitboard SquareBB[SQUARE_NB];
++Bitboard BoardSizeBB[FILE_NB][RANK_NB];
Bitboard KingFlank[FILE_NB] = {
QueenSide ^ FileDBB, QueenSide, QueenSide,
extern uint8_t PopCnt16[1 << 16];
extern uint8_t SquareDistance[SQUARE_NB][SQUARE_NB];
- extern Bitboard BoardSizeBB[FILE_NB][RANK_NB];
- extern Bitboard SquareBB[SQUARE_NB];
extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
extern Bitboard LineBB[SQUARE_NB][SQUARE_NB];
-extern Bitboard DistanceRingBB[SQUARE_NB][8];
-extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
-extern Bitboard PawnAttacks[COLOR_NB][SQUARE_NB];
+extern Bitboard DistanceRingBB[SQUARE_NB][FILE_NB];
+extern Bitboard PseudoAttacks[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
+extern Bitboard PseudoMoves[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
+extern Bitboard LeaperAttacks[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
+extern Bitboard LeaperMoves[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
extern Bitboard KingFlank[FILE_NB];
+ extern Bitboard SquareBB[SQUARE_NB];
++extern Bitboard BoardSizeBB[FILE_NB][RANK_NB];
+#ifdef LARGEBOARDS
+int popcount(Bitboard b); // required for 128 bit pext
+#endif
/// Magic holds all magic bitboards relevant data for a single square
struct Magic {
extern Magic RookMagics[SQUARE_NB];
extern Magic BishopMagics[SQUARE_NB];
-
- /// Overloads of bitwise operators between a Bitboard and a Square for testing
- /// whether a given bit is set in a bitboard, and for setting and clearing bits.
-
inline Bitboard square_bb(Square s) {
- assert(s >= SQ_A1 && s <= SQ_H8);
+ assert(s >= SQ_A1 && s <= SQ_MAX);
return SquareBB[s];
}
-
+
+ /// Overloads of bitwise operators between a Bitboard and a Square for testing
+ /// whether a given bit is set in a bitboard, and for setting and clearing bits.
+
inline Bitboard operator&( Bitboard b, Square s) { return b & square_bb(s); }
inline Bitboard operator|( Bitboard b, Square s) { return b | square_bb(s); }
inline Bitboard operator^( Bitboard b, Square s) { return b ^ square_bb(s); }
constexpr Color Them = (Us == WHITE ? BLACK : WHITE);
constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH);
constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH);
- constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB: Rank7BB | Rank6BB);
+ Bitboard LowRanks = rank_bb(relative_rank(Us, RANK_2, pos.max_rank())) | rank_bb(relative_rank(Us, RANK_3, pos.max_rank()));
- const Square ksq = pos.square<KING>(Us);
+ const Square ksq = pos.count<KING>(Us) ? pos.square<KING>(Us) : SQ_NONE;
+ Bitboard dblAttackByPawn = pawn_double_attacks_bb<Us>(pos.pieces(Us, PAWN));
+
// Find our pawns that are blocked or on the first two ranks
Bitboard b = pos.pieces(Us, PAWN) & (shift<Down>(pos.pieces()) | LowRanks);
// Squares occupied by those pawns, by our king or queen or controlled by
// enemy pawns are excluded from the mobility area.
- mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pe->pawn_attacks(Them));
+ if (pos.must_capture())
+ mobilityArea[Us] = AllSquares;
+ else
+ mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pe->pawn_attacks(Them) | shift<Down>(pos.pieces(Them, SHOGI_PAWN)));
// Initialize attackedBy[] for king and pawns
- attackedBy[Us][KING] = pos.attacks_from<KING>(ksq);
+ attackedBy[Us][KING] = pos.count<KING>(Us) ? pos.attacks_from<KING>(Us, ksq) : 0;
attackedBy[Us][PAWN] = pe->pawn_attacks(Us);
- attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN];
- attackedBy2[Us] = (attackedBy[Us][KING] & attackedBy[Us][PAWN])
- | dblAttackByPawn;
+ attackedBy[Us][SHOGI_PAWN] = shift<Up>(pos.pieces(Us, SHOGI_PAWN));
+ attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN] | attackedBy[Us][SHOGI_PAWN];
+ attackedBy2[Us] = (attackedBy[Us][KING] & attackedBy[Us][PAWN])
+ | (attackedBy[Us][KING] & attackedBy[Us][SHOGI_PAWN])
- | (attackedBy[Us][PAWN] & attackedBy[Us][SHOGI_PAWN]);
++ | (attackedBy[Us][PAWN] & attackedBy[Us][SHOGI_PAWN])
++ | dblAttackByPawn;
// Init our king safety tables
kingRing[Us] = attackedBy[Us][KING];
kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
// Remove from kingRing[] the squares defended by two pawns
- kingRing[Us] &= ~pawn_double_attacks_bb<Us>(pos.pieces(Us, PAWN));
+ kingRing[Us] &= ~dblAttackByPawn;
+
+ kingRing[Us] &= pos.board_bb();
}
Value npm = clamp(npm_w + npm_b, EndgameLimit, MidgameLimit);
// Map total non-pawn material into [PHASE_ENDGAME, PHASE_MIDGAME]
- e->gamePhase = Phase(((npm - EndgameLimit) * PHASE_MIDGAME) / (MidgameLimit - EndgameLimit));
-
+ if (pos.captures_to_hand())
+ {
+ npm = VALUE_ZERO;
+ for (PieceType pt : pos.piece_types())
+ npm += (pos.count_in_hand(WHITE, pt) + pos.count_in_hand(BLACK, pt)) * PieceValue[MG][make_piece(WHITE, pt)];
+ e->gamePhase = Phase(PHASE_MIDGAME * (MidgameLimit - std::min(npm, MidgameLimit)) / MidgameLimit);
+ }
+ else
+ e->gamePhase = Phase(((npm - EndgameLimit) * PHASE_MIDGAME) / (MidgameLimit - EndgameLimit));
+
+#ifdef LARGEBOARDS
+ // Disable endgame evaluation until it works independent of board size
+ if (false)
+#else
+ if (pos.endgame_eval())
+#endif
+ {
- // Let's look if we have a specialized evaluation function for this particular
- // material configuration. Firstly we look for a fixed configuration one, then
- // for a generic one if the previous search failed.
- if ((e->evaluationFunction = pos.this_thread()->endgames.probe<Value>(key)) != nullptr)
+ // Let's look if we have a specialized evaluation function for this particular
+ // material configuration. Firstly we look for a fixed configuration one, then
+ // for a generic one if the previous search failed.
+ if ((e->evaluationFunction = pos.this_thread()->endgames.probe<Value>(key)) != nullptr)
+ return e;
+
+ for (Color c = WHITE; c <= BLACK; ++c)
++ if (is_KFsPsK(pos, c))
++ {
++ e->evaluationFunction = &EvaluateKFsPsK[c];
+ return e;
++ }
+
- for (Color c = WHITE; c <= BLACK; ++c)
- if (is_KFsPsK(pos, c))
- {
- e->evaluationFunction = &EvaluateKFsPsK[c];
- return e;
- }
-
- for (Color c = WHITE; c <= BLACK; ++c)
- if (is_KXK(pos, c))
- {
- e->evaluationFunction = &EvaluateKXK[c];
- return e;
- }
-
- // OK, we didn't find any special evaluation function for the current material
- // configuration. Is there a suitable specialized scaling function?
- const EndgameBase<ScaleFactor>* sf;
-
- if ((sf = pos.this_thread()->endgames.probe<ScaleFactor>(key)) != nullptr)
++ for (Color c = WHITE; c <= BLACK; ++c)
+ if (is_KXK(pos, c))
{
- e->scalingFunction[sf->strongSide] = sf; // Only strong color assigned
+ e->evaluationFunction = &EvaluateKXK[c];
return e;
}
- // We didn't find any specialized scaling function, so fall back on generic
- // ones that refer to more than one material distribution. Note that in this
- // case we don't return after setting the function.
- for (Color c = WHITE; c <= BLACK; ++c)
+ // OK, we didn't find any special evaluation function for the current material
+ // configuration. Is there a suitable specialized scaling function?
+ const auto* sf = pos.this_thread()->endgames.probe<ScaleFactor>(key);
+
+ if (sf)
+ {
+ e->scalingFunction[sf->strongSide] = sf; // Only strong color assigned
+ return e;
+ }
+
+ // We didn't find any specialized scaling function, so fall back on generic
+ // ones that refer to more than one material distribution. Note that in this
+ // case we don't return after setting the function.
+ for (Color c = WHITE; c <= BLACK; ++c)
+ {
+ if (is_KBPsK(pos, c))
+ e->scalingFunction[c] = &ScaleKBPsK[c];
+
+ else if (is_KQKRPs(pos, c))
+ e->scalingFunction[c] = &ScaleKQKRPs[c];
+ }
+
+ if (npm_w + npm_b == VALUE_ZERO && pos.pieces(PAWN)) // Only pawns on the board
+ {
+ if (!pos.count<PAWN>(BLACK))
{
- if (is_KBPsK(pos, c))
- e->scalingFunction[c] = &ScaleKBPsK[c];
+ assert(pos.count<PAWN>(WHITE) >= 2);
- else if (is_KQKRPs(pos, c))
- e->scalingFunction[c] = &ScaleKQKRPs[c];
+ e->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
}
+ else if (!pos.count<PAWN>(WHITE))
+ {
+ assert(pos.count<PAWN>(BLACK) >= 2);
- if (npm_w + npm_b == VALUE_ZERO && pos.pieces(PAWN)) // Only pawns on the board
+ e->scalingFunction[BLACK] = &ScaleKPsK[BLACK];
+ }
+ else if (pos.count<PAWN>(WHITE) == 1 && pos.count<PAWN>(BLACK) == 1)
{
- if (!pos.count<PAWN>(BLACK))
- {
- assert(pos.count<PAWN>(WHITE) >= 2);
-
- e->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
- }
- else if (!pos.count<PAWN>(WHITE))
- {
- assert(pos.count<PAWN>(BLACK) >= 2);
-
- e->scalingFunction[BLACK] = &ScaleKPsK[BLACK];
- }
- else if (pos.count<PAWN>(WHITE) == 1 && pos.count<PAWN>(BLACK) == 1)
- {
- // This is a special case because we set scaling functions
- // for both colors instead of only one.
- e->scalingFunction[WHITE] = &ScaleKPKP[WHITE];
- e->scalingFunction[BLACK] = &ScaleKPKP[BLACK];
- }
+ // This is a special case because we set scaling functions
+ // for both colors instead of only one.
+ e->scalingFunction[WHITE] = &ScaleKPKP[WHITE];
+ e->scalingFunction[BLACK] = &ScaleKPKP[BLACK];
}
+ }
- // Zero or just one pawn makes it difficult to win, even with a small material
- // advantage. This catches some trivial draws like KK, KBK and KNK and gives a
- // drawish scale factor for cases such as KRKBP and KmmKm (except for KBBKN).
- if (!pos.count<PAWN>(WHITE) && npm_w - npm_b <= BishopValueMg)
- e->factor[WHITE] = uint8_t(npm_w < RookValueMg ? SCALE_FACTOR_DRAW :
- npm_b <= BishopValueMg ? 4 : 14);
+ // Zero or just one pawn makes it difficult to win, even with a small material
+ // advantage. This catches some trivial draws like KK, KBK and KNK and gives a
+ // drawish scale factor for cases such as KRKBP and KmmKm (except for KBBKN).
+ if (!pos.count<PAWN>(WHITE) && npm_w - npm_b <= BishopValueMg)
+ e->factor[WHITE] = uint8_t(npm_w < RookValueMg ? SCALE_FACTOR_DRAW :
+ npm_b <= BishopValueMg ? 4 : 14);
- if (!pos.count<PAWN>(BLACK) && npm_b - npm_w <= BishopValueMg)
- e->factor[BLACK] = uint8_t(npm_b < RookValueMg ? SCALE_FACTOR_DRAW :
- npm_w <= BishopValueMg ? 4 : 14);
+ if (!pos.count<PAWN>(BLACK) && npm_b - npm_w <= BishopValueMg)
+ e->factor[BLACK] = uint8_t(npm_b < RookValueMg ? SCALE_FACTOR_DRAW :
+ npm_w <= BishopValueMg ? 4 : 14);
+ }
// Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder
// for the bishop pair "extended piece", which allows us to be more flexible
// Score this pawn
if (support | phalanx)
- score += Connected[opposed][bool(phalanx)][popcount(support)][relative_rank(Us, s, pos.max_rank())];
-
+ {
- int r = relative_rank(Us, s);
++ int r = relative_rank(Us, s, pos.max_rank());
+ int v = phalanx ? Connected[r] + Connected[r + 1] : 2 * Connected[r];
+ v = 17 * popcount(support) + (v >> (opposed + 1));
+ score += make_score(v, v * (r - 2) / 4);
+ }
else if (!neighbours)
- score -= Isolated, e->weakUnopposed[Us] += !opposed;
+ score -= Isolated * (1 + 2 * pos.must_capture()), e->weakUnopposed[Us] += !opposed;
else if (backward)
score -= Backward, e->weakUnopposed[Us] += !opposed;
score -= Doubled;
}
+ const Square* pl_shogi = pos.squares<SHOGI_PAWN>(Us);
+
+ ourPawns = pos.pieces(Us, SHOGI_PAWN);
+ theirPawns = pos.pieces(Them, SHOGI_PAWN);
+
+ // Loop through all shogi pawns of the current color and score each one
+ while ((s = *pl_shogi++) != SQ_NONE)
+ {
+ assert(pos.piece_on(s) == make_piece(Us, SHOGI_PAWN));
+
+ File f = file_of(s);
+
+ e->semiopenFiles[Us] &= ~(1 << f);
+
- opposed = theirPawns & forward_file_bb(Us, s);
+ neighbours = ourPawns & adjacent_files_bb(f);
- phalanx = neighbours & rank_bb(s);
-
- if (phalanx)
- score += Connected[opposed][bool(phalanx)][0][relative_rank(Us, s, pos.max_rank())] / 2;
+
- else if (!neighbours)
++ if (!neighbours)
+ score -= Isolated / 2;
+ }
+
return score;
}
{
int bonus = -(ss-1)->statScore / 512;
- pureStaticEval = evaluate(pos);
- ss->staticEval = eval = pureStaticEval + bonus;
+ ss->staticEval = eval = evaluate(pos) + bonus;
}
else
- ss->staticEval = eval = pureStaticEval = -(ss-1)->staticEval + 2 * Eval::tempo_value(pos);
- ss->staticEval = eval = -(ss-1)->staticEval + 2 * Eval::Tempo;
++ ss->staticEval = eval = -(ss-1)->staticEval + 2 * Eval::tempo_value(pos);
- tte->save(posKey, VALUE_NONE, ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, pureStaticEval);
+ tte->save(posKey, VALUE_NONE, ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval);
}
// Step 7. Razoring (~2 Elo)
&& (ss-1)->currentMove != MOVE_NULL
&& (ss-1)->statScore < 23200
&& eval >= beta
- && pureStaticEval >= beta - 36 * depth / ONE_PLY + 225
+ && ss->staticEval >= beta - 36 * depth / ONE_PLY + 225
&& !excludedMove
&& pos.non_pawn_material(us)
+ && (pos.pieces(~us) ^ pos.pieces(~us, PAWN))
+ && (pos.pieces() ^ pos.pieces(BREAKTHROUGH_PIECE) ^ pos.pieces(CLOBBER_PIECE))
&& (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor))
{
assert(eval - beta >= 0);
}
// Step 11. Internal iterative deepening (~2 Elo)
- if ( depth >= (8 - 2 * pos.captures_to_hand()) * ONE_PLY
- && !ttMove)
- if (depth >= 8 * ONE_PLY && !ttMove)
++ if (depth >= (8 - 2 * pos.captures_to_hand()) * ONE_PLY && !ttMove)
{
- search<NT>(pos, ss, alpha, beta, depth - 7 * ONE_PLY, cutNode);
+ search<NT>(pos, ss, alpha, beta, depth - (7 - 2 * pos.captures_to_hand()) * ONE_PLY, cutNode);
tte = TT.probe(posKey, ttHit);
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;