S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260)
};
+ // KingProximity contains a penalty according to distance from king
+ constexpr Score KingProximity = S(1, 3);
+ constexpr Score EndgameKingProximity = S(0, 10);
+
// Assorted bonuses and penalties
- constexpr Score BishopPawns = S( 3, 7);
- constexpr Score CorneredBishop = S( 50, 50);
- constexpr Score FlankAttacks = S( 8, 0);
- constexpr Score Hanging = S( 69, 36);
- constexpr Score KingProtector = S( 7, 8);
- constexpr Score KnightOnQueen = S( 16, 12);
- constexpr Score LongDiagonalBishop = S( 45, 0);
- constexpr Score MinorBehindPawn = S( 18, 3);
- constexpr Score Outpost = S( 30, 21);
- constexpr Score PassedFile = S( 11, 8);
- constexpr Score PawnlessFlank = S( 17, 95);
- constexpr Score RestrictedPiece = S( 7, 7);
- constexpr Score RookOnQueenFile = S( 7, 6);
- constexpr Score SliderOnQueen = S( 59, 18);
- constexpr Score ThreatByKing = S( 24, 89);
- constexpr Score ThreatByPawnPush = S( 48, 39);
- constexpr Score ThreatBySafePawn = S(173, 94);
- constexpr Score TrappedRook = S( 52, 10);
- constexpr Score WeakQueen = S( 49, 15);
+ constexpr Score BishopPawns = S( 3, 7);
+ constexpr Score CorneredBishop = S( 50, 50);
+ constexpr Score FlankAttacks = S( 8, 0);
+ constexpr Score Hanging = S( 69, 36);
+ constexpr Score KingProtector = S( 7, 8);
+ constexpr Score KnightOnQueen = S( 16, 12);
+ constexpr Score LongDiagonalBishop = S( 45, 0);
+ constexpr Score MinorBehindPawn = S( 18, 3);
+ constexpr Score Outpost = S( 30, 21);
+ constexpr Score PassedFile = S( 11, 8);
+ constexpr Score PawnlessFlank = S( 17, 95);
+ constexpr Score RestrictedPiece = S( 7, 7);
+ constexpr Score RookOnQueenFile = S( 7, 6);
+ constexpr Score SliderOnQueen = S( 59, 18);
+ constexpr Score ThreatByKing = S( 24, 89);
+ constexpr Score ThreatByPawnPush = S( 48, 39);
+ constexpr Score ThreatBySafePawn = S(173, 94);
+ constexpr Score TrappedRook = S( 52, 10);
+ constexpr Score WeakQueen = S( 49, 15);
+ constexpr Score WeakQueenProtection = S( 14, 0);
#undef S
Trace::add(TOTAL, score);
}
- return (pos.side_to_move() == WHITE ? v : -v) // Side to move point of view
- + Eval::tempo_value(pos);
- return (pos.side_to_move() == WHITE ? v : -v) + Tempo; // Side to move point of view
++ return (pos.side_to_move() == WHITE ? v : -v) + Eval::tempo_value(pos); // Side to move point of view
}
} // namespace
#include <algorithm>
#include "types.h"
+#include "piece.h"
+#include "variant.h"
- Value PieceValue[PHASE_NB][PIECE_NB] = {
- { VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg,
- FersValueMg, AlfilValueMg, FersAlfilValueMg, SilverValueMg, AiwokValueMg, BersValueMg,
- ArchbishopValueMg, ChancellorValueMg, AmazonValueMg, KnibisValueMg, BiskniValueMg, KnirooValueMg, RookniValueMg,
- ShogiPawnValueMg, LanceValueMg, ShogiKnightValueMg, EuroShogiKnightValueMg, GoldValueMg, DragonHorseValueMg,
- ClobberPieceValueMg, BreakthroughPieceValueMg, ImmobilePieceValueMg,
- CannonPieceValueMg, JanggiCannonPieceValueMg, SoldierValueMg, HorseValueMg, ElephantValueMg, JanggiElephantValueMg, BannerValueMg,
- WazirValueMg, CommonerValueMg, CentaurValueMg },
- { VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg,
- FersValueEg, AlfilValueEg, FersAlfilValueEg, SilverValueEg, AiwokValueEg, BersValueEg,
- ArchbishopValueMg, ChancellorValueEg, AmazonValueEg, KnibisValueMg, BiskniValueMg, KnirooValueEg, RookniValueEg,
- ShogiPawnValueEg, LanceValueEg, ShogiKnightValueEg, EuroShogiKnightValueEg, GoldValueEg, DragonHorseValueEg,
- ClobberPieceValueEg, BreakthroughPieceValueEg, ImmobilePieceValueEg,
- CannonPieceValueEg, JanggiCannonPieceValueEg, SoldierValueEg, HorseValueEg, ElephantValueEg, JanggiElephantValueEg, BannerValueEg,
- WazirValueEg, CommonerValueEg, CentaurValueEg }
- };
-
namespace PSQT {
#define S(mg, eg) make_score(mg, eg)
// init() initializes piece-square tables: the white halves of the tables are
// copied from Bonus[] adding the piece value, then the black halves of the
// tables are initialized by flipping and changing the sign of the white scores.
-void init() {
+void init(const Variant* v) {
- for (Piece pc = W_PAWN; pc <= W_KING; ++pc)
+ PieceType strongestPiece = NO_PIECE_TYPE;
+ for (PieceType pt : v->pieceTypes)
+ if (PieceValue[MG][pt] > PieceValue[MG][strongestPiece])
+ strongestPiece = pt;
+
+ Value maxPromotion = VALUE_ZERO;
+ for (PieceType pt : v->promotionPieceTypes)
+ maxPromotion = std::max(maxPromotion, PieceValue[EG][pt]);
+
+ for (PieceType pt = PAWN; pt <= KING; ++pt)
{
+ Piece pc = make_piece(WHITE, pt);
+
- PieceValue[MG][~pc] = PieceValue[MG][pc];
- PieceValue[EG][~pc] = PieceValue[EG][pc];
-
Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]);
- for (Square s = SQ_A1; s <= SQ_H8; ++s)
+ // Consider promotion types in pawn score
+ if (pt == PAWN)
+ score -= make_score(0, (QueenValueEg - maxPromotion) / 100);
+
+ // Scale slider piece values with board size
+ const PieceInfo* pi = pieceMap.find(pt)->second;
+ bool isSlider = pi->sliderQuiet.size() || pi->sliderCapture.size() || pi->hopperQuiet.size() || pi->hopperCapture.size();
+ bool isPawn = !isSlider && pi->stepsQuiet.size() && !std::any_of(pi->stepsQuiet.begin(), pi->stepsQuiet.end(), [](Direction d) { return d < SOUTH / 2; });
+ bool isSlowLeaper = !isSlider && !std::any_of(pi->stepsQuiet.begin(), pi->stepsQuiet.end(), [](Direction d) { return dist(d) > 1; });
+
+ if (isSlider)
+ {
+ constexpr int lc = 5;
+ constexpr int rm = 5;
+ constexpr int r0 = rm + RANK_8;
+ int r1 = rm + (v->maxRank + v->maxFile) / 2;
+ int leaper = pi->stepsQuiet.size() + pi->stepsCapture.size();
+ int slider = pi->sliderQuiet.size() + pi->sliderCapture.size() + pi->hopperQuiet.size() + pi->hopperCapture.size();
+ score = make_score(mg_value(score) * (lc * leaper + r1 * slider) / (lc * leaper + r0 * slider),
+ eg_value(score) * (lc * leaper + r1 * slider) / (lc * leaper + r0 * slider));
+ }
+
+ // Increase leapers' value in makpong
+ if (v->makpongRule)
+ {
+ if (std::any_of(pi->stepsCapture.begin(), pi->stepsCapture.end(), [](Direction d) { return dist(d) > 1; })
+ && !pi->lameLeaper)
+ score = make_score(mg_value(score) * 4200 / (3500 + mg_value(score)),
+ eg_value(score) * 4700 / (3500 + mg_value(score)));
+ }
+
+ // For drop variants, halve the piece values
+ if (v->capturesToHand)
+ score = make_score(mg_value(score) * 3500 / (7000 + mg_value(score)),
+ eg_value(score) * 3500 / (7000 + eg_value(score)));
+ else if (!v->checking)
+ score = make_score(mg_value(score) * 2000 / (3500 + mg_value(score)),
+ eg_value(score) * 2200 / (3500 + eg_value(score)));
+ else if (v->twoBoards)
+ score = make_score(mg_value(score) * 7000 / (7000 + mg_value(score)),
+ eg_value(score) * 7000 / (7000 + eg_value(score)));
+ else if (v->checkCounting)
+ score = make_score(mg_value(score) * (40000 + mg_value(score)) / 41000,
+ eg_value(score) * (30000 + eg_value(score)) / 31000);
+ else if (pt == strongestPiece)
+ score += make_score(std::max(QueenValueMg - PieceValue[MG][pt], VALUE_ZERO) / 20,
+ std::max(QueenValueEg - PieceValue[EG][pt], VALUE_ZERO) / 20);
+
+ // For antichess variants, use negative piece values
+ if ( v->extinctionValue == VALUE_MATE
+ && v->extinctionPieceTypes.find(ALL_PIECES) != v->extinctionPieceTypes.end())
+ score = -make_score(mg_value(score) / 8, eg_value(score) / 8 / (1 + !pi->sliderCapture.size()));
+
+ for (Square s = SQ_A1; s <= SQ_MAX; ++s)
{
- File f = map_to_queenside(file_of(s));
- psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)]
- : Bonus[pc][rank_of(s)][f]);
- psq[~pc][~s] = -psq[pc][s];
+ File f = std::max(std::min(file_of(s), File(v->maxFile - file_of(s))), FILE_A);
+ Rank r = rank_of(s);
+ psq[ pc][ s] = score + ( pt == PAWN ? PBonus[std::min(r, RANK_8)][std::min(file_of(s), FILE_H)]
+ : pt == KING ? KingBonus[std::min(r, RANK_8)][std::min(f, FILE_D)] * (1 + v->capturesToHand)
+ : pt <= QUEEN ? Bonus[pc][std::min(r, RANK_8)][std::min(f, FILE_D)]
+ : pt == HORSE ? Bonus[KNIGHT][std::min(r, RANK_8)][std::min(f, FILE_D)]
+ : isSlider ? make_score(5, 5) * (2 * f + std::max(std::min(r, Rank(v->maxRank - r)), RANK_1) - v->maxFile - 1)
+ : isPawn ? make_score(5, 5) * (2 * f - v->maxFile)
+ : make_score(10, 10) * (1 + isSlowLeaper) * (f + std::max(std::min(r, Rank(v->maxRank - r)), RANK_1) - v->maxFile / 2));
+ if (pt == SOLDIER && r < v->soldierPromotionRank)
+ psq[pc][s] -= score * (v->soldierPromotionRank - r) / (4 + f);
+ psq[~pc][rank_of(s) <= v->maxRank ? relative_square(BLACK, s, v->maxRank) : s] = -psq[pc][s];
}
+ // pieces in pocket
+ psq[ pc][SQ_NONE] = score + make_score(45, 10);
+ psq[~pc][SQ_NONE] = -psq[pc][SQ_NONE];
}
}
BishopValueMg = 825, BishopValueEg = 915,
RookValueMg = 1276, RookValueEg = 1380,
QueenValueMg = 2538, QueenValueEg = 2682,
+ FersValueMg = 420, FersValueEg = 450,
+ AlfilValueMg = 350, AlfilValueEg = 330,
+ FersAlfilValueMg = 700, FersAlfilValueEg = 650,
+ SilverValueMg = 630, SilverValueEg = 630,
+ AiwokValueMg = 2300, AiwokValueEg = 2700,
+ BersValueMg = 2000, BersValueEg = 2000,
+ ArchbishopValueMg = 2200, ArchbishopValueEg = 2200,
+ ChancellorValueMg = 2300, ChancellorValueEg = 2600,
+ AmazonValueMg = 2700, AmazonValueEg = 2850,
+ KnibisValueMg = 1100, KnibisValueEg = 1200,
+ BiskniValueMg = 750, BiskniValueEg = 700,
+ KnirooValueMg = 1050, KnirooValueEg = 1250,
+ RookniValueMg = 800, RookniValueEg = 950,
+ ShogiPawnValueMg = 90, ShogiPawnValueEg = 100,
+ LanceValueMg = 350, LanceValueEg = 250,
+ ShogiKnightValueMg = 350, ShogiKnightValueEg = 300,
+ EuroShogiKnightValueMg = 400, EuroShogiKnightValueEg = 400,
+ GoldValueMg = 640, GoldValueEg = 640,
+ DragonHorseValueMg = 1500, DragonHorseValueEg = 1500,
+ ClobberPieceValueMg = 300, ClobberPieceValueEg = 300,
+ BreakthroughPieceValueMg = 300, BreakthroughPieceValueEg = 300,
+ ImmobilePieceValueMg = 100, ImmobilePieceValueEg = 100,
+ CannonPieceValueMg = 800, CannonPieceValueEg = 700,
+ JanggiCannonPieceValueMg = 800, JanggiCannonPieceValueEg = 600,
+ SoldierValueMg = 200, SoldierValueEg = 270,
+ HorseValueMg = 520, HorseValueEg = 800,
+ ElephantValueMg = 300, ElephantValueEg = 300,
+ JanggiElephantValueMg = 340, JanggiElephantValueEg = 350,
+ BannerValueMg = 3400, BannerValueEg = 3500,
+ WazirValueMg = 400, WazirValueEg = 350,
+ CommonerValueMg = 700, CommonerValueEg = 900,
+ CentaurValueMg = 1800, CentaurValueEg = 1900,
+ Tempo = 28,
MidgameLimit = 15258, EndgameLimit = 3915
};
enum Piece {
NO_PIECE,
- W_PAWN = 1, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
- B_PAWN = 9, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING,
- PIECE_NB = 16
+ PIECE_NB = 2 * PIECE_TYPE_NB
+};
+
+enum RiderType {
+ NO_RIDER = 0,
+ RIDER_BISHOP = 1 << 0,
+ RIDER_ROOK_H = 1 << 1,
+ RIDER_ROOK_V = 1 << 2,
+ RIDER_CANNON_H = 1 << 3,
+ RIDER_CANNON_V = 1 << 4,
+ RIDER_HORSE = 1 << 5,
+ RIDER_ELEPHANT = 1 << 6,
+ RIDER_JANGGI_ELEPHANT = 1 << 7,
+ HOPPING_RIDERS = RIDER_CANNON_H | RIDER_CANNON_V,
+ ASYMMETRICAL_RIDERS = RIDER_HORSE | RIDER_JANGGI_ELEPHANT,
};
- extern Value PieceValue[PHASE_NB][PIECE_NB];
+ constexpr Value PieceValue[PHASE_NB][PIECE_NB] = {
- { VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg, VALUE_ZERO, VALUE_ZERO,
- VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg, VALUE_ZERO, VALUE_ZERO },
- { VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg, VALUE_ZERO, VALUE_ZERO,
- VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg, VALUE_ZERO, VALUE_ZERO }
++ { VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg,
++ FersValueMg, AlfilValueMg, FersAlfilValueMg, SilverValueMg, AiwokValueMg, BersValueMg,
++ ArchbishopValueMg, ChancellorValueMg, AmazonValueMg, KnibisValueMg, BiskniValueMg, KnirooValueMg, RookniValueMg,
++ ShogiPawnValueMg, LanceValueMg, ShogiKnightValueMg, EuroShogiKnightValueMg, GoldValueMg, DragonHorseValueMg,
++ ClobberPieceValueMg, BreakthroughPieceValueMg, ImmobilePieceValueMg,
++ CannonPieceValueMg, JanggiCannonPieceValueMg, SoldierValueMg, HorseValueMg, ElephantValueMg, JanggiElephantValueMg, BannerValueMg,
++ WazirValueMg, CommonerValueMg, CentaurValueMg, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg,
++ FersValueMg, AlfilValueMg, FersAlfilValueMg, SilverValueMg, AiwokValueMg, BersValueMg,
++ ArchbishopValueMg, ChancellorValueMg, AmazonValueMg, KnibisValueMg, BiskniValueMg, KnirooValueMg, RookniValueMg,
++ ShogiPawnValueMg, LanceValueMg, ShogiKnightValueMg, EuroShogiKnightValueMg, GoldValueMg, DragonHorseValueMg,
++ ClobberPieceValueMg, BreakthroughPieceValueMg, ImmobilePieceValueMg,
++ CannonPieceValueMg, JanggiCannonPieceValueMg, SoldierValueMg, HorseValueMg, ElephantValueMg, JanggiElephantValueMg, BannerValueMg,
++ WazirValueMg, CommonerValueMg, CentaurValueMg, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO },
++ { VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg,
++ FersValueEg, AlfilValueEg, FersAlfilValueEg, SilverValueEg, AiwokValueEg, BersValueEg,
++ ArchbishopValueMg, ChancellorValueEg, AmazonValueEg, KnibisValueMg, BiskniValueMg, KnirooValueEg, RookniValueEg,
++ ShogiPawnValueEg, LanceValueEg, ShogiKnightValueEg, EuroShogiKnightValueEg, GoldValueEg, DragonHorseValueEg,
++ ClobberPieceValueEg, BreakthroughPieceValueEg, ImmobilePieceValueEg,
++ CannonPieceValueEg, JanggiCannonPieceValueEg, SoldierValueEg, HorseValueEg, ElephantValueEg, JanggiElephantValueEg, BannerValueEg,
++ WazirValueEg, CommonerValueEg, CentaurValueEg, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg,
++ FersValueEg, AlfilValueEg, FersAlfilValueEg, SilverValueEg, AiwokValueEg, BersValueEg,
++ ArchbishopValueMg, ChancellorValueEg, AmazonValueEg, KnibisValueMg, BiskniValueMg, KnirooValueEg, RookniValueEg,
++ ShogiPawnValueEg, LanceValueEg, ShogiKnightValueEg, EuroShogiKnightValueEg, GoldValueEg, DragonHorseValueEg,
++ ClobberPieceValueEg, BreakthroughPieceValueEg, ImmobilePieceValueEg,
++ CannonPieceValueEg, JanggiCannonPieceValueEg, SoldierValueEg, HorseValueEg, ElephantValueEg, JanggiElephantValueEg, BannerValueEg,
++ WazirValueEg, CommonerValueEg, CentaurValueEg, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
++ VALUE_ZERO, VALUE_ZERO, VALUE_ZERO }
+ };
+
++static_assert( PieceValue[MG][PIECE_TYPE_NB + 1] == PawnValueMg
++ && PieceValue[EG][PIECE_TYPE_NB + 1] == PawnValueEg, "PieceValue array broken");
+
typedef int Depth;
enum : int {