From: syzygy1 Date: Mon, 4 Dec 2017 16:52:31 +0000 (+0100) Subject: Use a Direction enum for Square deltas X-Git-Url: https://git.sesse.net/?p=stockfish;a=commitdiff_plain;h=822695d4d3a9336dc54bfabd0996e75865358ae2 Use a Direction enum for Square deltas 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. --- diff --git a/src/bitbase.cpp b/src/bitbase.cpp index d2062104..1c4217b0 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -111,7 +111,7 @@ namespace { 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 diff --git a/src/bitboard.cpp b/src/bitboard.cpp index e3c9140d..ccde1905 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -54,7 +54,7 @@ namespace { 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. @@ -188,7 +188,7 @@ void Bitboards::init() { 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) { @@ -199,11 +199,11 @@ void Bitboards::init() { } } - 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) { @@ -225,14 +225,14 @@ void Bitboards::init() { namespace { - 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) - 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]) { attack |= s; @@ -249,7 +249,7 @@ namespace { // 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 }, @@ -269,7 +269,7 @@ namespace { // 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 @@ -281,7 +281,7 @@ namespace { 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]; diff --git a/src/bitboard.h b/src/bitboard.h index 05f65931..87628c0c 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -152,7 +152,7 @@ inline Bitboard file_bb(Square s) { /// shift() moves a bitboard one step along direction D. Mainly for pawns -template +template 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 diff --git a/src/endgame.cpp b/src/endgame.cpp index ca17f6ac..8beff888 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -524,7 +524,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { Square bsq = pos.square(weakSide); Square psq = pos.square(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 diff --git a/src/evaluate.cpp b/src/evaluate.cpp index e470e613..8df58609 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -253,9 +253,9 @@ namespace { template template void Evaluation::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 @@ -372,7 +372,7 @@ namespace { && 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 @@ -422,10 +422,10 @@ namespace { template template Score Evaluation::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(Us); Bitboard weak, b, b1, b2, safe, other; @@ -530,11 +530,11 @@ namespace { template template Score Evaluation::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; @@ -636,8 +636,8 @@ namespace { template template Score Evaluation::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; diff --git a/src/movegen.cpp b/src/movegen.cpp index 465d616c..e8e048c9 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -42,8 +42,8 @@ namespace { assert(!pos.checkers()); - 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) @@ -65,7 +65,7 @@ namespace { } - template + template ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) { if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) @@ -94,13 +94,13 @@ namespace { // 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); Bitboard emptySquares; diff --git a/src/pawns.cpp b/src/pawns.cpp index a031534d..7bb82d92 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -94,10 +94,10 @@ namespace { template 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; @@ -254,7 +254,7 @@ Value Entry::shelter_storm(const Position& pos, Square 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; @@ -262,7 +262,7 @@ Value Entry::shelter_storm(const Position& pos, Square ksq) { 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 : diff --git a/src/position.cpp b/src/position.cpp index 14490cdd..a67d04f6 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -211,10 +211,10 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th 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 (token == '/') - sq -= Square(16); + sq += 2 * SOUTH; else if ((idx = PieceToChar.find(token)) != string::npos) { @@ -787,7 +787,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { if ( (int(to) ^ int(from)) == 16 && (attacks_from(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)]; } diff --git a/src/psqt.cpp b/src/psqt.cpp index 0d16b1c3..e8d3aaf3 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -116,7 +116,7 @@ void init() { 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]; } diff --git a/src/types.h b/src/types.h index c6e03cb1..bcfb70b4 100644 --- a/src/types.h +++ b/src/types.h @@ -223,7 +223,7 @@ enum Depth : int { static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2"); -enum Square { +enum Square : int { 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, @@ -234,8 +234,10 @@ enum Square { SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8, SQ_NONE, - SQUARE_NB = 64, + SQUARE_NB = 64 +}; +enum Direction : int { NORTH = 8, EAST = 1, SOUTH = -NORTH, @@ -284,31 +286,37 @@ constexpr T operator+(T d1, T d2) { return T(int(d1) + int(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) \ +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); } \ -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) -ENABLE_FULL_OPERATORS_ON(PieceType) -ENABLE_FULL_OPERATORS_ON(Piece) -ENABLE_FULL_OPERATORS_ON(Color) 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 +#undef ENABLE_INCR_OPERATORS_ON #undef ENABLE_BASE_OPERATORS_ON /// Additional operators to add integers to a Value @@ -317,6 +325,12 @@ constexpr Value operator-(Value v, int i) { return Value(int(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; @@ -346,6 +360,10 @@ constexpr Square operator~(Square s) { 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 } @@ -408,7 +426,7 @@ inline bool opposite_colors(Square s1, Square s2) { return ((s >> 3) ^ s) & 1; } -constexpr Square pawn_push(Color c) { +constexpr Direction pawn_push(Color c) { return c == WHITE ? NORTH : SOUTH; }