Subversion Repositories Games.Chess Giants

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.     Texel - A UCI chess engine.
  3.     Copyright (C) 2012-2014  Peter Ă–sterlund, peterosterlund2@gmail.com
  4.  
  5.     This program is free software: you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation, either version 3 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17. */
  18.  
  19. /*
  20.  * moveGen.cpp
  21.  *
  22.  *  Created on: Feb 25, 2012
  23.  *      Author: petero
  24.  */
  25.  
  26. #include "moveGen.hpp"
  27.  
  28. void
  29. MoveList::filter(const std::vector<Move>& searchMoves)
  30. {
  31.     int used = 0;
  32.     for (int i = 0;i < size; i++)
  33.         if (std::find(searchMoves.begin(), searchMoves.end(), (*this)[i]) != searchMoves.end())
  34.             (*this)[used++] = (*this)[i];
  35.     size = used;
  36. }
  37.  
  38. template void MoveGen::pseudoLegalMoves<true>(const Position& pos, MoveList& moveList);
  39. template void MoveGen::pseudoLegalMoves<false>(const Position& pos, MoveList& moveList);
  40.  
  41. template <bool wtm>
  42. void
  43. MoveGen::pseudoLegalMoves(const Position& pos, MoveList& moveList) {
  44.     using MyColor = ColorTraits<wtm>;
  45.     const U64 occupied = pos.occupiedBB();
  46.  
  47.     // Queen moves
  48.     U64 squares = pos.pieceTypeBB(MyColor::QUEEN);
  49.     while (squares != 0) {
  50.         int sq = BitBoard::extractSquare(squares);
  51.         U64 m = (BitBoard::rookAttacks(sq, occupied) | BitBoard::bishopAttacks(sq, occupied)) & ~pos.colorBB(wtm);
  52.         addMovesByMask(moveList, sq, m);
  53.     }
  54.  
  55.     // Rook moves
  56.     squares = pos.pieceTypeBB(MyColor::ROOK);
  57.     while (squares != 0) {
  58.         int sq = BitBoard::extractSquare(squares);
  59.         U64 m = BitBoard::rookAttacks(sq, occupied) & ~pos.colorBB(wtm);
  60.         addMovesByMask(moveList, sq, m);
  61.     }
  62.  
  63.     // Bishop moves
  64.     squares = pos.pieceTypeBB(MyColor::BISHOP);
  65.     while (squares != 0) {
  66.         int sq = BitBoard::extractSquare(squares);
  67.         U64 m = BitBoard::bishopAttacks(sq, occupied) & ~pos.colorBB(wtm);
  68.         addMovesByMask(moveList, sq, m);
  69.     }
  70.  
  71.     // King moves
  72.     {
  73.         int sq = pos.getKingSq(wtm);
  74.         U64 m = BitBoard::kingAttacks[sq] & ~pos.colorBB(wtm);
  75.         addMovesByMask(moveList, sq, m);
  76.         const int k0 = wtm ? E1 : E8;
  77.         if (sq == k0) {
  78.             const U64 OO_SQ = wtm ? BitBoard::sqMask(F1,G1) : BitBoard::sqMask(F8,G8);
  79.             const U64 OOO_SQ = wtm ? BitBoard::sqMask(B1,C1,D1) : BitBoard::sqMask(B8,C8,D8);
  80.             const int hCastle = wtm ? Position::H1_CASTLE : Position::H8_CASTLE;
  81.             const int aCastle = wtm ? Position::A1_CASTLE : Position::A8_CASTLE;
  82.             if (((pos.getCastleMask() & (1 << hCastle)) != 0) &&
  83.                 ((OO_SQ & occupied) == 0) &&
  84.                 (pos.getPiece(k0 + 3) == MyColor::ROOK) &&
  85.                 !sqAttacked(pos, k0) &&
  86.                 !sqAttacked(pos, k0 + 1)) {
  87.                 moveList.addMove(k0, k0 + 2, Piece::EMPTY);
  88.             }
  89.             if (((pos.getCastleMask() & (1 << aCastle)) != 0) &&
  90.                 ((OOO_SQ & occupied) == 0) &&
  91.                 (pos.getPiece(k0 - 4) == MyColor::ROOK) &&
  92.                 !sqAttacked(pos, k0) &&
  93.                 !sqAttacked(pos, k0 - 1)) {
  94.                 moveList.addMove(k0, k0 - 2, Piece::EMPTY);
  95.             }
  96.         }
  97.     }
  98.  
  99.     // Knight moves
  100.     U64 knights = pos.pieceTypeBB(MyColor::KNIGHT);
  101.     while (knights != 0) {
  102.         int sq = BitBoard::extractSquare(knights);
  103.         U64 m = BitBoard::knightAttacks[sq] & ~pos.colorBB(wtm);
  104.         addMovesByMask(moveList, sq, m);
  105.     }
  106.  
  107.     // Pawn moves
  108.     const U64 pawns = pos.pieceTypeBB(MyColor::PAWN);
  109.     const int epSquare = pos.getEpSquare();
  110.     const U64 epMask = (epSquare >= 0) ? (1ULL << epSquare) : 0ULL;
  111.     if (wtm) {
  112.         U64 m = (pawns << 8) & ~occupied;
  113.         addPawnMovesByMask<wtm>(moveList, m, -8, true);
  114.         m = ((m & BitBoard::maskRow3) << 8) & ~occupied;
  115.         addPawnDoubleMovesByMask(moveList, m, -16);
  116.  
  117.         m = (pawns << 7) & BitBoard::maskAToGFiles & (pos.colorBB(!wtm) | epMask);
  118.         addPawnMovesByMask<wtm>(moveList, m, -7, true);
  119.  
  120.         m = (pawns << 9) & BitBoard::maskBToHFiles & (pos.colorBB(!wtm) | epMask);
  121.         addPawnMovesByMask<wtm>(moveList, m, -9, true);
  122.     } else {
  123.         U64 m = (pawns >> 8) & ~occupied;
  124.         addPawnMovesByMask<wtm>(moveList, m, 8, true);
  125.         m = ((m & BitBoard::maskRow6) >> 8) & ~occupied;
  126.         addPawnDoubleMovesByMask(moveList, m, 16);
  127.  
  128.         m = (pawns >> 9) & BitBoard::maskAToGFiles & (pos.colorBB(!wtm) | epMask);
  129.         addPawnMovesByMask<wtm>(moveList, m, 9, true);
  130.  
  131.         m = (pawns >> 7) & BitBoard::maskBToHFiles & (pos.colorBB(!wtm) | epMask);
  132.         addPawnMovesByMask<wtm>(moveList, m, 7, true);
  133.     }
  134. }
  135.  
  136. template void MoveGen::checkEvasions<true>(const Position& pos, MoveList& moveList);
  137. template void MoveGen::checkEvasions<false>(const Position& pos, MoveList& moveList);
  138.  
  139. template <bool wtm>
  140. void
  141. MoveGen::checkEvasions(const Position& pos, MoveList& moveList) {
  142.     using MyColor = ColorTraits<wtm>;
  143.     using OtherColor = ColorTraits<!wtm>;
  144.     const U64 occupied = pos.occupiedBB();
  145.  
  146.     const int kingSq = pos.getKingSq(wtm);
  147.     U64 kingThreats = pos.pieceTypeBB(OtherColor::KNIGHT) & BitBoard::knightAttacks[kingSq];
  148.     U64 rookPieces = pos.pieceTypeBB(OtherColor::ROOK, OtherColor::QUEEN);
  149.     if (rookPieces != 0)
  150.         kingThreats |= rookPieces & BitBoard::rookAttacks(kingSq, occupied);
  151.     U64 bishPieces = pos.pieceTypeBB(OtherColor::BISHOP, OtherColor::QUEEN);
  152.     if (bishPieces != 0)
  153.         kingThreats |= bishPieces & BitBoard::bishopAttacks(kingSq, occupied);
  154.     const U64 myPawnAttacks = wtm ? BitBoard::wPawnAttacks[kingSq] : BitBoard::bPawnAttacks[kingSq];
  155.     kingThreats |= pos.pieceTypeBB(OtherColor::PAWN) & myPawnAttacks;
  156.     U64 validTargets = 0;
  157.     if ((kingThreats != 0) && ((kingThreats & (kingThreats-1)) == 0)) { // Exactly one attacking piece
  158.         int threatSq = BitBoard::numberOfTrailingZeros(kingThreats);
  159.         validTargets = kingThreats | BitBoard::squaresBetween[kingSq][threatSq];
  160.     }
  161.     validTargets |= pos.pieceTypeBB(OtherColor::KING);
  162.     // Queen moves
  163.     U64 squares = pos.pieceTypeBB(MyColor::QUEEN);
  164.     while (squares != 0) {
  165.         int sq = BitBoard::extractSquare(squares);
  166.         U64 m = (BitBoard::rookAttacks(sq, occupied) | BitBoard::bishopAttacks(sq, occupied)) &
  167.                     ~pos.colorBB(wtm) & validTargets;
  168.         addMovesByMask(moveList, sq, m);
  169.     }
  170.  
  171.     // Rook moves
  172.     squares = pos.pieceTypeBB(MyColor::ROOK);
  173.     while (squares != 0) {
  174.         int sq = BitBoard::extractSquare(squares);
  175.         U64 m = BitBoard::rookAttacks(sq, occupied) & ~pos.colorBB(wtm) & validTargets;
  176.         addMovesByMask(moveList, sq, m);
  177.     }
  178.  
  179.     // Bishop moves
  180.     squares = pos.pieceTypeBB(MyColor::BISHOP);
  181.     while (squares != 0) {
  182.         int sq = BitBoard::extractSquare(squares);
  183.         U64 m = BitBoard::bishopAttacks(sq, occupied) & ~pos.colorBB(wtm) & validTargets;
  184.         addMovesByMask(moveList, sq, m);
  185.     }
  186.  
  187.     // King moves
  188.     {
  189.         int sq = pos.getKingSq(wtm);
  190.         U64 m = BitBoard::kingAttacks[sq] & ~pos.colorBB(wtm);
  191.         addMovesByMask(moveList, sq, m);
  192.     }
  193.  
  194.     // Knight moves
  195.     U64 knights = pos.pieceTypeBB(MyColor::KNIGHT);
  196.     while (knights != 0) {
  197.         int sq = BitBoard::extractSquare(knights);
  198.         U64 m = BitBoard::knightAttacks[sq] & ~pos.colorBB(wtm) & validTargets;
  199.         addMovesByMask(moveList, sq, m);
  200.     }
  201.  
  202.     // Pawn moves
  203.     const U64 pawns = pos.pieceTypeBB(MyColor::PAWN);
  204.     const int epSquare = pos.getEpSquare();
  205.     const U64 epMask = (epSquare >= 0) ? (1ULL << epSquare) : 0ULL;
  206.     if (wtm) {
  207.         U64 m = (pawns << 8) & ~occupied;
  208.         addPawnMovesByMask<wtm>(moveList, m & validTargets, -8, true);
  209.         m = ((m & BitBoard::maskRow3) << 8) & ~occupied;
  210.         addPawnDoubleMovesByMask(moveList, m & validTargets, -16);
  211.  
  212.         m = (pawns << 7) & BitBoard::maskAToGFiles & ((pos.colorBB(!wtm) & validTargets) | epMask);
  213.         addPawnMovesByMask<wtm>(moveList, m, -7, true);
  214.  
  215.         m = (pawns << 9) & BitBoard::maskBToHFiles & ((pos.colorBB(!wtm) & validTargets) | epMask);
  216.         addPawnMovesByMask<wtm>(moveList, m, -9, true);
  217.     } else {
  218.         U64 m = (pawns >> 8) & ~occupied;
  219.         addPawnMovesByMask<wtm>(moveList, m & validTargets, 8, true);
  220.         m = ((m & BitBoard::maskRow6) >> 8) & ~occupied;
  221.         addPawnDoubleMovesByMask(moveList, m & validTargets, 16);
  222.  
  223.         m = (pawns >> 9) & BitBoard::maskAToGFiles & ((pos.colorBB(!wtm) & validTargets) | epMask);
  224.         addPawnMovesByMask<wtm>(moveList, m, 9, true);
  225.  
  226.         m = (pawns >> 7) & BitBoard::maskBToHFiles & ((pos.colorBB(!wtm) & validTargets) | epMask);
  227.         addPawnMovesByMask<wtm>(moveList, m, 7, true);
  228.     }
  229.  
  230. #ifdef MOVELIST_DEBUG
  231.     {
  232.         // Extra check that all valid evasions were generated
  233.         MoveList allMoves;
  234.         pseudoLegalMoves(pos, allMoves);
  235.         Position tmpPos(pos);
  236.         removeIllegal(tmpPos, allMoves);
  237.         std::set<std::string> evMoves;
  238.         for (int i = 0; i < moveList.size; i++)
  239.             evMoves.insert(TextIO::moveToUCIString(moveList.m[i]));
  240.         for (int i = 0; i < allMoves.size; i++)
  241.             assert(evMoves.find(TextIO::moveToUCIString(allMoves.m[i])) != evMoves.end());
  242.     }
  243. #endif
  244. }
  245.  
  246. template void MoveGen::pseudoLegalCapturesAndChecks<true>(const Position& pos, MoveList& moveList);
  247. template void MoveGen::pseudoLegalCapturesAndChecks<false>(const Position& pos, MoveList& moveList);
  248.  
  249. template <bool wtm>
  250. void
  251. MoveGen::pseudoLegalCapturesAndChecks(const Position& pos, MoveList& moveList) {
  252.     using MyColor = ColorTraits<wtm>;
  253.     const U64 occupied = pos.occupiedBB();
  254.  
  255.     const int oKingSq = pos.getKingSq(!wtm);
  256.     U64 discovered = 0; // Squares that could generate discovered checks
  257.     U64 kRookAtk = BitBoard::rookAttacks(oKingSq, occupied);
  258.     if ((BitBoard::rookAttacks(oKingSq, occupied & ~kRookAtk) &
  259.             pos.pieceTypeBB(MyColor::QUEEN, MyColor::ROOK)) != 0)
  260.         discovered |= kRookAtk;
  261.     U64 kBishAtk = BitBoard::bishopAttacks(oKingSq, occupied);
  262.     if ((BitBoard::bishopAttacks(oKingSq, occupied & ~kBishAtk) &
  263.             pos.pieceTypeBB(MyColor::QUEEN, MyColor::BISHOP)) != 0)
  264.         discovered |= kBishAtk;
  265.  
  266.     // Queen moves
  267.     U64 squares = pos.pieceTypeBB(MyColor::QUEEN);
  268.     while (squares != 0) {
  269.         int sq = BitBoard::extractSquare(squares);
  270.         U64 m = (BitBoard::rookAttacks(sq, occupied) | BitBoard::bishopAttacks(sq, occupied));
  271.         if ((discovered & (1ULL<<sq)) == 0) m &= (pos.colorBB(!wtm) | kRookAtk | kBishAtk);
  272.         m &= ~pos.colorBB(wtm);
  273.         addMovesByMask(moveList, sq, m);
  274.     }
  275.  
  276.     // Rook moves
  277.     squares = pos.pieceTypeBB(MyColor::ROOK);
  278.     while (squares != 0) {
  279.         int sq = BitBoard::extractSquare(squares);
  280.         U64 m = BitBoard::rookAttacks(sq, occupied);
  281.         if ((discovered & (1ULL<<sq)) == 0) m &= (pos.colorBB(!wtm) | kRookAtk);
  282.         m &= ~pos.colorBB(wtm);
  283.         addMovesByMask(moveList, sq, m);
  284.     }
  285.  
  286.     // Bishop moves
  287.     squares = pos.pieceTypeBB(MyColor::BISHOP);
  288.     while (squares != 0) {
  289.         int sq = BitBoard::extractSquare(squares);
  290.         U64 m = BitBoard::bishopAttacks(sq, occupied);
  291.         if ((discovered & (1ULL<<sq)) == 0) m &= (pos.colorBB(!wtm) | kBishAtk);
  292.         m &= ~pos.colorBB(wtm);
  293.         addMovesByMask(moveList, sq, m);
  294.     }
  295.  
  296.     // King moves
  297.     {
  298.         int sq = pos.getKingSq(wtm);
  299.         U64 m = BitBoard::kingAttacks[sq];
  300.         m &= ((discovered & (1ULL<<sq)) == 0) ? pos.colorBB(!wtm) : ~pos.colorBB(wtm);
  301.         addMovesByMask(moveList, sq, m);
  302.         const int k0 = wtm ? E1 : E8;
  303.         if (sq == k0) {
  304.             const U64 OO_SQ = wtm ? BitBoard::sqMask(F1,G1) : BitBoard::sqMask(F8,G8);
  305.             const U64 OOO_SQ = wtm ? BitBoard::sqMask(B1,C1,D1) : BitBoard::sqMask(B8,C8,D8);
  306.             const int hCastle = wtm ? Position::H1_CASTLE : Position::H8_CASTLE;
  307.             const int aCastle = wtm ? Position::A1_CASTLE : Position::A8_CASTLE;
  308.             if (((pos.getCastleMask() & (1 << hCastle)) != 0) &&
  309.                 ((OO_SQ & occupied) == 0) &&
  310.                 (pos.getPiece(k0 + 3) == MyColor::ROOK) &&
  311.                 !sqAttacked(pos, k0) &&
  312.                 !sqAttacked(pos, k0 + 1)) {
  313.                 moveList.addMove(k0, k0 + 2, Piece::EMPTY);
  314.             }
  315.             if (((pos.getCastleMask() & (1 << aCastle)) != 0) &&
  316.                 ((OOO_SQ & occupied) == 0) &&
  317.                 (pos.getPiece(k0 - 4) == MyColor::ROOK) &&
  318.                 !sqAttacked(pos, k0) &&
  319.                 !sqAttacked(pos, k0 - 1)) {
  320.                 moveList.addMove(k0, k0 - 2, Piece::EMPTY);
  321.             }
  322.         }
  323.     }
  324.  
  325.     // Knight moves
  326.     U64 knights = pos.pieceTypeBB(MyColor::KNIGHT);
  327.     U64 kKnightAtk = BitBoard::knightAttacks[oKingSq];
  328.     while (knights != 0) {
  329.         int sq = BitBoard::extractSquare(knights);
  330.         U64 m = BitBoard::knightAttacks[sq] & ~pos.colorBB(wtm);
  331.         if ((discovered & (1ULL<<sq)) == 0) m &= (pos.colorBB(!wtm) | kKnightAtk);
  332.         addMovesByMask(moveList, sq, m);
  333.     }
  334.  
  335.     // Pawn moves
  336.     const U64 pawns = pos.pieceTypeBB(MyColor::PAWN);
  337.     const int epSquare = pos.getEpSquare();
  338.     const U64 epMask = (epSquare >= 0) ? (1ULL << epSquare) : 0ULL;
  339.     if (wtm) {
  340.         // Captures
  341.         U64 m = (pawns << 7) & BitBoard::maskAToGFiles & (pos.colorBB(!wtm) | epMask);
  342.         addPawnMovesByMask<wtm>(moveList, m, -7, false);
  343.         m = (pawns << 9) & BitBoard::maskBToHFiles & (pos.colorBB(!wtm) | epMask);
  344.         addPawnMovesByMask<wtm>(moveList, m, -9, false);
  345.  
  346.         // Discovered checks and promotions
  347.         U64 pawnAll = discovered | BitBoard::maskRow7;
  348.         m = ((pawns & pawnAll) << 8) & ~occupied;
  349.         addPawnMovesByMask<wtm>(moveList, m, -8, false);
  350.         m = ((m & BitBoard::maskRow3) << 8) & ~occupied;
  351.         addPawnDoubleMovesByMask(moveList, m, -16);
  352.  
  353.         // Normal checks
  354.         m = ((pawns & ~pawnAll) << 8) & ~occupied;
  355.         addPawnMovesByMask<wtm>(moveList, m & BitBoard::bPawnAttacks[oKingSq], -8, false);
  356.         m = ((m & BitBoard::maskRow3) << 8) & ~occupied;
  357.         addPawnDoubleMovesByMask(moveList, m & BitBoard::bPawnAttacks[oKingSq], -16);
  358.     } else {
  359.         // Captures
  360.         U64 m = (pawns >> 9) & BitBoard::maskAToGFiles & (pos.colorBB(!wtm) | epMask);
  361.         addPawnMovesByMask<wtm>(moveList, m, 9, false);
  362.         m = (pawns >> 7) & BitBoard::maskBToHFiles & (pos.colorBB(!wtm) | epMask);
  363.         addPawnMovesByMask<wtm>(moveList, m, 7, false);
  364.  
  365.         // Discovered checks and promotions
  366.         U64 pawnAll = discovered | BitBoard::maskRow2;
  367.         m = ((pawns & pawnAll) >> 8) & ~occupied;
  368.         addPawnMovesByMask<wtm>(moveList, m, 8, false);
  369.         m = ((m & BitBoard::maskRow6) >> 8) & ~occupied;
  370.         addPawnDoubleMovesByMask(moveList, m, 16);
  371.  
  372.         // Normal checks
  373.         m = ((pawns & ~pawnAll) >> 8) & ~occupied;
  374.         addPawnMovesByMask<wtm>(moveList, m & BitBoard::wPawnAttacks[oKingSq], 8, false);
  375.         m = ((m & BitBoard::maskRow6) >> 8) & ~occupied;
  376.         addPawnDoubleMovesByMask(moveList, m & BitBoard::wPawnAttacks[oKingSq], 16);
  377.     }
  378. }
  379.  
  380. template void MoveGen::pseudoLegalCaptures<true>(const Position& pos, MoveList& moveList);
  381. template void MoveGen::pseudoLegalCaptures<false>(const Position& pos, MoveList& moveList);
  382.  
  383. template <bool wtm>
  384. void
  385. MoveGen::pseudoLegalCaptures(const Position& pos, MoveList& moveList) {
  386.     using MyColor = ColorTraits<wtm>;
  387.     const U64 occupied = pos.occupiedBB();
  388.  
  389.     // Queen moves
  390.     U64 squares = pos.pieceTypeBB(MyColor::QUEEN);
  391.     while (squares != 0) {
  392.         int sq = BitBoard::extractSquare(squares);
  393.         U64 m = (BitBoard::rookAttacks(sq, occupied) | BitBoard::bishopAttacks(sq, occupied)) & pos.colorBB(!wtm);
  394.         addMovesByMask(moveList, sq, m);
  395.     }
  396.  
  397.     // Rook moves
  398.     squares = pos.pieceTypeBB(MyColor::ROOK);
  399.     while (squares != 0) {
  400.         int sq = BitBoard::extractSquare(squares);
  401.         U64 m = BitBoard::rookAttacks(sq, occupied) & pos.colorBB(!wtm);
  402.         addMovesByMask(moveList, sq, m);
  403.     }
  404.  
  405.     // Bishop moves
  406.     squares = pos.pieceTypeBB(MyColor::BISHOP);
  407.     while (squares != 0) {
  408.         int sq = BitBoard::extractSquare(squares);
  409.         U64 m = BitBoard::bishopAttacks(sq, occupied) & pos.colorBB(!wtm);
  410.         addMovesByMask(moveList, sq, m);
  411.     }
  412.  
  413.     // Knight moves
  414.     U64 knights = pos.pieceTypeBB(MyColor::KNIGHT);
  415.     while (knights != 0) {
  416.         int sq = BitBoard::extractSquare(knights);
  417.         U64 m = BitBoard::knightAttacks[sq] & pos.colorBB(!wtm);
  418.         addMovesByMask(moveList, sq, m);
  419.     }
  420.  
  421.     // King moves
  422.     int sq = pos.getKingSq(wtm);
  423.     U64 m = BitBoard::kingAttacks[sq] & pos.colorBB(!wtm);
  424.     addMovesByMask(moveList, sq, m);
  425.  
  426.     // Pawn moves
  427.     const U64 pawns = pos.pieceTypeBB(MyColor::PAWN);
  428.     const int epSquare = pos.getEpSquare();
  429.     const U64 epMask = (epSquare >= 0) ? (1ULL << epSquare) : 0ULL;
  430.     if (wtm) {
  431.         m = (pawns << 8) & ~occupied;
  432.         m &= BitBoard::maskRow8;
  433.         addPawnMovesByMask<wtm>(moveList, m, -8, false);
  434.  
  435.         m = (pawns << 7) & BitBoard::maskAToGFiles & (pos.colorBB(!wtm) | epMask);
  436.         addPawnMovesByMask<wtm>(moveList, m, -7, false);
  437.         m = (pawns << 9) & BitBoard::maskBToHFiles & (pos.colorBB(!wtm) | epMask);
  438.         addPawnMovesByMask<wtm>(moveList, m, -9, false);
  439.     } else {
  440.         m = (pawns >> 8) & ~occupied;
  441.         m &= BitBoard::maskRow1;
  442.         addPawnMovesByMask<wtm>(moveList, m, 8, false);
  443.  
  444.         m = (pawns >> 9) & BitBoard::maskAToGFiles & (pos.colorBB(!wtm) | epMask);
  445.         addPawnMovesByMask<wtm>(moveList, m, 9, false);
  446.         m = (pawns >> 7) & BitBoard::maskBToHFiles & (pos.colorBB(!wtm) | epMask);
  447.         addPawnMovesByMask<wtm>(moveList, m, 7, false);
  448.     }
  449. }
  450.  
  451. bool
  452. MoveGen::givesCheck(const Position& pos, const Move& m) {
  453.     bool wtm = pos.isWhiteMove();
  454.     int oKingSq = pos.getKingSq(!wtm);
  455.     int oKing = wtm ? Piece::BKING : Piece::WKING;
  456.     int p = Piece::makeWhite(m.promoteTo() == Piece::EMPTY ? pos.getPiece(m.from()) : m.promoteTo());
  457.     int d1 = BitBoard::getDirection(m.to(), oKingSq);
  458.     switch (d1) {
  459.     case 8: case -8: case 1: case -1: // Rook direction
  460.         if ((p == Piece::WQUEEN) || (p == Piece::WROOK))
  461.             if ((d1 != 0) && (nextPiece(pos, m.to(), d1) == oKing))
  462.                 return true;
  463.         break;
  464.     case 9: case 7: case -9: case -7: // Bishop direction
  465.         if ((p == Piece::WQUEEN) || (p == Piece::WBISHOP)) {
  466.             if ((d1 != 0) && (nextPiece(pos, m.to(), d1) == oKing))
  467.                 return true;
  468.         } else if (p == Piece::WPAWN) {
  469.             if (((d1 > 0) == wtm) && (pos.getPiece(m.to() + d1) == oKing))
  470.                 return true;
  471.         }
  472.         break;
  473.     default:
  474.         if (d1 != 0) { // Knight direction
  475.             if (p == Piece::WKNIGHT)
  476.                 return true;
  477.         }
  478.         break;
  479.     }
  480.     int d2 = BitBoard::getDirection(m.from(), oKingSq);
  481.     if ((d2 != 0) && (d2 != d1) && (nextPiece(pos, m.from(), d2) == oKing)) {
  482.         int p2 = nextPieceSafe(pos, m.from(), -d2);
  483.         switch (d2) {
  484.         case 8: case -8: case 1: case -1: // Rook direction
  485.             if ((p2 == (wtm ? Piece::WQUEEN : Piece::BQUEEN)) ||
  486.                 (p2 == (wtm ? Piece::WROOK : Piece::BROOK)))
  487.                 return true;
  488.             break;
  489.         case 9: case 7: case -9: case -7: // Bishop direction
  490.             if ((p2 == (wtm ? Piece::WQUEEN : Piece::BQUEEN)) ||
  491.                 (p2 == (wtm ? Piece::WBISHOP : Piece::BBISHOP)))
  492.                 return true;
  493.             break;
  494.         }
  495.     }
  496.     if ((m.promoteTo() != Piece::EMPTY) && (d1 != 0) && (d1 == d2)) {
  497.         switch (d1) {
  498.         case 8: case -8: case 1: case -1: // Rook direction
  499.             if ((p == Piece::WQUEEN) || (p == Piece::WROOK))
  500.                 if ((d1 != 0) && (nextPiece(pos, m.from(), d1) == oKing))
  501.                     return true;
  502.             break;
  503.         case 9: case 7: case -9: case -7: // Bishop direction
  504.             if ((p == Piece::WQUEEN) || (p == Piece::WBISHOP)) {
  505.                 if ((d1 != 0) && (nextPiece(pos, m.from(), d1) == oKing))
  506.                     return true;
  507.             }
  508.             break;
  509.         }
  510.     }
  511.     if (p == Piece::WKING) {
  512.         if (m.to() - m.from() == 2) { // O-O
  513.             if (nextPieceSafe(pos, m.from(), -1) == oKing)
  514.                 return true;
  515.             if (nextPieceSafe(pos, m.from() + 1, wtm ? 8 : -8) == oKing)
  516.                 return true;
  517.         } else if (m.to() - m.from() == -2) { // O-O-O
  518.             if (nextPieceSafe(pos, m.from(), 1) == oKing)
  519.                 return true;
  520.             if (nextPieceSafe(pos, m.from() - 1, wtm ? 8 : -8) == oKing)
  521.                 return true;
  522.         }
  523.     } else if (p == Piece::WPAWN) {
  524.         if (pos.getPiece(m.to()) == Piece::EMPTY) {
  525.             int dx = Position::getX(m.to()) - Position::getX(m.from());
  526.             if (dx != 0) { // en passant
  527.                 int epSq = m.from() + dx;
  528.                 int d3 = BitBoard::getDirection(epSq, oKingSq);
  529.                 switch (d3) {
  530.                 case 9: case 7: case -9: case -7:
  531.                     if (nextPiece(pos, epSq, d3) == oKing) {
  532.                         int p2 = nextPieceSafe(pos, epSq, -d3);
  533.                         if ((p2 == (wtm ? Piece::WQUEEN : Piece::BQUEEN)) ||
  534.                             (p2 == (wtm ? Piece::WBISHOP : Piece::BBISHOP)))
  535.                             return true;
  536.                     }
  537.                     break;
  538.                 case 1:
  539.                     if (nextPiece(pos, std::max(epSq, m.from()), d3) == oKing) {
  540.                         int p2 = nextPieceSafe(pos, std::min(epSq, m.from()), -d3);
  541.                         if ((p2 == (wtm ? Piece::WQUEEN : Piece::BQUEEN)) ||
  542.                             (p2 == (wtm ? Piece::WROOK : Piece::BROOK)))
  543.                             return true;
  544.                     }
  545.                     break;
  546.                 case -1:
  547.                     if (nextPiece(pos, std::min(epSq, m.from()), d3) == oKing) {
  548.                         int p2 = nextPieceSafe(pos, std::max(epSq, m.from()), -d3);
  549.                         if ((p2 == (wtm ? Piece::WQUEEN : Piece::BQUEEN)) ||
  550.                             (p2 == (wtm ? Piece::WROOK : Piece::BROOK)))
  551.                             return true;
  552.                     }
  553.                     break;
  554.                 }
  555.             }
  556.         }
  557.     }
  558.     return false;
  559. }
  560.  
  561. void
  562. MoveGen::removeIllegal(Position& pos, MoveList& moveList) {
  563.     int length = 0;
  564.     UndoInfo ui;
  565.  
  566.     bool isInCheck = inCheck(pos);
  567.     const U64 occupied = pos.occupiedBB();
  568.     int kSq = pos.getKingSq(pos.isWhiteMove());
  569.     U64 kingAtks = BitBoard::rookAttacks(kSq, occupied) | BitBoard::bishopAttacks(kSq, occupied);
  570.     int epSquare = pos.getEpSquare();
  571.     if (isInCheck) {
  572.         kingAtks |= pos.pieceTypeBB(pos.isWhiteMove() ? Piece::BKNIGHT : Piece::WKNIGHT);
  573.         for (int mi = 0; mi < moveList.size; mi++) {
  574.             const Move& m = moveList[mi];
  575.             bool legal;
  576.             if ((m.from() != kSq) && ((kingAtks & (1ULL<<m.to())) == 0) && (m.to() != epSquare)) {
  577.                 legal = false;
  578.             } else {
  579.                 pos.makeMove(m, ui);
  580.                 pos.setWhiteMove(!pos.isWhiteMove());
  581.                 legal = !inCheck(pos);
  582.                 pos.setWhiteMove(!pos.isWhiteMove());
  583.                 pos.unMakeMove(m, ui);
  584.             }
  585.             if (legal)
  586.                 moveList[length++] = m;
  587.         }
  588.     } else {
  589.         for (int mi = 0; mi < moveList.size; mi++) {
  590.             const Move& m = moveList[mi];
  591.             bool legal;
  592.             if ((m.from() != kSq) && ((kingAtks & (1ULL<<m.from())) == 0) && (m.to() != epSquare)) {
  593.                 legal = true;
  594.             } else {
  595.                 pos.makeMove(m, ui);
  596.                 pos.setWhiteMove(!pos.isWhiteMove());
  597.                 legal = !inCheck(pos);
  598.                 pos.setWhiteMove(!pos.isWhiteMove());
  599.                 pos.unMakeMove(m, ui);
  600.             }
  601.             if (legal)
  602.                 moveList[length++] = m;
  603.         }
  604.     }
  605.     moveList.size = length;
  606. }
  607.  
  608. bool
  609. MoveGen::isLegal(Position& pos, const Move& m, bool isInCheck) {
  610.     UndoInfo ui;
  611.     int kSq = pos.getKingSq(pos.isWhiteMove());
  612.     const int epSquare = pos.getEpSquare();
  613.     if (isInCheck) {
  614.         if ((m.from() != kSq) && (m.to() != epSquare)) {
  615.             U64 occupied = pos.occupiedBB();
  616.             U64 toMask = 1ULL << m.to();
  617.             Piece::Type knight = pos.isWhiteMove() ? Piece::BKNIGHT : Piece::WKNIGHT;
  618.             if (((BitBoard::rookAttacks(kSq, occupied) & toMask) == 0) &&
  619.                 ((BitBoard::bishopAttacks(kSq, occupied) & toMask) == 0) &&
  620.                 ((BitBoard::knightAttacks[kSq] & pos.pieceTypeBB(knight) & toMask) == 0))
  621.                 return false;
  622.         }
  623.         pos.makeMoveB(m, ui);
  624.         bool legal = !inCheck(pos);
  625.         pos.unMakeMoveB(m, ui);
  626.         return legal;
  627.     } else {
  628.         if (m.from() == kSq) {
  629.             U64 occupied = pos.occupiedBB() & ~(1ULL<<m.from());
  630.             return !MoveGen::sqAttacked(pos, m.to(), occupied);
  631.         } else {
  632.             if (m.to() != epSquare) {
  633.                 U64 occupied = pos.occupiedBB();
  634.                 U64 fromMask = 1ULL << m.from();
  635.                 if (((BitBoard::rookAttacks(kSq, occupied) & fromMask) == 0) &&
  636.                     ((BitBoard::bishopAttacks(kSq, occupied) & fromMask) == 0))
  637.                     return true;
  638.                 else if (BitBoard::getDirection(kSq, m.from()) == BitBoard::getDirection(kSq, m.to()))
  639.                     return true;
  640.             }
  641.             pos.makeMoveB(m, ui);
  642.             bool legal = !inCheck(pos);
  643.             pos.unMakeMoveB(m, ui);
  644.             return legal;
  645.         }
  646.     }
  647. }
  648.