if (s1 != s2)
{
SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2));
- DistanceRingBB[s1][SquareDistance[s1][s2] - 1] |= s2;
+ DistanceRingBB[s1][SquareDistance[s1][s2]] |= s2;
}
- int steps[][5] = { {}, { 7, 9 }, { 6, 10, 15, 17 }, {}, {}, {}, { 1, 7, 8, 9 } };
+ // Piece moves
+ Direction RookDirections[5] = { NORTH, EAST, SOUTH, WEST };
+ Direction BishopDirections[5] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
+
+#ifdef PRECOMPUTED_MAGICS
+ init_magics(RookTable, RookMagics, RookDirections, RookMagicInit);
+ init_magics(BishopTable, BishopMagics, BishopDirections, BishopMagicInit);
+#else
+ init_magics(RookTable, RookMagics, RookDirections);
+ init_magics(BishopTable, BishopMagics, BishopDirections);
+#endif
+
+ int stepsCapture[][13] = {
+ {}, // NO_PIECE_TYPE
+ { NORTH_WEST, NORTH_EAST }, // pawn
+ { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
+ NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // knight
+ {}, // bishop
+ {}, // rook
+ {}, // queen
+ { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // fers/met
+ { 2 * SOUTH_WEST, 2 * SOUTH_EAST, 2 * NORTH_WEST, 2 * NORTH_EAST }, // alfil
+ { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH, NORTH_EAST }, // silver/khon
+ { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH_WEST, SOUTH_EAST, SOUTH + 2 * EAST,
+ NORTH + 2 * WEST, NORTH_WEST, NORTH_EAST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // aiwok
+ { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // bers/dragon
+ { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
+ NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // archbishop
+ { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
+ NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // chancellor
+ { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
+ NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // amazon
+ {}, // knibis
+ { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
+ NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // biskni
+ { NORTH }, // shogi pawn
+ {}, // lance
+ { 2 * NORTH + WEST, 2 * NORTH + EAST }, // shogi knight
+ { WEST, EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // euroshogi knight
+ { SOUTH, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST }, // gold
+ { SOUTH, WEST, EAST, NORTH }, // horse
+ { SOUTH, WEST, EAST, NORTH }, // clobber
+ { NORTH_WEST, NORTH_EAST }, // breakthrough
+ {}, // immobile
+ { SOUTH, WEST, EAST, NORTH }, // wazir
+ { SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST }, // commoner
+ { SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST } // king
+ };
+ int stepsQuiet[][13] = {
+ {}, // NO_PIECE_TYPE
+ { NORTH }, // pawn
+ { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
+ NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // knight
+ {}, // bishop
+ {}, // rook
+ {}, // queen
+ { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // fers/met
+ { 2 * SOUTH_WEST, 2 * SOUTH_EAST, 2 * NORTH_WEST, 2 * NORTH_EAST }, // alfil
+ { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH, NORTH_EAST }, // silver/khon
+ { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH_WEST, SOUTH_EAST, SOUTH + 2 * EAST,
+ NORTH + 2 * WEST, NORTH_WEST, NORTH_EAST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // aiwok
+ { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // bers/dragon
+ { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
+ NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // archbishop
+ { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
+ NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // chancellor
+ { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
+ NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // amazon
+ { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
+ NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // knibis
+ {}, // biskni
+ { NORTH }, // shogi pawn
+ {}, // lance
+ { 2 * NORTH + WEST, 2 * NORTH + EAST }, // shogi knight
+ { WEST, EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // euroshogi knight
+ { SOUTH, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST }, // gold
+ { SOUTH, WEST, EAST, NORTH }, // horse
+ {}, // clobber
+ { NORTH_WEST, NORTH, NORTH_EAST }, // breakthrough
+ {}, // immobile
+ { SOUTH, WEST, EAST, NORTH }, // wazir
+ { SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST }, // commoner
+ { SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST } // king
+ };
+ Direction sliderCapture[][9] = {
+ {}, // NO_PIECE_TYPE
+ {}, // pawn
+ {}, // knight
+ { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // bishop
+ { NORTH, EAST, SOUTH, WEST }, // rook
+ { NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // queen
+ {}, // fers/met
+ {}, // alfil
+ {}, // silver/khon
+ { NORTH, EAST, SOUTH, WEST }, // aiwok
+ { NORTH, EAST, SOUTH, WEST }, // bers/dragon
+ { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // archbishop
+ { NORTH, EAST, SOUTH, WEST }, // chancellor
+ { NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // amazon
+ { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // knibis
+ {}, // biskni
+ {}, // shogi pawn
+ { NORTH }, // lance
+ {}, // shogi knight
+ {}, // euroshogi knight
+ {}, // gold
+ { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // horse
+ {}, // clobber
+ {}, // breakthrough
+ {}, // immobile
+ {}, // wazir
+ {}, // commoner
+ {} // king
+ };
+ Direction sliderQuiet[][9] = {
+ {}, // NO_PIECE_TYPE
+ {}, // pawn
+ {}, // knight
+ { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // bishop
+ { NORTH, EAST, SOUTH, WEST }, // rook
+ { NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // queen
+ {}, // fers/met
+ {}, // alfil
+ {}, // silver/khon
+ { NORTH, EAST, SOUTH, WEST }, // aiwok
+ { NORTH, EAST, SOUTH, WEST }, // bers/dragon
+ { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // archbishop
+ { NORTH, EAST, SOUTH, WEST }, // chancellor
+ { NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // amazon
+ {}, // knibis
+ { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // biskni
+ {}, // shogi pawn
+ { NORTH }, // lance
+ {}, // shogi knight
+ {}, // euroshogi knight
+ {}, // gold
+ { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // horse
+ {}, // clobber
+ {}, // breakthrough
+ {}, // immobile
+ {}, // wazir
+ {}, // commoner
+ {} // king
+ };
+ int sliderDistCapture[] = {
+ 0, // NO_PIECE_TYPE
+ 0, // pawn
+ 0, // knight
+ FILE_MAX, // bishop
+ FILE_MAX, // rook
+ FILE_MAX, // queen
+ 0, // fers/met
+ 0, // alfil
+ 0, // silver/khon
+ FILE_MAX, // aiwok
+ FILE_MAX, // bers/dragon
+ FILE_MAX, // archbishop
+ FILE_MAX, // chancellor
+ FILE_MAX, // amazon
+ FILE_MAX, // knibis
+ 0, // biskni
+ 0, // shogi pawn
+ FILE_MAX, // lance
+ 0, // shogi knight
+ 0, // euroshogi knight
+ 0, // gold
+ FILE_MAX, // horse
+ 0, // clobber
+ 0, // breakthrough
+ 0, // immobile
+ 0, // wazir
+ 0, // commoner
+ 0 // king
+ };
+ int sliderDistQuiet[] = {
+ 0, // NO_PIECE_TYPE
+ 0, // pawn
+ 0, // knight
+ FILE_MAX, // bishop
+ FILE_MAX, // rook
+ FILE_MAX, // queen
+ 0, // fers/met
+ 0, // alfil
+ 0, // silver/khon
+ FILE_MAX, // aiwok
+ FILE_MAX, // bers/dragon
+ FILE_MAX, // archbishop
+ FILE_MAX, // chancellor
+ FILE_MAX, // amazon
+ 0, // knibis
+ FILE_MAX, // biskni
+ 0, // shogi pawn
+ FILE_MAX, // lance
+ 0, // shogi knight
+ 0, // euroshogi knight
+ 0, // gold
+ FILE_MAX, // horse
+ 0, // clobber
+ 0, // breakthrough
+ 0, // immobile
+ 0, // wazir
+ 0, // commoner
+ 0 // king
+ };
for (Color c = WHITE; c <= BLACK; ++c)
- for (PieceType pt : { PAWN, KNIGHT, KING })
- for (Square s = SQ_A1; s <= SQ_H8; ++s)
- for (int i = 0; steps[pt][i]; ++i)
+ for (PieceType pt = PAWN; pt <= KING; ++pt)
+ for (Square s = SQ_A1; s <= SQ_MAX; ++s)
+ {
+ for (int i = 0; stepsCapture[pt][i]; ++i)
{
- Square to = s + Direction(c == WHITE ? steps[pt][i] : -steps[pt][i]);
+ Square to = s + Direction(c == WHITE ? stepsCapture[pt][i] : -stepsCapture[pt][i]);
- if (is_ok(to) && distance(s, to) < 3)
+ if (is_ok(to) && distance(s, to) < 4)
{
- if (pt == PAWN)
- PawnAttacks[c][s] |= to;
- else
- PseudoAttacks[pt][s] |= to;
+ PseudoAttacks[c][pt][s] |= to;
+ LeaperAttacks[c][pt][s] |= to;
}
}
+ for (int i = 0; stepsQuiet[pt][i]; ++i)
+ {
+ Square to = s + Direction(c == WHITE ? stepsQuiet[pt][i] : -stepsQuiet[pt][i]);
- Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST };
- Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
-
- init_magics(RookTable, RookMagics, RookDirections);
- init_magics(BishopTable, BishopMagics, BishopDirections);
+ if (is_ok(to) && distance(s, to) < 4)
+ {
+ PseudoMoves[c][pt][s] |= to;
+ LeaperMoves[c][pt][s] |= to;
+ }
+ }
+ PseudoAttacks[c][pt][s] |= sliding_attack(sliderCapture[pt], s, 0, sliderDistCapture[pt], c);
+ PseudoMoves[c][pt][s] |= sliding_attack(sliderQuiet[pt], s, 0, sliderDistQuiet[pt], c);
+ }
- for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
+ for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1)
{
- PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb<BISHOP>(s1, 0);
- PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0);
-
for (PieceType pt : { BISHOP, ROOK })
- for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
+ for (Square s2 = SQ_A1; s2 <= SQ_MAX; ++s2)
{
- if (!(PseudoAttacks[pt][s1] & s2))
+ if (!(PseudoAttacks[WHITE][pt][s1] & s2))
continue;
- LineBB[s1][s2] = (attacks_bb(pt, s1, 0) & attacks_bb(pt, s2, 0)) | s1 | s2;
- BetweenBB[s1][s2] = attacks_bb(pt, s1, SquareBB[s2]) & attacks_bb(pt, s2, SquareBB[s1]);
+ LineBB[s1][s2] = (attacks_bb(WHITE, pt, s1, 0) & attacks_bb(WHITE, pt, s2, 0)) | s1 | s2;
+ BetweenBB[s1][s2] = attacks_bb(WHITE, pt, s1, SquareBB[s2]) & attacks_bb(WHITE, pt, s2, SquareBB[s1]);
}
}
}
Score Evaluation<T>::king() const {
constexpr Color Them = (Us == WHITE ? BLACK : WHITE);
- constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB
- : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB);
+ Rank r = relative_rank(Us, std::min(Rank((pos.max_rank() - 1) / 2 + 1), pos.max_rank()), pos.max_rank());
+ Bitboard Camp = AllSquares ^ forward_ranks_bb(Us, r);
+
+ if (!pos.count<KING>(Us) || !pos.checking_permitted())
+ return SCORE_ZERO;
const Square ksq = pos.square<KING>(Us);
- Bitboard weak, b, b1, b2, safe, unsafeChecks;
+ Bitboard kingFlank, weak, b, b1, b2, safe, unsafeChecks;
// King shelter and enemy pawns storm
Score score = pe->king_safety<Us>(pos, ksq);
+ // Find the squares that opponent attacks in our king flank, and the squares
+ // which are attacked twice in that flank but not defended by our pawns.
- kingFlank = KingFlank[file_of(ksq)];
++ File f = std::max(std::min(file_of(ksq), File(pos.max_file() - 1)), FILE_B);
++ kingFlank = pos.max_file() == FILE_H ? KingFlank[file_of(ksq)] : file_bb(f) | adjacent_files_bb(f);
+ b1 = attackedBy[Them][ALL_PIECES] & kingFlank & Camp;
- b2 = b1 & attackedBy2[Them] & ~attackedBy[Us][PAWN];
++ b2 = b1 & attackedBy2[Them] & ~attackedBy[Us][PAWN] & ~attackedBy[Us][SHOGI_PAWN];
+
+ int tropism = popcount(b1) + popcount(b2);
+
// Main king safety evaluation
- if (kingAttackersCount[Them] > 1 - pos.count<QUEEN>(Them))
+ if ((kingAttackersCount[Them] > 1 - pos.count<QUEEN>(Them)) || pos.captures_to_hand())
{
int kingDanger = 0;
unsafeChecks = 0;
unsafeChecks &= mobilityArea[Them];
kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them]
- + 69 * kingAttacksCount[Them]
- + 185 * popcount(kingRing[Us] & weak)
+ + 69 * kingAttacksCount[Them] * (1 + 2 * !!pos.max_check_count())
+ + 185 * popcount(kingRing[Us] & weak) * (1 + pos.captures_to_hand() + !!pos.max_check_count())
- + 129 * popcount(pos.blockers_for_king(Us) | unsafeChecks)
+ + 150 * popcount(pos.blockers_for_king(Us) | unsafeChecks)
+ + 4 * tropism
- - 873 * !pos.count<QUEEN>(Them)
+ - 873 * !(pos.count<QUEEN>(Them) || pos.captures_to_hand()) / (1 + !!pos.max_check_count())
- 6 * mg_value(score) / 8
- - 2;
+ - 30;
// Transform the kingDanger units into a Score, and subtract it from the evaluation
if (kingDanger > 0)
}
}
- File f = std::max(std::min(file_of(ksq), File(pos.max_file() - 1)), FILE_B);
- Bitboard kf = pos.max_file() == FILE_H ? KingFlank[f] : file_bb(f) | adjacent_files_bb(f);
-
// Penalty when our king is on a pawnless flank
- if (!(pos.pieces(PAWN) & kf))
+ if (!(pos.pieces(PAWN) & kingFlank))
score -= PawnlessFlank;
- // Find the squares that opponent attacks in our king flank, and the squares
- // which are attacked twice in that flank but not defended by our pawns.
- b1 = attackedBy[Them][ALL_PIECES] & kf & Camp;
- b2 = b1 & attackedBy2[Them] & ~(attackedBy[Us][PAWN] | attackedBy[Us][SHOGI_PAWN]);
-
- // King tropism, to anticipate slow motion attacks on our king
- score -= CloseEnemies * (popcount(b1) + popcount(b2)) * (1 + pos.captures_to_hand() + !!pos.max_check_count());
+ // King tropism bonus, to anticipate slow motion attacks on our king
- score -= CloseEnemies * tropism;
++ score -= CloseEnemies * tropism * (1 + pos.captures_to_hand() + !!pos.max_check_count());
+
+ // For drop games, king danger is independent of game phase
+ if (pos.captures_to_hand())
+ score = make_score(mg_value(score), mg_value(score)) / (1 + !pos.shogi_doubled_pawn());
if (T)
Trace::add(KING, Us, score);
{
Square s = pop_lsb(&b);
score += ThreatByMinor[type_of(pos.piece_on(s))];
-
- if (type_of(pos.piece_on(s)) != PAWN)
- score += ThreatByRank * (int)relative_rank(Them, s);
+ if (type_of(pos.piece_on(s)) != PAWN && type_of(pos.piece_on(s)) != SHOGI_PAWN)
+ score += ThreatByRank * (int)relative_rank(Them, s, pos.max_rank());
-
- else if (pos.blockers_for_king(Them) & s)
- score += ThreatByRank * (int)relative_rank(Them, s, pos.max_rank()) / 2;
}
b = weak & attackedBy[Us][ROOK];
{
Square s = pop_lsb(&b);
score += ThreatByRook[type_of(pos.piece_on(s))];
- if (type_of(pos.piece_on(s)) != PAWN)
- score += ThreatByRank * (int)relative_rank(Them, s);
+ if (type_of(pos.piece_on(s)) != PAWN && type_of(pos.piece_on(s)) != SHOGI_PAWN)
+ score += ThreatByRank * (int)relative_rank(Them, s, pos.max_rank());
-
- else if (pos.blockers_for_king(Them) & s)
- score += ThreatByRank * (int)relative_rank(Them, s, pos.max_rank()) / 2;
}
if (weak & attackedBy[Us][KING])
assert(!(pos.pieces(Them, PAWN) & forward_file_bb(Us, s + Up)));
- if (forward_file_bb(Us, s) & pos.pieces(Them))
- score -= HinderPassedPawn;
-
- int r = relative_rank(Us, s);
+ int r = relative_rank(Us, s, pos.max_rank());
int w = PassedDanger[r];
Score bonus = PassedRank[r];
template<Tracing T> template<Color Us>
Score Evaluation<T>::space() const {
- constexpr Color Them = (Us == WHITE ? BLACK : WHITE);
- constexpr Bitboard SpaceMask =
- Us == WHITE ? CenterFiles & (Rank2BB | Rank3BB | Rank4BB)
- : CenterFiles & (Rank7BB | Rank6BB | Rank5BB);
-
- if (pos.non_pawn_material() < SpaceThreshold)
+ bool pawnsOnly = !(pos.pieces(Us) ^ pos.pieces(Us, PAWN));
+
+ if (pos.non_pawn_material() < SpaceThreshold && !pos.captures_to_hand() && !pawnsOnly)
return SCORE_ZERO;
+ constexpr Color Them = (Us == WHITE ? BLACK : WHITE);
+ constexpr Bitboard SpaceMask =
+ Us == WHITE ? CenterFiles & (Rank2BB | Rank3BB | Rank4BB)
+ : CenterFiles & (Rank7BB | Rank6BB | Rank5BB);
+
// Find the available squares for our pieces inside the area defined by SpaceMask
Bitboard safe = SpaceMask
- & ~pos.pieces(Us, PAWN)
- & ~attackedBy[Them][PAWN];
+ & ~pos.pieces(Us, PAWN, SHOGI_PAWN)
+ & ~attackedBy[Them][PAWN]
+ & ~attackedBy[Them][SHOGI_PAWN];
+
+ if (pawnsOnly)
+ safe = pos.pieces(Us, PAWN) & ~attackedBy[Them][ALL_PIECES];
// Find all squares which are at most three squares behind some friendly pawn
- Bitboard behind = pos.pieces(Us, PAWN);
- behind |= (Us == WHITE ? behind >> 8 : behind << 8);
- behind |= (Us == WHITE ? behind >> 16 : behind << 16);
+ Bitboard behind = pos.pieces(Us, PAWN, SHOGI_PAWN);
+ behind |= (Us == WHITE ? behind >> NORTH : behind << NORTH);
+ behind |= (Us == WHITE ? behind >> (2 * NORTH) : behind << (2 * NORTH));
+
int bonus = popcount(safe) + popcount(behind & safe);
int weight = pos.count<ALL_PIECES>(Us) - 2 * pe->open_files();
Bitboard ourPawns = b & pos.pieces(Us);
Bitboard theirPawns = b & pos.pieces(Them);
- Value safety = (ourPawns & file_bb(ksq)) ? Value(5) : Value(-5);
-
- if (shift<Down>(theirPawns) & (FileABB | FileHBB) & BlockRanks & ksq)
- safety += Value(374);
+ Value safety = (shift<Down>(theirPawns) & (FileABB | FileHBB) & BlockRanks & ksq) ?
+ Value(374) : Value(5);
- File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq)));
+ File center = std::max(FILE_B, std::min(File(pos.max_file() - 1), file_of(ksq)));
for (File f = File(center - 1); f <= File(center + 1); ++f)
{
b = ourPawns & file_bb(f);
// type on a given square a (middlegame, endgame) score pair is assigned. Table
// is defined for files A..D and white side: it is symmetric for black side and
// second half of the files.
-constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = {
+constexpr Score Bonus[PIECE_TYPE_NB][RANK_NB][int(FILE_NB) / 2] = {
{ },
{ // Pawn
- { S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0) },
- { S(-11, 7), S( 6,-4), S( 7, 8), S( 3,-2) },
- { S(-18,-4), S( -2,-5), S( 19, 5), S(24, 4) },
- { S(-17, 3), S( -9, 3), S( 20,-8), S(35,-3) },
- { S( -6, 8), S( 5, 9), S( 3, 7), S(21,-6) },
- { S( -6, 8), S( -8,-5), S( -6, 2), S(-2, 4) },
- { S( -4, 3), S( 20,-9), S( -8, 1), S(-4,18) }
+ { S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0) },
+ { S(-11,-3), S( 7, -1), S( 7, 7), S(17, 2) },
+ { S(-16,-2), S( -3, 2), S( 23, 6), S(23,-1) },
+ { S(-14, 7), S( -7, -4), S( 20,-8), S(24, 2) },
+ { S( -5,13), S( -2, 10), S( -1,-1), S(12,-8) },
+ { S(-11,16), S(-12, 6), S( -2, 1), S( 4,16) },
+ { S( -2, 1), S( 20,-12), S(-10, 6), S(-2,25) }
},
{ // Knight
{ S(-161,-105), S(-96,-82), S(-80,-46), S(-73,-14) },
{ S(-2,-40), S( 6,-16), S( 8,-10), S(10, 3) },
{ S(-2,-55), S( 7,-30), S( 7,-21), S( 6, -6) },
{ S(-1,-74), S(-4,-55), S(-1,-43), S( 0,-30) }
- },
- { // King
+ }
+};
+
+constexpr Score KingBonus[RANK_NB][int(FILE_NB) / 2] = {
- { S(267, 0), S(320, 48), S(270, 75), S(195, 84) },
- { S(264, 43), S(304, 92), S(238,143), S(180,132) },
- { S(200, 83), S(245,138), S(176,167), S(110,165) },
- { S(177,106), S(185,169), S(148,169), S(110,179) },
- { S(149,108), S(177,163), S(115,200), S( 66,203) },
- { S(118, 95), S(159,155), S( 84,176), S( 41,174) },
- { S( 87, 50), S(128, 99), S( 63,122), S( 20,139) },
- { S( 63, 9), S( 88, 55), S( 47, 80), S( 0, 90) }
+ { S(272, 0), S(325, 41), S(273, 80), S(190, 93) },
+ { S(277, 57), S(305, 98), S(241,138), S(183,131) },
+ { S(198, 86), S(253,138), S(168,165), S(120,173) },
+ { S(169,103), S(191,152), S(136,168), S(108,169) },
+ { S(145, 98), S(176,166), S(112,197), S(69, 194) },
+ { S(122, 87), S(159,164), S(85, 174), S(36, 189) },
+ { S(87, 40), S(120, 99), S(64, 128), S(25, 141) },
+ { S(64, 5), S(87, 60), S(49, 75), S(0, 75) }
- }
};
#undef S
if (!rootNode)
{
+ Value variantResult;
+ if (pos.is_game_end(variantResult, ss->ply))
+ return variantResult;
+
// Step 2. Check for aborted search and immediate draw
if ( Threads.stop.load(std::memory_order_relaxed)
- || pos.is_draw(ss->ply)
|| ss->ply >= MAX_PLY)
- return (ss->ply >= MAX_PLY && !inCheck) ? evaluate(pos) : VALUE_DRAW;
+ return (ss->ply >= MAX_PLY && !inCheck) ? evaluate(pos)
+ : value_draw(depth, pos.this_thread());
// Step 3. Mate distance pruning. Even if we mate at the next move our score
// would be at best mate_in(ss->ply+1), but if alpha is already bigger because
}
else
{
- ss->staticEval = eval =
- (ss-1)->currentMove != MOVE_NULL ? evaluate(pos)
- : -(ss-1)->staticEval + 2 * Eval::tempo_value(pos);
+ if ((ss-1)->currentMove != MOVE_NULL)
+ {
+ int p = (ss-1)->statScore;
+ int bonus = p > 0 ? (-p - 2500) / 512 :
+ p < 0 ? (-p + 2500) / 512 : 0;
- tte->save(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE,
- ss->staticEval);
+ pureStaticEval = evaluate(pos);
+ ss->staticEval = eval = pureStaticEval + bonus;
+ }
+ else
- ss->staticEval = eval = pureStaticEval = -(ss-1)->staticEval + 2 * Eval::Tempo;
++ ss->staticEval = eval = pureStaticEval = -(ss-1)->staticEval + 2 * Eval::tempo_value(pos);
+
+ tte->save(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE, pureStaticEval);
}
// Step 7. Razoring (~2 Elo)
- if ( !PvNode
- && depth < 3 * ONE_PLY
+ if ( depth < 2 * ONE_PLY
+ && !pos.must_capture()
+ && !pos.capture_the_flag_piece()
+ && !pos.max_check_count()
- && eval <= alpha - RazorMargin[depth / ONE_PLY])
- {
- Value ralpha = alpha - (depth >= 2 * ONE_PLY) * RazorMargin[depth / ONE_PLY];
- Value v = qsearch<NonPV>(pos, ss, ralpha, ralpha+1);
- if (depth < 2 * ONE_PLY || v <= ralpha)
- return v;
- }
+ && eval <= alpha - RazorMargin)
+ return qsearch<NT>(pos, ss, alpha, beta);
improving = ss->staticEval >= (ss-2)->staticEval
|| (ss-2)->staticEval == VALUE_NONE;
// Step 9. Null move search with verification search (~40 Elo)
if ( !PvNode
&& (ss-1)->currentMove != MOVE_NULL
- && (ss-1)->statScore < 22500
+ && (ss-1)->statScore < 23200
&& eval >= beta
- && ss->staticEval >= beta - 36 * depth / ONE_PLY + 225
+ && pureStaticEval >= 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);
// Null move dynamic reduction based on depth and value
- Depth R = ((823 - 150 * !pos.checking_permitted() + 67 * depth / ONE_PLY) / 256 + std::min((eval - beta) / PawnValueMg, 3)) * ONE_PLY;
- Depth R = ((823 + 67 * depth / ONE_PLY) / 256 + std::min(int(eval - beta) / 200, 3)) * ONE_PLY;
++ Depth R = ((823 - 150 * !pos.checking_permitted() + 67 * depth / ONE_PLY) / 256 + std::min(int(eval - beta) / 200, 3)) * ONE_PLY;
ss->currentMove = MOVE_NULL;
- ss->continuationHistory = thisThread->continuationHistory[NO_PIECE][0].get();
+ ss->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0];
pos.do_null_move(st);
extension = ONE_PLY;
}
else if ( givesCheck // Check extension (~2 Elo)
- && !moveCountPruning
&& pos.see_ge(move))
extension = ONE_PLY;
+ else if ( pos.must_capture() // Capture extension (all moves are captures)
+ && pos.capture(move)
+ && MoveList<CAPTURES>(pos).size() == 1)
+ extension = ONE_PLY;
// Calculate new depth for this move
newDepth = depth - ONE_PLY + extension;
{
Depth r = reduction<PvNode>(improving, depth, moveCount);
- if (captureOrPromotion || (pos.must_capture() && MoveList<CAPTURES>(pos).size())) // (~5 Elo)
- {
- // Decrease reduction by comparing opponent's stat score
- if ((ss-1)->statScore < 0)
- r -= ONE_PLY;
- }
- else
- {
- // Decrease reduction if opponent's move count is high (~5 Elo)
- if ((ss-1)->moveCount > 15)
- r -= ONE_PLY;
+ // Decrease reduction if opponent's move count is high (~10 Elo)
+ if ((ss-1)->moveCount > 15)
+ r -= ONE_PLY;
- if (!captureOrPromotion)
++ if (!captureOrPromotion && !(pos.must_capture() && MoveList<CAPTURES>(pos).size()))
+ {
// Decrease reduction for exact PV nodes (~0 Elo)
if (pvExact)
r -= ONE_PLY;
VALUE_MATE_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY,
VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY,
- PawnValueMg = 171, PawnValueEg = 240,
- KnightValueMg = 764, KnightValueEg = 848,
- BishopValueMg = 826, BishopValueEg = 891,
- RookValueMg = 1282, RookValueEg = 1373,
- QueenValueMg = 2500, QueenValueEg = 2670,
- PawnValueMg = 142, PawnValueEg = 207,
- KnightValueMg = 784, KnightValueEg = 868,
- BishopValueMg = 828, BishopValueEg = 916,
- RookValueMg = 1286, RookValueEg = 1378,
- QueenValueMg = 2528, QueenValueEg = 2698,
++ PawnValueMg = 142, PawnValueEg = 207,
++ KnightValueMg = 784, KnightValueEg = 868,
++ BishopValueMg = 828, BishopValueEg = 916,
++ RookValueMg = 1286, RookValueEg = 1378,
++ QueenValueMg = 2528, QueenValueEg = 2698,
+ FersValueMg = 400, FersValueEg = 400,
+ AlfilValueMg = 300, AlfilValueEg = 300,
+ SilverValueMg = 600, SilverValueEg = 600,
+ AiwokValueMg = 2500, AiwokValueEg = 2500,
+ BersValueMg = 2000, BersValueEg = 2000,
+ ArchbishopValueMg = 2000, ArchbishopValueEg = 2000,
+ ChancellorValueMg = 2300, ChancellorValueEg = 2300,
+ AmazonValueMg = 3000, AmazonValueEg = 3000,
+ KnibisValueMg = 800, KnibisValueEg = 800,
+ BiskniValueMg = 800, BiskniValueEg = 800,
+ ShogiPawnValueMg = 100, ShogiPawnValueEg = 100,
+ LanceValueMg = 300, LanceValueEg = 300,
+ ShogiKnightValueMg = 300, ShogiKnightValueEg = 300,
+ EuroShogiKnightValueMg = 400, EuroShogiKnightValueEg = 400,
+ GoldValueMg = 600, GoldValueEg = 600,
+ HorseValueMg = 1500, HorseValueEg = 1500,
+ ClobberPieceValueMg = 300, ClobberPieceValueEg = 300,
+ BreakthroughPieceValueMg = 300, BreakthroughPieceValueEg = 300,
+ ImmobilePieceValueMg = 100, ImmobilePieceValueEg = 100,
+ WazirValueMg = 400, WazirValueEg = 400,
+ CommonerValueMg = 600, CommonerValueEg = 600,
MidgameLimit = 15258, EndgameLimit = 3915
};