Currently the NORTH/WEST/SOUTH/EAST values are of type Square, but conceptually they are not squares but directions. This patch separates these values into a Direction enum and overloads addition and subtraction to allow adding a Square to a Direction (to get a new Square).
I have also slightly trimmed the possible overloadings to improve type safety. For example, it would normally not make sense to add a Color to a Color or a Piece to a Piece, or to multiply or divide them by an integer. It would also normally not make sense to add a Square to a Square.
This is a non-functional change.
ksq[WHITE] = Square((idx >> 0) & 0x3F);
ksq[BLACK] = Square((idx >> 6) & 0x3F);
us = Color ((idx >> 12) & 0x01);
ksq[WHITE] = Square((idx >> 0) & 0x3F);
ksq[BLACK] = Square((idx >> 6) & 0x3F);
us = Color ((idx >> 12) & 0x01);
- psq = make_square(File((idx >> 13) & 0x3), RANK_7 - Rank((idx >> 15) & 0x7));
+ psq = make_square(File((idx >> 13) & 0x3), Rank(RANK_7 - ((idx >> 15) & 0x7)));
// Check if two pieces are on the same square or if a king can be captured
if ( distance(ksq[WHITE], ksq[BLACK]) <= 1
// Check if two pieces are on the same square or if a king can be captured
if ( distance(ksq[WHITE], ksq[BLACK]) <= 1
Bitboard RookTable[0x19000]; // To store rook attacks
Bitboard BishopTable[0x1480]; // To store bishop attacks
Bitboard RookTable[0x19000]; // To store rook attacks
Bitboard BishopTable[0x1480]; // To store bishop attacks
- void init_magics(Bitboard table[], Magic magics[], Square deltas[]);
+ void init_magics(Bitboard table[], Magic magics[], Direction directions[]);
// bsf_index() returns the index into BSFTable[] to look up the bitscan. Uses
// Matt Taylor's folding for 32 bit case, extended to 64 bit by Kim Walisch.
// bsf_index() returns the index into BSFTable[] to look up the bitscan. Uses
// Matt Taylor's folding for 32 bit case, extended to 64 bit by Kim Walisch.
for (Square s = SQ_A1; s <= SQ_H8; ++s)
for (int i = 0; steps[pt][i]; ++i)
{
for (Square s = SQ_A1; s <= SQ_H8; ++s)
for (int i = 0; steps[pt][i]; ++i)
{
- Square to = s + Square(c == WHITE ? steps[pt][i] : -steps[pt][i]);
+ Square to = s + Direction(c == WHITE ? steps[pt][i] : -steps[pt][i]);
if (is_ok(to) && distance(s, to) < 3)
{
if (is_ok(to) && distance(s, to) < 3)
{
- Square RookDeltas[] = { NORTH, EAST, SOUTH, WEST };
- Square BishopDeltas[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
+ Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST };
+ Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
- init_magics(RookTable, RookMagics, RookDeltas);
- init_magics(BishopTable, BishopMagics, BishopDeltas);
+ init_magics(RookTable, RookMagics, RookDirections);
+ init_magics(BishopTable, BishopMagics, BishopDirections);
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
{
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
{
- Bitboard sliding_attack(Square deltas[], Square sq, Bitboard occupied) {
+ Bitboard sliding_attack(Direction directions[], Square sq, Bitboard occupied) {
Bitboard attack = 0;
for (int i = 0; i < 4; ++i)
Bitboard attack = 0;
for (int i = 0; i < 4; ++i)
- for (Square s = sq + deltas[i];
- is_ok(s) && distance(s, s - deltas[i]) == 1;
- s += deltas[i])
+ for (Square s = sq + directions[i];
+ is_ok(s) && distance(s, s - directions[i]) == 1;
+ s += directions[i])
// chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we
// use the so called "fancy" approach.
// chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we
// use the so called "fancy" approach.
- void init_magics(Bitboard table[], Magic magics[], Square deltas[]) {
+ void init_magics(Bitboard table[], Magic magics[], Direction directions[]) {
// Optimal PRNG seeds to pick the correct magics in the shortest time
int seeds[][RANK_NB] = { { 8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020 },
// Optimal PRNG seeds to pick the correct magics in the shortest time
int seeds[][RANK_NB] = { { 8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020 },
// the number of 1s of the mask. Hence we deduce the size of the shift to
// apply to the 64 or 32 bits word to get the index.
Magic& m = magics[s];
// the number of 1s of the mask. Hence we deduce the size of the shift to
// apply to the 64 or 32 bits word to get the index.
Magic& m = magics[s];
- m.mask = sliding_attack(deltas, s, 0) & ~edges;
+ m.mask = sliding_attack(directions, s, 0) & ~edges;
m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask);
// Set the offset for the attacks table of the square. We have individual
m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask);
// Set the offset for the attacks table of the square. We have individual
b = size = 0;
do {
occupancy[size] = b;
b = size = 0;
do {
occupancy[size] = b;
- reference[size] = sliding_attack(deltas, s, b);
+ reference[size] = sliding_attack(directions, s, b);
if (HasPext)
m.attacks[pext(b, m.mask)] = reference[size];
if (HasPext)
m.attacks[pext(b, m.mask)] = reference[size];
/// shift() moves a bitboard one step along direction D. Mainly for pawns
/// shift() moves a bitboard one step along direction D. Mainly for pawns
constexpr Bitboard shift(Bitboard b) {
return D == NORTH ? b << 8 : D == SOUTH ? b >> 8
: D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == SOUTH_EAST ? (b & ~FileHBB) >> 7
constexpr Bitboard shift(Bitboard b) {
return D == NORTH ? b << 8 : D == SOUTH ? b >> 8
: D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == SOUTH_EAST ? (b & ~FileHBB) >> 7
Square bsq = pos.square<BISHOP>(weakSide);
Square psq = pos.square<PAWN>(strongSide);
Rank rk = relative_rank(strongSide, psq);
Square bsq = pos.square<BISHOP>(weakSide);
Square psq = pos.square<PAWN>(strongSide);
Rank rk = relative_rank(strongSide, psq);
- Square push = pawn_push(strongSide);
+ Direction push = pawn_push(strongSide);
// If the pawn is on the 5th rank and the pawn (currently) is on
// the same color square as the bishop then there is a chance of
// If the pawn is on the 5th rank and the pawn (currently) is on
// the same color square as the bishop then there is a chance of
template<Tracing T> template<Color Us>
void Evaluation<T>::initialize() {
template<Tracing T> template<Color Us>
void Evaluation<T>::initialize() {
- const Color Them = (Us == WHITE ? BLACK : WHITE);
- const Square Up = (Us == WHITE ? NORTH : SOUTH);
- const Square Down = (Us == WHITE ? SOUTH : NORTH);
+ const Color Them = (Us == WHITE ? BLACK : WHITE);
+ const Direction Up = (Us == WHITE ? NORTH : SOUTH);
+ const Direction Down = (Us == WHITE ? SOUTH : NORTH);
const Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB: Rank7BB | Rank6BB);
// Find our pawns on the first two ranks, and those which are blocked
const Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB: Rank7BB | Rank6BB);
// Find our pawns on the first two ranks, and those which are blocked
&& pos.is_chess960()
&& (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1)))
{
&& pos.is_chess960()
&& (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1)))
{
- Square d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST);
+ Direction d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST);
if (pos.piece_on(s + d) == make_piece(Us, PAWN))
score -= !pos.empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1 * 4
: pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? TrappedBishopA1H1 * 2
if (pos.piece_on(s + d) == make_piece(Us, PAWN))
score -= !pos.empty(s + d + pawn_push(Us)) ? TrappedBishopA1H1 * 4
: pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? TrappedBishopA1H1 * 2
template<Tracing T> template<Color Us>
Score Evaluation<T>::evaluate_king() {
template<Tracing T> template<Color Us>
Score Evaluation<T>::evaluate_king() {
- const Color Them = (Us == WHITE ? BLACK : WHITE);
- const Square Up = (Us == WHITE ? NORTH : SOUTH);
- const Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB
- : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB);
+ const Color Them = (Us == WHITE ? BLACK : WHITE);
+ const Direction Up = (Us == WHITE ? NORTH : SOUTH);
+ const Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB
+ : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB);
const Square ksq = pos.square<KING>(Us);
Bitboard weak, b, b1, b2, safe, other;
const Square ksq = pos.square<KING>(Us);
Bitboard weak, b, b1, b2, safe, other;
template<Tracing T> template<Color Us>
Score Evaluation<T>::evaluate_threats() {
template<Tracing T> template<Color Us>
Score Evaluation<T>::evaluate_threats() {
- const Color Them = (Us == WHITE ? BLACK : WHITE);
- const Square Up = (Us == WHITE ? NORTH : SOUTH);
- const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
- const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
- const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
+ const Color Them = (Us == WHITE ? BLACK : WHITE);
+ const Direction Up = (Us == WHITE ? NORTH : SOUTH);
+ const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
+ const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
+ const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
Bitboard b, weak, defended, stronglyProtected, safeThreats;
Score score = SCORE_ZERO;
Bitboard b, weak, defended, stronglyProtected, safeThreats;
Score score = SCORE_ZERO;
template<Tracing T> template<Color Us>
Score Evaluation<T>::evaluate_passed_pawns() {
template<Tracing T> template<Color Us>
Score Evaluation<T>::evaluate_passed_pawns() {
- const Color Them = (Us == WHITE ? BLACK : WHITE);
- const Square Up = (Us == WHITE ? NORTH : SOUTH);
+ const Color Them = (Us == WHITE ? BLACK : WHITE);
+ const Direction Up = (Us == WHITE ? NORTH : SOUTH);
Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares;
Score score = SCORE_ZERO;
Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares;
Score score = SCORE_ZERO;
- const Square K = Chess960 ? kto > kfrom ? WEST : EAST
- : KingSide ? WEST : EAST;
+ const Direction K = Chess960 ? kto > kfrom ? WEST : EAST
+ : KingSide ? WEST : EAST;
for (Square s = kto; s != kfrom; s += K)
if (pos.attackers_to(s) & enemies)
for (Square s = kto; s != kfrom; s += K)
if (pos.attackers_to(s) & enemies)
- template<GenType Type, Square D>
+ template<GenType Type, Direction D>
ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) {
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) {
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
// Compute our parametrized parameters at compile time, named according to
// the point of view of white side.
// Compute our parametrized parameters at compile time, named according to
// the point of view of white side.
- const Color Them = (Us == WHITE ? BLACK : WHITE);
- const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
- const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
- const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
- const Square Up = (Us == WHITE ? NORTH : SOUTH);
- const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
- const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
+ const Color Them = (Us == WHITE ? BLACK : WHITE);
+ const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
+ const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
+ const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
+ const Direction Up = (Us == WHITE ? NORTH : SOUTH);
+ const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
+ const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
template<Color Us>
Score evaluate(const Position& pos, Pawns::Entry* e) {
template<Color Us>
Score evaluate(const Position& pos, Pawns::Entry* e) {
- const Color Them = (Us == WHITE ? BLACK : WHITE);
- const Square Up = (Us == WHITE ? NORTH : SOUTH);
- const Square Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
- const Square Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
+ const Color Them = (Us == WHITE ? BLACK : WHITE);
+ const Direction Up = (Us == WHITE ? NORTH : SOUTH);
+ const Direction Right = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
+ const Direction Left = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
Bitboard b, neighbours, stoppers, doubled, supported, phalanx;
Bitboard lever, leverPush;
Bitboard b, neighbours, stoppers, doubled, supported, phalanx;
Bitboard lever, leverPush;
Value safety = MaxSafetyBonus;
File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq)));
Value safety = MaxSafetyBonus;
File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq)));
- for (File f = center - File(1); f <= center + File(1); ++f)
+ for (File f = File(center - 1); f <= File(center + 1); ++f)
{
b = ourPawns & file_bb(f);
Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1;
{
b = ourPawns & file_bb(f);
Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1;
b = theirPawns & file_bb(f);
Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
b = theirPawns & file_bb(f);
Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
- int d = std::min(f, FILE_H - f);
+ int d = std::min(f, ~f);
safety -= ShelterWeakness[f == file_of(ksq)][d][rkUs]
+ StormDanger
[f == file_of(ksq) && rkThem == relative_rank(Us, ksq) + 1 ? BlockedByKing :
safety -= ShelterWeakness[f == file_of(ksq)][d][rkUs]
+ StormDanger
[f == file_of(ksq) && rkThem == relative_rank(Us, ksq) + 1 ? BlockedByKing :
while ((ss >> token) && !isspace(token))
{
if (isdigit(token))
while ((ss >> token) && !isspace(token))
{
if (isdigit(token))
- sq += Square(token - '0'); // Advance the given number of files
+ sq += (token - '0') * EAST; // Advance the given number of files
else if ((idx = PieceToChar.find(token)) != string::npos)
{
else if ((idx = PieceToChar.find(token)) != string::npos)
{
if ( (int(to) ^ int(from)) == 16
&& (attacks_from<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN)))
{
if ( (int(to) ^ int(from)) == 16
&& (attacks_from<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN)))
{
- st->epSquare = (from + to) / 2;
+ st->epSquare = to - pawn_push(us);
k ^= Zobrist::enpassant[file_of(st->epSquare)];
}
k ^= Zobrist::enpassant[file_of(st->epSquare)];
}
for (Square s = SQ_A1; s <= SQ_H8; ++s)
{
for (Square s = SQ_A1; s <= SQ_H8; ++s)
{
- File f = std::min(file_of(s), FILE_H - file_of(s));
+ File f = std::min(file_of(s), ~file_of(s));
psq[ pc][ s] = v + Bonus[pc][rank_of(s)][f];
psq[~pc][~s] = -psq[pc][s];
}
psq[ pc][ s] = v + Bonus[pc][rank_of(s)][f];
psq[~pc][~s] = -psq[pc][s];
}
static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2");
static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2");
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3,
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3,
SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8,
SQ_NONE,
SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8,
SQ_NONE,
NORTH = 8,
EAST = 1,
SOUTH = -NORTH,
NORTH = 8,
EAST = 1,
SOUTH = -NORTH,
constexpr T operator-(T d1, T d2) { return T(int(d1) - int(d2)); } \
constexpr T operator-(T d) { return T(-int(d)); } \
inline T& operator+=(T& d1, T d2) { return d1 = d1 + d2; } \
constexpr T operator-(T d1, T d2) { return T(int(d1) - int(d2)); } \
constexpr T operator-(T d) { return T(-int(d)); } \
inline T& operator+=(T& d1, T d2) { return d1 = d1 + d2; } \
-inline T& operator-=(T& d1, T d2) { return d1 = d1 - d2; } \
+inline T& operator-=(T& d1, T d2) { return d1 = d1 - d2; }
+
+#define ENABLE_INCR_OPERATORS_ON(T) \
+inline T& operator++(T& d) { return d = T(int(d) + 1); } \
+inline T& operator--(T& d) { return d = T(int(d) - 1); }
#define ENABLE_FULL_OPERATORS_ON(T) \
ENABLE_BASE_OPERATORS_ON(T) \
#define ENABLE_FULL_OPERATORS_ON(T) \
ENABLE_BASE_OPERATORS_ON(T) \
+ENABLE_INCR_OPERATORS_ON(T) \
constexpr T operator*(int i, T d) { return T(i * int(d)); } \
constexpr T operator*(T d, int i) { return T(int(d) * i); } \
constexpr T operator*(int i, T d) { return T(i * int(d)); } \
constexpr T operator*(T d, int i) { return T(int(d) * i); } \
-inline T& operator++(T& d) { return d = T(int(d) + 1); } \
-inline T& operator--(T& d) { return d = T(int(d) - 1); } \
constexpr T operator/(T d, int i) { return T(int(d) / i); } \
constexpr int operator/(T d1, T d2) { return int(d1) / int(d2); } \
inline T& operator*=(T& d, int i) { return d = T(int(d) * i); } \
inline T& operator/=(T& d, int i) { return d = T(int(d) / i); }
ENABLE_FULL_OPERATORS_ON(Value)
constexpr T operator/(T d, int i) { return T(int(d) / i); } \
constexpr int operator/(T d1, T d2) { return int(d1) / int(d2); } \
inline T& operator*=(T& d, int i) { return d = T(int(d) * i); } \
inline T& operator/=(T& d, int i) { return d = T(int(d) / i); }
ENABLE_FULL_OPERATORS_ON(Value)
-ENABLE_FULL_OPERATORS_ON(PieceType)
-ENABLE_FULL_OPERATORS_ON(Piece)
-ENABLE_FULL_OPERATORS_ON(Color)
ENABLE_FULL_OPERATORS_ON(Depth)
ENABLE_FULL_OPERATORS_ON(Depth)
-ENABLE_FULL_OPERATORS_ON(Square)
-ENABLE_FULL_OPERATORS_ON(File)
-ENABLE_FULL_OPERATORS_ON(Rank)
+ENABLE_FULL_OPERATORS_ON(Direction)
+
+ENABLE_INCR_OPERATORS_ON(PieceType)
+ENABLE_INCR_OPERATORS_ON(Piece)
+ENABLE_INCR_OPERATORS_ON(Color)
+ENABLE_INCR_OPERATORS_ON(Square)
+ENABLE_INCR_OPERATORS_ON(File)
+ENABLE_INCR_OPERATORS_ON(Rank)
ENABLE_BASE_OPERATORS_ON(Score)
#undef ENABLE_FULL_OPERATORS_ON
ENABLE_BASE_OPERATORS_ON(Score)
#undef ENABLE_FULL_OPERATORS_ON
+#undef ENABLE_INCR_OPERATORS_ON
#undef ENABLE_BASE_OPERATORS_ON
/// Additional operators to add integers to a Value
#undef ENABLE_BASE_OPERATORS_ON
/// Additional operators to add integers to a Value
inline Value& operator+=(Value& v, int i) { return v = v + i; }
inline Value& operator-=(Value& v, int i) { return v = v - i; }
inline Value& operator+=(Value& v, int i) { return v = v + i; }
inline Value& operator-=(Value& v, int i) { return v = v - i; }
+/// Additional operators to add a Direction to a Square
+inline Square operator+(Square s, Direction d) { return Square(int(s) + int(d)); }
+inline Square operator-(Square s, Direction d) { return Square(int(s) - int(d)); }
+inline Square& operator+=(Square &s, Direction d) { return s = s + d; }
+inline Square& operator-=(Square &s, Direction d) { return s = s - d; }
+
/// Only declared but not defined. We don't want to multiply two scores due to
/// a very high risk of overflow. So user should explicitly convert to integer.
Score operator*(Score s1, Score s2) = delete;
/// Only declared but not defined. We don't want to multiply two scores due to
/// a very high risk of overflow. So user should explicitly convert to integer.
Score operator*(Score s1, Score s2) = delete;
return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8
}
return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8
}
+constexpr File operator~(File f) {
+ return File(f ^ FILE_H); // Horizontal flip FILE_A -> FILE_H
+}
+
constexpr Piece operator~(Piece pc) {
return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT
}
constexpr Piece operator~(Piece pc) {
return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT
}
return ((s >> 3) ^ s) & 1;
}
return ((s >> 3) ^ s) & 1;
}
-constexpr Square pawn_push(Color c) {
+constexpr Direction pawn_push(Color c) {
return c == WHITE ? NORTH : SOUTH;
}
return c == WHITE ? NORTH : SOUTH;
}