@echo "Advanced examples, for experienced users: "
@echo ""
@echo "make build ARCH=x86-64 COMP=clang"
- @echo "make profile-build ARCH=x86-64-modern COMP=gcc COMPCXX=g++-4.8"
+ @echo "make profile-build ARCH=x86-64-bmi2 COMP=gcc COMPCXX=g++-4.8"
@echo ""
+ @echo "Version for large boards (only GCC and mingw, 64-bit required): "
+ @echo ""
+ @echo "make build ARCH=x86-64 COMP=gcc largeboards=yes"
+ @echo ""
.PHONY: help build profile-build strip install clean objclean profileclean help \
template<Color Us> Score threats() const;
template<Color Us> Score passed() const;
template<Color Us> Score space() const;
+ template<Color Us> Score variant() const;
ScaleFactor scale_factor(Value eg) const;
- Score initiative(Value eg) const;
+ Score initiative(Score score) const;
const Position& pos;
Material::Entry* me;
if (Pt == ROOK)
{
// Bonus for aligning rook with enemy pawns on the same rank/file
- if (relative_rank(Us, s) >= RANK_5)
- score += RookOnPawn * popcount(pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s]);
+ if (relative_rank(Us, s, pos.max_rank()) >= RANK_5)
+ score += RookOnPawn * popcount(pos.pieces(Them, PAWN) & PseudoAttacks[Us][ROOK][s]);
+ // Bonus for rook on the same file as a queen
+ if (file_bb(s) & pos.pieces(QUEEN))
+ score += RookOnQueenFile;
+
// Bonus for rook on an open or semi-open file
if (pos.is_on_semiopen_file(Us, s))
score += RookOnFile[bool(pos.is_on_semiopen_file(Them, s))];
b1 = attacks_bb<ROOK >(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
b2 = attacks_bb<BISHOP>(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
- // Enemy rooks checks
- rookChecks = b1 & safe & attackedBy[Them][ROOK];
-
- if (rookChecks)
- kingDanger += RookSafeCheck;
- else
- unsafeChecks |= b1 & attackedBy[Them][ROOK];
-
- // Enemy queen safe checks: we count them only if they are from squares from
- // which we can't give a rook check, because rook checks are more valuable.
- queenChecks = (b1 | b2)
- & attackedBy[Them][QUEEN]
- & safe
- & ~attackedBy[Us][QUEEN]
- & ~rookChecks;
-
- if (queenChecks)
- kingDanger += QueenSafeCheck;
-
- // Enemy bishops checks: we count them only if they are from squares from
- // which we can't give a queen check, because queen checks are more valuable.
- bishopChecks = b2
- & attackedBy[Them][BISHOP]
- & safe
- & ~queenChecks;
-
- if (bishopChecks)
- kingDanger += BishopSafeCheck;
- else
- unsafeChecks |= b2 & attackedBy[Them][BISHOP];
+ std::function <Bitboard (Color, PieceType)> get_attacks = [this](Color c, PieceType pt) {
+ return attackedBy[c][pt] | (pos.captures_to_hand() && pos.count_in_hand(c, pt) ? ~pos.pieces() : Bitboard(0));
+ };
+ for (PieceType pt : pos.piece_types())
+ {
+ switch (pt)
+ {
+ case QUEEN:
+ // Enemy queen safe checks: we count them only if they are from squares from
+ // which we can't give a rook check, because rook checks are more valuable.
+ queenChecks = (b1 | b2)
+ & get_attacks(Them, QUEEN)
+ & safe
+ & ~attackedBy[Us][QUEEN]
+ & ~(b1 & attackedBy[Them][ROOK]);
+
+ if (queenChecks)
+ kingDanger += QueenSafeCheck;
+ break;
+ case ROOK:
+ case BISHOP:
+ case KNIGHT:
+ knightChecks = attacks_bb(Us, pt, ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)) & get_attacks(Them, pt) & pos.board_bb();
+ if (knightChecks & safe)
+ kingDanger += pt == ROOK ? RookSafeCheck
+ : pt == BISHOP ? BishopSafeCheck
+ : KnightSafeCheck;
+ else
+ unsafeChecks |= knightChecks;
+ break;
+ case PAWN:
+ if (pos.captures_to_hand() && pos.count_in_hand(Them, pt))
+ {
+ pawnChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & ~pos.pieces() & pos.board_bb();
+ if (pawnChecks & safe)
+ kingDanger += OtherSafeCheck;
+ else
+ unsafeChecks |= pawnChecks;
+ }
+ break;
+ case SHOGI_PAWN:
+ case KING:
+ break;
+ default:
+ otherChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & get_attacks(Them, pt) & pos.board_bb();
+ if (otherChecks & safe)
+ kingDanger += OtherSafeCheck;
+ else
+ unsafeChecks |= otherChecks;
+ }
+ }
- // Enemy knights checks
- knightChecks = pos.attacks_from<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
+ if (pos.check_counting())
+ kingDanger *= 2;
- // Unsafe or occupied checking squares will also be considered, as long as
- // the square is in the attacker's mobility area.
- unsafeChecks &= mobilityArea[Them];
-
- if (knightChecks & safe)
- kingDanger += KnightSafeCheck;
- else
- unsafeChecks |= knightChecks;
+ Square s = file_of(ksq) == FILE_A ? ksq + EAST : file_of(ksq) == pos.max_file() ? ksq + WEST : ksq;
+ Bitboard kingFlank = pos.max_file() == FILE_H ? KingFlank[file_of(ksq)] : file_bb(s) | adjacent_files_bb(s);
// Find the squares that opponent attacks in our king flank, and the squares
// which are attacked twice in that flank.
int kingFlankAttacks = popcount(b1) + popcount(b2);
kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them]
- + 69 * kingAttacksCount[Them]
- + 185 * popcount(kingRing[Us] & weak)
+ + 69 * kingAttacksCount[Them] * (2 + 8 * pos.check_counting() + pos.captures_to_hand()) / 2
+ + 185 * popcount(kingRing[Us] & weak) * (1 + pos.captures_to_hand() + pos.check_counting())
- 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING])
- 35 * bool(attackedBy[Us][BISHOP] & attackedBy[Us][KING])
- - 10 * bool(attackedBy2[Us] & attackedBy[Us][KING]) * pos.captures_to_hand()
- + 150 * popcount(pos.blockers_for_king(Us) | unsafeChecks)
+ + 148 * popcount(unsafeChecks)
+ + 98 * popcount(pos.blockers_for_king(Us))
- - 873 * !pos.count<QUEEN>(Them)
+ - 873 * !(pos.major_pieces(Them) || pos.captures_to_hand()) / (1 + pos.check_counting())
- 6 * mg_value(score) / 8
+ mg_value(mobility[Them] - mobility[Us])
+ 5 * kingFlankAttacks * kingFlankAttacks / 16
b &= ~attackedBy[Them][PAWN] & safe;
// Bonus for safe pawn threats on the next move
- b = pawn_attacks_bb<Us>(b) & nonPawnEnemies;
+ b = (pawn_attacks_bb<Us>(b) | shift<Up>(shift<Up>(pos.pieces(Us, SHOGI_PAWN)))) & nonPawnEnemies;
score += ThreatByPawnPush * popcount(b);
- // Our safe or protected pawns
- b = pos.pieces(Us, PAWN) & safe;
-
- b = (pawn_attacks_bb<Us>(b) | shift<Up>(pos.pieces(Us, SHOGI_PAWN))) & nonPawnEnemies;
- score += ThreatBySafePawn * popcount(b);
-
// Bonus for threats on the next moves against enemy queen
if (pos.count<QUEEN>(Them) == 1)
{
// known attacking/defending status of the players.
template<Tracing T>
- Score Evaluation<T>::initiative(Value eg) const {
+ Score Evaluation<T>::initiative(Score score) const {
+
+ Value mg = mg_value(score);
+ Value eg = eg_value(score);
- int outflanking = distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
- - distance<Rank>(pos.square<KING>(WHITE), pos.square<KING>(BLACK));
+ // No initiative bonus for extinction variants
+ if (pos.extinction_value() != VALUE_NONE || pos.captures_to_hand() || pos.connect_n())
+ return SCORE_ZERO;
+
+ int outflanking = !pos.count<KING>(WHITE) || !pos.count<KING>(BLACK) ? 0
+ : distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
+ - distance<Rank>(pos.square<KING>(WHITE), pos.square<KING>(BLACK));
bool pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide)
&& (pos.pieces(PAWN) & KingSide);
score += king< WHITE>() - king< BLACK>()
+ threats<WHITE>() - threats<BLACK>()
+ passed< WHITE>() - passed< BLACK>()
- + space< WHITE>() - space< BLACK>();
+ + space< WHITE>() - space< BLACK>()
+ + variant<WHITE>() - variant<BLACK>();
- score += initiative(eg_value(score));
+ score += initiative(score);
// Interpolate between a middlegame and a (scaled by 'sf') endgame score
ScaleFactor sf = scale_factor(eg_value(score));
constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
- moveList = generate_moves<KNIGHT, Checks>(pos, moveList, Us, target);
- moveList = generate_moves<BISHOP, Checks>(pos, moveList, Us, target);
- moveList = generate_moves< ROOK, Checks>(pos, moveList, Us, target);
- moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target);
-
- if (Type != QUIET_CHECKS && Type != EVASIONS)
+ for (PieceType pt = PieceType(PAWN + 1); pt < KING; ++pt)
+ moveList = generate_moves<Checks>(pos, moveList, Us, pt, target);
+ // generate drops
+ if (pos.piece_drops() && Type != CAPTURES && pos.count_in_hand(Us, ALL_PIECES))
+ for (PieceType pt = PAWN; pt <= KING; ++pt)
+ moveList = generate_drops<Us, Checks>(pos, moveList, pt, target & ~pos.pieces(~Us));
+
+ if (Type != QUIET_CHECKS && Type != EVASIONS && pos.count<KING>(Us))
{
Square ksq = pos.square<KING>(Us);
- Bitboard b = pos.attacks_from<KING>(ksq) & target;
+ Bitboard b = pos.attacks_from<KING>(Us, ksq) & target;
while (b)
- *moveList++ = make_move(ksq, pop_lsb(&b));
+ moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, ksq, pop_lsb(&b));
- if (Type != CAPTURES && pos.can_castle(CastlingRight(OO | OOO)))
+ if (Type != CAPTURES && pos.can_castle(CastlingRights(OO | OOO)))
{
if (!pos.castling_impeded(OO) && pos.can_castle(OO))
- *moveList++ = make<CASTLING>(ksq, pos.castling_rook_square(OO));
+ moveList = make_move_and_gating<CASTLING>(pos, moveList, Us, ksq, pos.castling_rook_square(OO));
if (!pos.castling_impeded(OOO) && pos.can_castle(OOO))
- *moveList++ = make<CASTLING>(ksq, pos.castling_rook_square(OOO));
+ moveList = make_move_and_gating<CASTLING>(pos, moveList, Us, ksq, pos.castling_rook_square(OOO));
}
}
+ // Castling with non-king piece
- if (!pos.count<KING>(Us) && Type != CAPTURES && pos.can_castle(CastlingRight(OO | OOO)))
++ if (!pos.count<KING>(Us) && Type != CAPTURES && pos.can_castle(CastlingRights(OO | OOO)))
+ {
+ Square from = make_square(FILE_E, relative_rank(Us, pos.castling_rank(), pos.max_rank()));
+ if (!pos.castling_impeded(OO) && pos.can_castle(OO))
+ moveList = make_move_and_gating<CASTLING>(pos, moveList, Us, from, pos.castling_rook_square(OO));
+
+ if (!pos.castling_impeded(OOO) && pos.can_castle(OOO))
+ moveList = make_move_and_gating<CASTLING>(pos, moveList, Us, from, pos.castling_rook_square(OOO));
+ }
+
return moveList;
}
}
else if (!neighbours)
- score -= Isolated * (1 + 2 * pos.must_capture()) + WeakUnopposed * int(!opposed);
- score -= Isolated + WeakUnopposed * !opposed;
++ score -= Isolated * (1 + 2 * pos.must_capture()) + WeakUnopposed * !opposed;
else if (backward)
- score -= Backward + WeakUnopposed * int(!opposed);
+ score -= Backward + WeakUnopposed * !opposed;
- if (doubled && !support)
- score -= Doubled;
+ if (!support)
+ score -= Doubled * doubled
+ + WeakLever * more_than_one(lever);
}
- // Penalize the unsupported and non passed pawns attacked twice by the enemy
- b = ourPawns
- & doubleAttackThem
- & ~(e->pawnAttacks[Us] | e->passedPawns[Us]);
- score -= WeakLever * popcount(b);
-
+ // Double pawn evaluation if there are no non-pawn pieces
+ if (pos.count<ALL_PIECES>(Us) == pos.count<PAWN>(Us))
+ score = score * 2;
+
+ 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));
+
+ neighbours = ourPawns & adjacent_files_bb(s);
+
+ if (!neighbours)
+ score -= Isolated / 2;
+ }
+
return score;
}
for (File f = File(center - 1); f <= File(center + 1); ++f)
{
b = ourPawns & file_bb(f);
- Rank ourRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : RANK_1;
- int ourRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0;
++ int ourRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : 0;
b = theirPawns & file_bb(f);
- Rank theirRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : RANK_1;
- int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0;
++ int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : 0;
- int d = std::min(f, ~f);
- bonus += make_score(ShelterStrength[d][ourRank], 0);
+ int d = std::min(std::min(f, File(pos.max_file() - f)), FILE_D);
+ bonus += make_score(ShelterStrength[d][ourRank], 0) * (1 + (pos.captures_to_hand() && ourRank <= RANK_2));
if (ourRank && (ourRank == theirRank - 1))
- bonus -= make_score(82 * (theirRank == RANK_3), 82 * (theirRank == RANK_3));
+ bonus -= BlockedStorm * int(theirRank == RANK_3);
else
bonus -= make_score(UnblockedStorm[d][theirRank], 0);
}
kingSquares[Us] = ksq;
castlingRights[Us] = pos.castling_rights(Us);
+ Score shelters[3] = { evaluate_shelter<Us>(pos, ksq),
+ make_score(-VALUE_INFINITE, 0),
+ make_score(-VALUE_INFINITE, 0) };
+
+ // If we can castle use the bonus after castling if it is bigger
+ if (pos.can_castle(Us & KING_SIDE))
- shelters[1] = evaluate_shelter<Us>(pos, relative_square(Us, SQ_G1));
++ shelters[1] = evaluate_shelter<Us>(pos, make_square(pos.castling_kingside_file(), Us == WHITE ? RANK_1 : pos.max_rank()));
+
+ if (pos.can_castle(Us & QUEEN_SIDE))
- shelters[2] = evaluate_shelter<Us>(pos, relative_square(Us, SQ_C1));
++ shelters[2] = evaluate_shelter<Us>(pos, make_square(pos.castling_queenside_file(), Us == WHITE ? RANK_1 : pos.max_rank()));
+
+ for (int i : {1, 2})
+ if (mg_value(shelters[i]) > mg_value(shelters[0]))
+ shelters[0] = shelters[i];
+
+ // In endgame we like to bring our king near our closest pawn
Bitboard pawns = pos.pieces(Us, PAWN);
int minPawnDist = pawns ? 8 : 0;
- if (pawns & PseudoAttacks[KING][ksq])
+ if (pawns & PseudoAttacks[Us][KING][ksq])
minPawnDist = 1;
-
else while (pawns)
minPawnDist = std::min(minPawnDist, distance(ksq, pop_lsb(&pawns)));
void Position::set_castling_right(Color c, Square rfrom) {
- Square kfrom = square<KING>(c);
+ Square kfrom = count<KING>(c) ? square<KING>(c) : make_square(FILE_E, relative_rank(c, castling_rank(), max_rank()));
- CastlingSide cs = kfrom < rfrom ? KING_SIDE : QUEEN_SIDE;
- CastlingRight cr = (c | cs);
+ CastlingRights cr = c & (kfrom < rfrom ? KING_SIDE: QUEEN_SIDE);
st->castlingRights |= cr;
castlingRightsMask[kfrom] |= cr;
castlingRightsMask[rfrom] |= cr;
castlingRookSquare[cr] = rfrom;
- Square kto = make_square(cs == KING_SIDE ? castling_kingside_file() : castling_queenside_file(),
- Square kto = relative_square(c, cr & KING_SIDE ? SQ_G1 : SQ_C1);
- Square rto = relative_square(c, cr & KING_SIDE ? SQ_F1 : SQ_D1);
++ Square kto = make_square(cr & KING_SIDE ? castling_kingside_file() : castling_queenside_file(),
+ relative_rank(c, castling_rank(), max_rank()));
- Square rto = kto + (cs == KING_SIDE ? WEST : EAST);
++ Square rto = kto + (cr & KING_SIDE ? WEST : EAST);
castlingPath[cr] = (between_bb(rfrom, rto) | between_bb(kfrom, kto) | rto | kto)
& ~(square_bb(kfrom) | rfrom);
if (std::memcmp(&si, st, sizeof(StateInfo)))
assert(0 && "pos_is_ok: State");
- for (Piece pc : Pieces)
- {
- if ( pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc)))
- || pieceCount[pc] != std::count(board, board + SQUARE_NB, pc))
- assert(0 && "pos_is_ok: Pieces");
-
- for (int i = 0; i < pieceCount[pc]; ++i)
- if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i)
- assert(0 && "pos_is_ok: Index");
- }
+ for (Color c : {WHITE, BLACK})
+ for (PieceType pt = PAWN; pt <= KING; ++pt)
+ {
+ Piece pc = make_piece(c, pt);
+ if ( pieceCount[pc] != popcount(pieces(c, pt))
+ || pieceCount[pc] != std::count(board, board + SQUARE_NB, pc))
+ assert(0 && "pos_is_ok: Pieces");
+
+ for (int i = 0; i < pieceCount[pc]; ++i)
+ if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i)
+ assert(0 && "pos_is_ok: Index");
+ }
for (Color c : { WHITE, BLACK })
- for (CastlingSide s : {KING_SIDE, QUEEN_SIDE})
+ for (CastlingRights cr : {c & KING_SIDE, c & QUEEN_SIDE})
{
- if (!can_castle(c | s))
+ if (!can_castle(cr))
continue;
- if ( piece_on(castlingRookSquare[c | s]) != make_piece(c, ROOK)
- || castlingRightsMask[castlingRookSquare[c | s]] != (c | s)
- || (castlingRightsMask[square<KING>(c)] & (c | s)) != (c | s))
+ if ( piece_on(castlingRookSquare[cr]) != make_piece(c, ROOK)
+ || castlingRightsMask[castlingRookSquare[cr]] != cr
+ || (castlingRightsMask[square<KING>(c)] & cr) != cr)
assert(0 && "pos_is_ok: Castling");
}
return st->epSquare;
}
+inline Bitboard Position::gates(Color c) const {
+ assert(var != nullptr);
+ return st->gatesBB[c];
+}
+
inline bool Position::is_on_semiopen_file(Color c, Square s) const {
- return !(pieces(c, PAWN) & file_bb(s));
+ return !(pieces(c, PAWN, SHOGI_PAWN) & file_bb(s));
}
- inline bool Position::can_castle(CastlingRight cr) const {
+ inline bool Position::can_castle(CastlingRights cr) const {
return st->castlingRights & cr;
}
// Step 9. Null move search with verification search (~40 Elo)
if ( !PvNode
&& (ss-1)->currentMove != MOVE_NULL
- && (ss-1)->statScore < 23200
+ && (ss-1)->statScore < 22661
&& eval >= beta
- && ss->staticEval >= beta - 36 * depth / ONE_PLY + 225
+ && eval >= ss->staticEval
+ && ss->staticEval >= beta - 33 * depth / ONE_PLY + 299 - improving * 30
&& !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);
// Null move dynamic reduction based on depth and value
- Depth R = ((823 - 150 * !pos.checking_permitted() + 67 * depth / ONE_PLY) / 256 + std::min(int(eval - beta) / 200, 3)) * ONE_PLY;
- Depth R = ((835 + 70 * depth / ONE_PLY) / 256 + std::min(int(eval - beta) / 185, 3)) * ONE_PLY;
++ Depth R = ((835 - 150 * !pos.checking_permitted() + 70 * depth / ONE_PLY) / 256 + std::min(int(eval - beta) / 185, 3)) * ONE_PLY;
ss->currentMove = MOVE_NULL;
ss->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0];
// much above beta, we can (almost) safely prune the previous move.
if ( !PvNode
&& depth >= 5 * ONE_PLY
+ && (pos.pieces() ^ pos.pieces(CLOBBER_PIECE))
&& abs(beta) < VALUE_MATE_IN_MAX_PLY)
{
- Value raisedBeta = std::min(beta + 216 * (1 + pos.check_counting() + (pos.extinction_value() != VALUE_NONE)) - 48 * improving, VALUE_INFINITE);
- Value raisedBeta = std::min(beta + 191 - 46 * improving, VALUE_INFINITE);
++ Value raisedBeta = std::min(beta + 191 * (1 + pos.check_counting() + (pos.extinction_value() != VALUE_NONE)) - 46 * improving, VALUE_INFINITE);
MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &thisThread->captureHistory);
int probCutCount = 0;
}
// Step 11. Internal iterative deepening (~2 Elo)
- if (depth >= (8 - 2 * pos.captures_to_hand()) * ONE_PLY && !ttMove)
- if (depth >= 7 * ONE_PLY && !ttMove)
++ if (depth >= (7 - 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;
if (rootNode && thisThread == Threads.main() && Time.elapsed() > 3000)
sync_cout << "info depth " << depth / ONE_PLY
- << " currmove " << UCI::move(move, pos.is_chess960())
+ << " currmove " << UCI::move(pos, move)
<< " currmovenumber " << moveCount + thisThread->pvIdx << sync_endl;
-
- // In MultiPV mode also skip moves which will be searched later as PV moves
- if (rootNode && std::count(thisThread->rootMoves.begin() + thisThread->pvIdx + 1,
- thisThread->rootMoves.begin() + thisThread->multiPV, move))
- continue;
-
if (PvNode)
(ss+1)->pv = nullptr;
lmrDepth /= ONE_PLY;
// Countermoves based pruning (~20 Elo)
- if ( lmrDepth < 3 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1)
+ if ( lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1)
- && (*contHist[0])[movedPiece][to_sq(move)] < CounterMovePruneThreshold
- && (*contHist[1])[movedPiece][to_sq(move)] < CounterMovePruneThreshold)
+ && (*contHist[0])[history_slot(movedPiece)][to_sq(move)] < CounterMovePruneThreshold
+ && (*contHist[1])[history_slot(movedPiece)][to_sq(move)] < CounterMovePruneThreshold)
continue;
// Futility pruning: parent node (~2 Elo)
- if ( lmrDepth < 7
+ if ( lmrDepth < 6
&& !inCheck
+ && !( pos.extinction_value() == -VALUE_MATE
+ && pos.extinction_piece_types().find(ALL_PIECES) == pos.extinction_piece_types().end())
- && ss->staticEval + 256 + 200 * lmrDepth <= alpha)
+ && ss->staticEval + 250 + 211 * lmrDepth <= alpha)
continue;
// Prune moves with negative SEE (~10 Elo)
- if (!pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth)))
+ if (!pos.must_capture() && !pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth)))
continue;
}
- else if ( (!givesCheck || !extension)
+ else if ( !(givesCheck && extension)
- && !pos.see_ge(move, Value(-199) * (depth / ONE_PLY))) // (~20 Elo)
+ && !pos.must_capture()
- && !pos.see_ge(move, -(PawnValueEg + 120 * pos.captures_to_hand()) * (depth / ONE_PLY))) // (~20 Elo)
++ && !pos.see_ge(move, Value(-199 - 120 * pos.captures_to_hand()) * (depth / ONE_PLY))) // (~20 Elo)
continue;
}
// Step 16. Reduced depth search (LMR). If the move fails high it will be
// re-searched at full depth.
if ( depth >= 3 * ONE_PLY
- && moveCount > 1 + 3 * rootNode
+ && moveCount > 1 + 2 * rootNode
+ && (!rootNode || thisThread->best_move_count(move) == 0)
&& ( !captureOrPromotion
|| moveCountPruning
- || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha)
+ || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha
- || cutNode))
++ || cutNode)
+ && !(pos.must_capture() && MoveList<CAPTURES>(pos).size()))
{
Depth r = reduction(improving, depth, moveCount);
if ((ss-1)->moveCount > 15)
r -= ONE_PLY;
- // Decrease reduction if move has been singularly extended
+ // Decrease reduction if ttMove has been singularly extended
r -= singularLMR * ONE_PLY;
- if (!captureOrPromotion)
+ if (!captureOrPromotion && !(pos.must_capture() && MoveList<CAPTURES>(pos).size()))
{
// Increase reduction if ttMove is a capture (~0 Elo)
if (ttCapture)
r -= 2 * ONE_PLY;
ss->statScore = thisThread->mainHistory[us][from_to(move)]
- + (*contHist[0])[movedPiece][to_sq(move)]
- + (*contHist[1])[movedPiece][to_sq(move)]
- + (*contHist[3])[movedPiece][to_sq(move)]
+ + (*contHist[0])[history_slot(movedPiece)][to_sq(move)]
+ + (*contHist[1])[history_slot(movedPiece)][to_sq(move)]
+ + (*contHist[3])[history_slot(movedPiece)][to_sq(move)]
- - 4000;
+ - 4729;
// Reset statScore to zero if negative and most stats shows >= 0
if ( ss->statScore < 0
}
constexpr Piece operator~(Piece pc) {
- return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT
+ return Piece(pc ^ PIECE_TYPE_NB); // Swap color of piece BLACK KNIGHT -> WHITE KNIGHT
}
- constexpr CastlingRight operator|(Color c, CastlingSide s) {
- return CastlingRight(WHITE_OO << ((s == QUEEN_SIDE) + 2 * c));
+ constexpr CastlingRights operator&(Color c, CastlingRights cr) {
+ return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr);
}
constexpr Value mate_in(int ply) {
return c == WHITE ? NORTH : SOUTH;
}
- inline MoveType type_of(Move m) {
-constexpr Square from_sq(Move m) {
- return Square((m >> 6) & 0x3F);
++constexpr MoveType type_of(Move m) {
+ return MoveType(m & (15 << (2 * SQUARE_BITS)));
}
constexpr Square to_sq(Move m) {
- return Square(m & 0x3F);
+ return Square(m & SQUARE_BIT_MASK);
+}
+
- inline Square from_sq(Move m) {
- if (type_of(m) == DROP)
- return SQ_NONE;
- return Square((m >> SQUARE_BITS) & SQUARE_BIT_MASK);
++constexpr Square from_sq(Move m) {
++ return type_of(m) == DROP ? SQ_NONE : Square((m >> SQUARE_BITS) & SQUARE_BIT_MASK);
}
-constexpr int from_to(Move m) {
- return m & 0xFFF;
+inline int from_to(Move m) {
+ return to_sq(m) + (from_sq(m) << SQUARE_BITS);
}
-constexpr MoveType type_of(Move m) {
- return MoveType(m & (3 << 14));
+inline PieceType promotion_type(Move m) {
+ return type_of(m) == PROMOTION ? PieceType((m >> (2 * SQUARE_BITS + MOVE_TYPE_BITS)) & (PIECE_TYPE_NB - 1)) : NO_PIECE_TYPE;
}
-constexpr PieceType promotion_type(Move m) {
- return PieceType(((m >> 12) & 3) + KNIGHT);
+inline PieceType gating_type(Move m) {
+ return PieceType((m >> (2 * SQUARE_BITS + MOVE_TYPE_BITS)) & (PIECE_TYPE_NB - 1));
+}
+
+inline Square gating_square(Move m) {
+ return Square((m >> (2 * SQUARE_BITS + MOVE_TYPE_BITS + PIECE_TYPE_BITS)) & SQUARE_BIT_MASK);
+}
+
+inline bool is_gating(Move m) {
+ return gating_type(m) && (type_of(m) == NORMAL || type_of(m) == CASTLING);
}
constexpr Move make_move(Square from, Square to) {
- return Move((from << 6) + to);
+ return Move((from << SQUARE_BITS) + to);
+}
+
+template<MoveType T>
+inline Move make(Square from, Square to, PieceType pt = NO_PIECE_TYPE) {
+ return Move((pt << (2 * SQUARE_BITS + MOVE_TYPE_BITS)) + T + (from << SQUARE_BITS) + to);
+}
+
+constexpr Move make_drop(Square to, PieceType pt_in_hand, PieceType pt_dropped) {
+ return Move((pt_in_hand << (2 * SQUARE_BITS + MOVE_TYPE_BITS + PIECE_TYPE_BITS)) + (pt_dropped << (2 * SQUARE_BITS + MOVE_TYPE_BITS)) + DROP + to);
}
+ constexpr Move reverse_move(Move m) {
+ return make_move(to_sq(m), from_sq(m));
+ }
+
template<MoveType T>
-constexpr Move make(Square from, Square to, PieceType pt = KNIGHT) {
- return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to);
+constexpr Move make_gating(Square from, Square to, PieceType pt, Square gate) {
+ return Move((gate << (2 * SQUARE_BITS + MOVE_TYPE_BITS + PIECE_TYPE_BITS)) + (pt << (2 * SQUARE_BITS + MOVE_TYPE_BITS)) + T + (from << SQUARE_BITS) + to);
+}
+
+constexpr PieceType dropped_piece_type(Move m) {
+ return PieceType((m >> (2 * SQUARE_BITS + MOVE_TYPE_BITS)) & (PIECE_TYPE_NB - 1));
+}
+
+constexpr PieceType in_hand_piece_type(Move m) {
+ return PieceType((m >> (2 * SQUARE_BITS + MOVE_TYPE_BITS + PIECE_TYPE_BITS)) & (PIECE_TYPE_NB - 1));
}
-constexpr bool is_ok(Move m) {
- return from_sq(m) != to_sq(m); // Catch MOVE_NULL and MOVE_NONE
+inline bool is_ok(Move m) {
+ return from_sq(m) != to_sq(m) || type_of(m) == PROMOTION; // Catch MOVE_NULL and MOVE_NONE
}
#endif // #ifndef TYPES_H_INCLUDED