LCOV - code coverage report
Current view: top level - Source - attack.cpp (source / functions) Coverage Total Hit
Test: coverage Lines: 95.3 % 128 122
Test Date: 2026-03-02 16:42:41 Functions: 91.7 % 12 11

            Line data    Source code
       1              : #include "attack.hpp"
       2              : 
       3              : #include "bitboard.hpp"
       4              : #include "logging.hpp"
       5              : #include "positionTools.hpp"
       6              : #include "timers.hpp"
       7              : 
       8              : #ifndef WITH_MAGIC
       9              : namespace {
      10              : array1d<int,512> _ranks = {0};
      11              : }
      12              : #endif
      13              : 
      14              : namespace BBTools {
      15              : 
      16              : array1d<Mask,NbSquare> mask;
      17              : 
      18              : // This initialisation function is taken from Dumb chess engine by Richard Delorme
      19           22 : void initMask() {
      20           22 :    Logging::LogIt(Logging::logInfo) << "Init mask";
      21           22 :    Logging::LogIt(Logging::logInfo) << "Size of masks : " << sizeof(mask) / 1024 << "Kb";
      22           22 :    array2d<Square,NbSquare,NbSquare> d = {{0}};
      23         1430 :    for (Square x = 0; x < NbSquare; ++x) {
      24         1408 :       mask[x].bbsquare = SquareToBitboard(x);
      25         5632 :       for (Square i = -1; i <= 1; ++i) {
      26        16896 :          for (Square j = -1; j <= 1; ++j) {
      27        12672 :             if (i == 0 && j == 0) continue;
      28              : #if !defined(WITH_SMALL_MEMORY)
      29        43296 :             for (Square r = SQRANK(x) + i, f = SQFILE(x) + j; 0 <= r && r < 8 && 0 <= f && f < 8; r += i, f += j) {
      30        32032 :                const int y = 8 * r + f;
      31        32032 :                d[x][y]     = 8 * i + j;
      32        88704 :                for (Square z = x + d[x][y]; z != y; z += d[x][y]) mask[x].between[y] |= SquareToBitboard(z);
      33              :             }
      34              : #endif
      35              :             const auto r = SQRANK(x);
      36              :             const auto f = SQFILE(x);
      37        11264 :             if (0 <= r + i && r + i < 8 && 0 <= f + j && f + j < 8) mask[x].kingZone |= SquareToBitboard((SQRANK(x) + i) * 8 + SQFILE(x) + j);
      38              :          }
      39              :       }
      40              : 
      41         4488 :       for (Square y = x - 9; y >= 0 && d[x][y] == -9; y -= 9) mask[x].diagonal |= SquareToBitboard(y);
      42         4488 :       for (Square y = x + 9; y < NbSquare && d[x][y] == 9; y += 9) mask[x].diagonal |= SquareToBitboard(y);
      43              : 
      44         4488 :       for (Square y = x - 7; y >= 0 && d[x][y] == -7; y -= 7) mask[x].antidiagonal |= SquareToBitboard(y);
      45         4488 :       for (Square y = x + 7; y < NbSquare && d[x][y] == 7; y += 7) mask[x].antidiagonal |= SquareToBitboard(y);
      46              : 
      47         6336 :       for (Square y = x - 8; y >= 0; y -= 8) mask[x].file |= SquareToBitboard(y);
      48         6336 :       for (Square y = x + 8; y < NbSquare; y += 8) mask[x].file |= SquareToBitboard(y);
      49              : 
      50              :       auto f = SQFILE(x);
      51              :       auto r = SQRANK(x);
      52         4224 :       for (Square i = -1, c = 1, dp = 6; i <= 1; i += 2, c = 0, dp = 1) {
      53         8448 :          for (Square j = -1; j <= 1; j += 2)
      54         5632 :             if (0 <= r + i && r + i < 8 && 0 <= f + j && f + j < 8) { mask[x].pawnAttack[c] |= SquareToBitboard((r + i) * 8 + (f + j)); }
      55         2816 :          if (0 <= r + i && r + i < 8) {
      56         2464 :             mask[x].push[c] = SquareToBitboard((r + i) * 8 + f);
      57         2464 :             if (r == dp) mask[x].dpush[c] = SquareToBitboard((r + 2 * i) * 8 + f); // double push
      58              :          }
      59              :       }
      60              : #if !defined(WITH_SMALL_MEMORY)
      61         1408 :       if (r == 3 || r == 4) {
      62          352 :          if (f > 0) mask[x].enpassant |= SquareToBitboard(x - 1);
      63          352 :          if (f < 7) mask[x].enpassant |= SquareToBitboard(x + 1);
      64              :       }
      65              : #endif
      66              : 
      67        12672 :       for (Square i = -2; i <= 2; i = (i == -1 ? 1 : i + 1)) {
      68        33792 :          for (Square j = -2; j <= 2; ++j) {
      69        28160 :             if (i == j || i == -j || j == 0) continue;
      70        11264 :             if (0 <= r + i && r + i < 8 && 0 <= f + j && f + j < 8) { mask[x].knight |= SquareToBitboard(8 * (r + i) + (f + j)); }
      71              :          }
      72              :       }
      73              : 
      74         5632 :       for (Square i = -1; i <= 1; ++i) {
      75        16896 :          for (Square j = -1; j <= 1; ++j) {
      76        12672 :             if (i == 0 && j == 0) continue;
      77        11264 :             if (0 <= r + i && r + i < 8 && 0 <= f + j && f + j < 8) { mask[x].king |= SquareToBitboard(8 * (r + i) + (f + j)); }
      78              :          }
      79              :       }
      80              : 
      81              :       BitBoard wspan = SquareToBitboardTable(x);
      82         1408 :       wspan |= wspan << 8;
      83         1408 :       wspan |= wspan << 16;
      84         1408 :       wspan |= wspan << 32;
      85              :       wspan = _shiftNorth(wspan);
      86              :       BitBoard bspan = SquareToBitboardTable(x);
      87         1408 :       bspan |= bspan >> 8;
      88         1408 :       bspan |= bspan >> 16;
      89         1408 :       bspan |= bspan >> 32;
      90              :       bspan = _shiftSouth(bspan);
      91              : 
      92              : #if !defined(WITH_SMALL_MEMORY)
      93              :       ///@todo try to use them in bitboardTools to see if its faster than on the fly computations ...
      94         1408 :       mask[x].frontSpan[Co_White] = wspan;
      95         1408 :       mask[x].frontSpan[Co_Black] = bspan;
      96              : 
      97         1408 :       mask[x].rearSpan[Co_Black] = wspan;
      98         1408 :       mask[x].rearSpan[Co_White] = bspan;
      99              : 
     100              :       mask[x].passerSpan[Co_White] = wspan;
     101         1408 :       mask[x].passerSpan[Co_White] |= _shiftWest(wspan);
     102         1408 :       mask[x].passerSpan[Co_White] |= _shiftEast(wspan);
     103              :       mask[x].passerSpan[Co_Black] = bspan;
     104         1408 :       mask[x].passerSpan[Co_Black] |= _shiftWest(bspan);
     105         1408 :       mask[x].passerSpan[Co_Black] |= _shiftEast(bspan);
     106              : 
     107              :       mask[x].attackFrontSpan[Co_White] = _shiftWest(wspan);
     108         1408 :       mask[x].attackFrontSpan[Co_White] |= _shiftEast(wspan);
     109              :       mask[x].attackFrontSpan[Co_Black] = _shiftWest(bspan);
     110         1408 :       mask[x].attackFrontSpan[Co_Black] |= _shiftEast(bspan);
     111              : #endif      
     112              :    }
     113              : 
     114              : #ifndef WITH_MAGIC
     115              :    for (Square o = 0; o < 64; ++o) {
     116              :       for (Square k = 0; k < 8; ++k) {
     117              :          int y = 0;
     118              :          for (Square x = k - 1; x >= 0; --x) {
     119              :             const BitBoard b = SquareToBitboard(x);
     120              :             y |= b;
     121              :             if (((o << 1) & b) == b) break;
     122              :          }
     123              :          for (Square x = k + 1; x < 8; ++x) {
     124              :             const BitBoard b = SquareToBitboard(x);
     125              :             y |= b;
     126              :             if (((o << 1) & b) == b) break;
     127              :          }
     128              :          _ranks[o * 8 + k] = y;
     129              :       }
     130              :    }
     131              : #endif
     132           22 : }
     133              : 
     134              : #ifndef WITH_MAGIC // then use HQBB
     135              : 
     136              : BitBoard attack(const BitBoard occupancy, const Square s, const BitBoard m) {
     137              :    assert(isValidSquare(s));
     138              :    START_TIMER
     139              :    BitBoard forward = occupancy & m;
     140              :    BitBoard reverse = swapbits(forward);
     141              :    forward -= SquareToBitboard(s);
     142              :    reverse -= SquareToBitboard(s ^ 63);
     143              :    forward ^= swapbits(reverse);
     144              :    forward &= m;
     145              :    STOP_AND_SUM_TIMER(Attack)
     146              :    return forward;
     147              : }
     148              : 
     149              : BitBoard rankAttack(const BitBoard occupancy, const Square s) {
     150              :    assert(isValidSquare(s));
     151              :    const int f = SQFILE(s);
     152              :    const int r = s & 56;
     153              :    return static_cast<BitBoard>(_ranks[((occupancy >> r) & 126) * 4 + f]) << r;
     154              : }
     155              : 
     156              : BitBoard fileAttack(const BitBoard occupancy, const Square s) {
     157              :    assert(isValidSquare(s));
     158              :    return attack(occupancy, s, mask[s].file);
     159              : }
     160              : 
     161              : BitBoard diagonalAttack(const BitBoard occupancy, const Square s) {
     162              :    assert(isValidSquare(s));
     163              :    return attack(occupancy, s, mask[s].diagonal);
     164              : }
     165              : 
     166              : BitBoard antidiagonalAttack(const BitBoard occupancy, const Square s) {
     167              :    assert(isValidSquare(s));
     168              :    return attack(occupancy, s, mask[s].antidiagonal);
     169              : }
     170              : 
     171              : #else // MAGIC
     172              : 
     173              : namespace MagicBB {
     174              : 
     175              : array1d<SMagic,NbSquare> bishopMagic;
     176              : array1d<SMagic,NbSquare> rookMagic;
     177              : 
     178              : array2d<BitBoard,NbSquare,1 << BISHOP_INDEX_BITS> bishopAttacks;
     179              : array2d<BitBoard,NbSquare,1 << ROOK_INDEX_BITS> rookAttacks;
     180              : 
     181              : constexpr array1d<BitBoard,NbSquare> bishopMagics = {
     182              :     0x1002004102008200, 0x1002004102008200, 0x4310002248214800, 0x402010c110014208, 0xa000a06240114001, 0xa000a06240114001, 0x402010c110014208, 0xa000a06240114001,
     183              :     0x1002004102008200, 0x1002004102008200, 0x1002004102008200, 0x1002004102008200, 0x100c009840001000, 0x4310002248214800, 0xa000a06240114001, 0x4310002248214800,
     184              :     0x4310002248214800, 0x822143005020a148, 0x0001901c00420040, 0x0880504024308060, 0x0100201004200002, 0xa000a06240114001, 0x822143005020a148, 0x1002004102008200,
     185              :     0x1002004102008200, 0x1002004102008200, 0x1002004102008200, 0x2008080100820102, 0x1481010004104010, 0x0002052000100024, 0xc880221002060081, 0xc880221002060081,
     186              :     0x4310002248214800, 0xc880221002060081, 0x0001901c00420040, 0x8400208020080201, 0x000e008400060020, 0x00449210e3902028, 0x402010c110014208, 0xc880221002060081,
     187              :     0x100c009840001000, 0xc880221002060081, 0x1000820800c00060, 0x2803101084008800, 0x2200608200100080, 0x0040900130840090, 0x0024010008800a00, 0x0400110410804810,
     188              :     0x402010c110014208, 0xa000a06240114001, 0xa000a06240114001, 0x1002004102008200, 0x1002004102008200, 0x1002004102008200, 0x1002004102008200, 0x1002004102008200,
     189              :     0xa000a06240114001, 0x4310002248214800, 0x1002004102008200, 0x1002004102008200, 0x1002004102008200, 0x1002004102008200, 0x1002004102008200, 0x1002004102008200
     190              : };
     191              : 
     192              : constexpr array1d<BitBoard,NbSquare> rookMagics = {
     193              :     0x8200108041020020, 0x8200108041020020, 0xc880221002060081, 0x0009100804021000, 0x0500010004107800, 0x0024010008800a00, 0x0400110410804810, 0x8300038100004222,
     194              :     0x004a800182c00020, 0x0009100804021000, 0x3002200010c40021, 0x0020100104000208, 0x01021001a0080020, 0x0884020010082100, 0x1000820800c00060, 0x8020480110020020,
     195              :     0x0002052000100024, 0x0200190040088100, 0x0030802001a00800, 0x8010002004000202, 0x0040010100080010, 0x2200608200100080, 0x0001901c00420040, 0x0001400a24008010,
     196              :     0x1400a22008001042, 0x8200108041020020, 0x2004500023002400, 0x8105100028001048, 0x8010024d00014802, 0x8000820028030004, 0x402010c110014208, 0x8300038100004222,
     197              :     0x0001804002800124, 0x0084022014041400, 0x0030802001a00800, 0x0110a01001080008, 0x0b10080850081100, 0x000010040049020c, 0x0024010008800a00, 0x014c800040100426,
     198              :     0x1100400010208000, 0x0009100804021000, 0x0010024871202002, 0x8014001028c80801, 0x1201082010a00200, 0x0002008004102009, 0x8300038100004222, 0x0000401001a00408,
     199              :     0x4520920010210200, 0x0400110410804810, 0x8105100028001048, 0x8105100028001048, 0x0802801009083002, 0x8200108041020020, 0x8200108041020020, 0x4000a12400848110,
     200              :     0x2000804026001102, 0x2000804026001102, 0x800040a010040901, 0x80001802002c0422, 0x0010b018200c0122, 0x200204802a080401, 0x8880604201100844, 0x80000cc281092402
     201              : };
     202              : 
     203     25952256 : BitBoard computeAttacks(const Square index, const BitBoard occ, const Square delta) {
     204              :    BitBoard attacks = emptyBitBoard;
     205              :    BitBoard blocked = emptyBitBoard;
     206    113000448 :    for (Square shift = index + delta; ISNEIGHBOUR(shift, shift - delta); shift += delta) {
     207    125118400 :       if (!blocked) attacks |= SquareToBitboard(shift);
     208     87048192 :       blocked |= ((1ULL << shift) & occ);
     209              :    }
     210     25952256 :    return attacks;
     211              : }
     212              : 
     213      6488064 : BitBoard occupiedFromIndex(const int j, BitBoard mask) {
     214      6488064 :    BitBoard occ = emptyBitBoard;
     215      6488064 :    Square i = 0;
     216     71143424 :    BB::applyOn(mask, [&](const Square & k){
     217     64655360 :       if (j & SquareToBitboard(i)) occ |= (1ULL << k);
     218     64655360 :       ++i;
     219     64655360 :    });
     220      6488064 :    return occ;
     221              : }
     222              : 
     223           22 : void initMagic() {
     224           22 :    Logging::LogIt(Logging::logInfo) << "Init magic";
     225         1430 :    for (Square from = 0; from < 64; from++) {
     226         1408 :       bishopMagic[from].mask = emptyBitBoard;
     227         1408 :       rookMagic[from].mask   = emptyBitBoard;
     228        91520 :       for (Square j = 0; j < 64; j++) {
     229        90112 :          if (from == j) continue;
     230        96096 :          if (SQRANK(from) == SQRANK(j) && !ISOUTERFILE(j)) rookMagic[from].mask |= SquareToBitboard(j);
     231        96096 :          if (SQFILE(from) == SQFILE(j) && !PROMOTION_RANK(j)) rookMagic[from].mask |= SquareToBitboard(j);
     232        88704 :          if (abs(SQRANK(from) - SQRANK(j)) == abs(SQFILE(from) - SQFILE(j)) && !ISOUTERFILE(j) && !PROMOTION_RANK(j))
     233         8008 :             bishopMagic[from].mask |= SquareToBitboard(j);
     234              :       }
     235         1408 :       bishopMagic[from].magic = bishopMagics[from];
     236       722304 :       for (int j = 0; j < (1 << BISHOP_INDEX_BITS); j++) {
     237       720896 :          const BitBoard occ = occupiedFromIndex(j, bishopMagic[from].mask);
     238       720896 :          bishopAttacks[from][MAGICBISHOPINDEX(occ, from)] =
     239       720896 :              (computeAttacks(from, occ, -7) | computeAttacks(from, occ, 7) | computeAttacks(from, occ, -9) | computeAttacks(from, occ, 9));
     240              :       }
     241         1408 :       rookMagic[from].magic = rookMagics[from];
     242      5768576 :       for (int j = 0; j < (1 << ROOK_INDEX_BITS); j++) {
     243      5767168 :          const BitBoard occ = occupiedFromIndex(j, rookMagic[from].mask);
     244      5767168 :          rookAttacks[from][MAGICROOKINDEX(occ, from)] =
     245      5767168 :              (computeAttacks(from, occ, -1) | computeAttacks(from, occ, 1) | computeAttacks(from, occ, -8) | computeAttacks(from, occ, 8));
     246              :       }
     247              :    }
     248           22 : }
     249              : 
     250              : } // namespace MagicBB
     251              : 
     252              : #endif // MAGIC
     253              : 
     254    199268068 : bool isAttackedBB(const Position &p, const Square s, const Color c) { ///@todo try to optimize order better ?
     255    199268068 :    assert(isValidSquare(s));
     256              :    const BitBoard occupancy = p.occupancy();
     257    199268068 :    if (c == Co_White)
     258     83525669 :       return attack<P_wb>(s, p.blackBishop() | p.blackQueen(), occupancy) ||
     259     82084711 :              attack<P_wr>(s, p.blackRook() | p.blackQueen(), occupancy) ||
     260     26719627 :              attack<P_wp>(s, p.blackPawn(), occupancy, Co_White) ||
     261     76559252 :              attack<P_wn>(s, p.blackKnight()) ||
     262              :              attack<P_wk>(s, p.blackKing());
     263              :    else
     264    312672562 :       return attack<P_wb>(s, p.whiteBishop() | p.whiteQueen(), occupancy) ||
     265    311159365 :              attack<P_wr>(s, p.whiteRook() | p.whiteQueen(), occupancy) ||
     266    129728246 :              attack<P_wp>(s, p.whitePawn(), occupancy, Co_Black) ||
     267    291340606 :              attack<P_wn>(s, p.whiteKnight()) ||
     268              :              attack<P_wk>(s, p.whiteKing());
     269              : }
     270              : 
     271            1 : BitBoard allAttackedBB(const Position &p, const Square s, const Color c) {
     272            1 :    assert(isValidSquare(s));
     273              :    const BitBoard occupancy = p.occupancy();
     274            1 :    if (c == Co_White)
     275            2 :       return attack<P_wb>(s, p.blackBishop() | p.blackQueen(), occupancy) |
     276            2 :              attack<P_wr>(s, p.blackRook() | p.blackQueen(), occupancy) |
     277            1 :              attack<P_wn>(s, p.blackKnight()) |
     278              :              attack<P_wp>(s, p.blackPawn(), occupancy, Co_White) |
     279            1 :              attack<P_wk>(s, p.blackKing());
     280              :    else
     281            0 :       return attack<P_wb>(s, p.whiteBishop() | p.whiteQueen(), occupancy) |
     282            0 :              attack<P_wr>(s, p.whiteRook() | p.whiteQueen(), occupancy) |
     283            0 :              attack<P_wn>(s, p.whiteKnight()) |
     284              :              attack<P_wp>(s, p.whitePawn(), occupancy, Co_Black) |
     285            0 :              attack<P_wk>(s, p.whiteKing());
     286              : }
     287              : 
     288      5790404 : BitBoard allAttackedBB(const Position &p, const Square s) {
     289      5790404 :    assert(isValidSquare(s));
     290              :    const BitBoard occupancy = p.occupancy();
     291     11580808 :    return attack<P_wb>(s, p.allBishop() | p.allQueen(), occupancy) |
     292     11580808 :           attack<P_wr>(s, p.allRook() | p.allQueen(), occupancy) |
     293      5790404 :           attack<P_wn>(s, p.allKnight()) |
     294      5790404 :           attack<P_wp>(s, p.blackPawn(), occupancy, Co_White) |
     295              :           attack<P_wp>(s, p.whitePawn(), occupancy, Co_Black) |
     296      5790404 :           attack<P_wk>(s, p.allKing());
     297              : }
     298              : 
     299     26925812 : BitBoard between(const Square sq1, const Square sq2){
     300              : #if !defined(WITH_SMALL_MEMORY)
     301     26925812 :    return mask[sq1].between[sq2];
     302              : #else
     303              :    constexpr BitBoard m1   {static_cast<BitBoard>(-1)};
     304              :    constexpr BitBoard a2a7 {0x0001010101010100};
     305              :    constexpr BitBoard b2g7 {0x0040201008040200};
     306              :    constexpr BitBoard h1b7 {0x0002040810204080};
     307              :    const BitBoard btwn = (m1 << sq1) ^ (m1 << sq2);
     308              :    const BitBoard file = (sq2 & 7) - (sq1   & 7);
     309              :    const BitBoard rank = ((sq2 | 7) -  sq1) >> 3 ;
     310              :    BitBoard line  = ((file  &  7) - 1) & a2a7; /* a2a7 if same file */
     311              :    line += 2 * (((rank  &  7) - 1) >> 58); /* b1g1 if same rank */
     312              :    line += (((rank - file) & 15) - 1) & b2g7; /* b2g7 if same diagonal */
     313              :    line += (((rank + file) & 15) - 1) & h1b7; /* h1b7 if same antidiag */
     314              :    line *= btwn & -btwn; /* mul acts like shift by smaller square */
     315              :    return line & btwn;   /* return the bits on that line in-between */
     316              : #endif
     317              : }
     318              : 
     319              : } // namespace BBTools
     320              : 
     321            0 : bool isAttacked(const Position &p, const Square s){
     322              :    //assert(isValidSquare(s)); ///@todo ?
     323              :    START_TIMER
     324    199268068 :    const bool b = isValidSquare(s) && BBTools::isAttackedBB(p, s, p.c);
     325              :    STOP_AND_SUM_TIMER(IsAttacked);
     326            0 :    return b;
     327              : }
     328              : 
     329    198803298 : bool isPosInCheck(const Position& p){
     330              :    // handles chess variants
     331              :    ///@todo some chess variant will always return false here, there is no such things as check
     332    198803298 :    return isAttacked(p, kingSquare(p));
     333              : }
     334              : 
     335       162332 : bool isAttacked(const Position &p, BitBoard bb) { // copy ///@todo should be done without iterating over Square !
     336       605060 :    while (bb)
     337       464770 :       if (isAttacked(p, BB::popBit(bb))) return true;
     338              :    return false;
     339              : }
        

Generated by: LCOV version 2.0-1