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.hpp
  21.  *
  22.  *  Created on: Feb 25, 2012
  23.  *      Author: petero
  24.  */
  25.  
  26. #ifndef MOVEGEN_HPP_
  27. #define MOVEGEN_HPP_
  28.  
  29. #include "move.hpp"
  30. #include "position.hpp"
  31. #include "util/util.hpp"
  32.  
  33. #include <cassert>
  34.  
  35. //#define MOVELIST_DEBUG
  36.  
  37. #ifdef MOVELIST_DEBUG
  38. # include <set>
  39. # include "textio.hpp"
  40. #endif
  41.  
  42. /** A stack-allocated move list object. */
  43. class MoveList {
  44. public:
  45.     MoveList();
  46.  
  47.     void clear();
  48.  
  49.           Move& operator[](int i);
  50.     const Move& operator[](int i) const;
  51.  
  52.     void addMove(int from, int to, int promoteTo);
  53.  
  54.     /** Remove all moves that are not included in searchMoves. */
  55.     void filter(const std::vector<Move>& searchMoves);
  56.  
  57.     int size;
  58.  
  59. private:
  60.     static const int MAX_MOVES = 256;
  61.     int buf[sizeof(Move[MAX_MOVES])/sizeof(int)];
  62. };
  63.  
  64. /**
  65.  * Generates move lists (pseudo-legal, legal, check evasions, captures).
  66.  */
  67. class MoveGen {
  68. public:
  69.     MoveGen() = delete;
  70.  
  71.     /**
  72.      * Generate and return a list of pseudo-legal moves.
  73.      * Pseudo-legal means that the moves don't necessarily defend from check threats.
  74.      */
  75.     template <bool wtm>
  76.     static void pseudoLegalMoves(const Position& pos, MoveList& moveList);
  77.     static void pseudoLegalMoves(const Position& pos, MoveList& moveList);
  78.  
  79.     /**
  80.      * Generate and return a list of pseudo-legal check evasion moves.
  81.      * Pseudo-legal means that the moves don't necessarily defend from check threats.
  82.      */
  83.     template <bool wtm>
  84.     static void checkEvasions(const Position& pos, MoveList& moveList);
  85.     static void checkEvasions(const Position& pos, MoveList& moveList);
  86.  
  87.     /** Generate captures, checks, and possibly some other moves that are too hard to filter out. */
  88.     template <bool wtm>
  89.     static void pseudoLegalCapturesAndChecks(const Position& pos, MoveList& moveList);
  90.     static void pseudoLegalCapturesAndChecks(const Position& pos, MoveList& moveList);
  91.  
  92.     /** Generate and return a list of pseudo-legal capture moves. */
  93.     template <bool wtm>
  94.     static void pseudoLegalCaptures(const Position& pos, MoveList& moveList);
  95.     static void pseudoLegalCaptures(const Position& pos, MoveList& moveList);
  96.  
  97.     /** Return true if the side to move is in check. */
  98.     static bool inCheck(const Position& pos);
  99.  
  100.     /** Return true if making a move delivers check to the opponent */
  101.     static bool givesCheck(const Position& pos, const Move& m);
  102.  
  103.     /** Return true if the side to move can take the opponents king. */
  104.     static bool canTakeKing(Position& pos);
  105.  
  106.     /** Return true if a square is attacked by the opposite side. */
  107.     static bool sqAttacked(const Position& pos, int sq);
  108.     static bool sqAttacked(const Position& pos, int sq, U64 occupied);
  109.     template <bool wtm> static bool sqAttacked(const Position& pos, int sq, U64 occupied);
  110.  
  111.     /**
  112.      * Remove all illegal moves from moveList.
  113.      * "moveList" is assumed to be a list of pseudo-legal moves.
  114.      * This function removes the moves that don't defend from check threats.
  115.      */
  116.     static void removeIllegal(Position& pos, MoveList& moveList);
  117.  
  118.     /** Return true if the pseudo-legal move "move" is legal is position "pos".
  119.      * isInCheck must be equal to inCheck(pos). */
  120.     static bool isLegal(Position& pos, const Move& move, bool isInCheck);
  121.  
  122. private:
  123.     /** Return the next piece in a given direction, starting from sq. */
  124.     static int nextPiece(const Position& pos, int sq, int delta);
  125.  
  126.     /** Like nextPiece(), but handles board edges. */
  127.     static int nextPieceSafe(const Position& pos, int sq, int delta);
  128.  
  129.     template <bool wtm>
  130.     static void addPawnMovesByMask(MoveList& moveList, U64 mask, int delta, bool allPromotions);
  131.  
  132.     static void addPawnDoubleMovesByMask(MoveList& moveList, U64 mask, int delta);
  133.  
  134.     static void addMovesByMask(MoveList& moveList, int sq0, U64 mask);
  135. };
  136.  
  137.  
  138. inline
  139. MoveList::MoveList()
  140.     : size(0) {
  141. }
  142.  
  143. inline void
  144. MoveList::clear() {
  145.     size = 0;
  146. }
  147.  
  148. inline Move&
  149. MoveList::operator[](int i) {
  150.     return ((Move*)&buf[0])[i];
  151. }
  152. inline const Move&
  153. MoveList::operator[](int i) const {
  154.     return ((Move*)&buf[0])[i];
  155. }
  156.  
  157. inline void
  158. MoveList::addMove(int from, int to, int promoteTo) {
  159.     Move& m = (*this)[size++];
  160.     new (&m) Move(from, to, promoteTo, 0);
  161. }
  162.  
  163. inline void
  164. MoveGen::pseudoLegalMoves(const Position& pos, MoveList& moveList) {
  165.     if (pos.isWhiteMove())
  166.         pseudoLegalMoves<true>(pos, moveList);
  167.     else
  168.         pseudoLegalMoves<false>(pos, moveList);
  169. }
  170.  
  171. inline void
  172. MoveGen::checkEvasions(const Position& pos, MoveList& moveList) {
  173.     if (pos.isWhiteMove())
  174.         checkEvasions<true>(pos, moveList);
  175.     else
  176.         checkEvasions<false>(pos, moveList);
  177. }
  178.  
  179. inline void
  180. MoveGen::pseudoLegalCapturesAndChecks(const Position& pos, MoveList& moveList) {
  181.     if (pos.isWhiteMove())
  182.         pseudoLegalCapturesAndChecks<true>(pos, moveList);
  183.     else
  184.         pseudoLegalCapturesAndChecks<false>(pos, moveList);
  185. }
  186.  
  187. inline void
  188. MoveGen::pseudoLegalCaptures(const Position& pos, MoveList& moveList) {
  189.     if (pos.isWhiteMove())
  190.         pseudoLegalCaptures<true>(pos, moveList);
  191.     else
  192.         pseudoLegalCaptures<false>(pos, moveList);
  193. }
  194.  
  195. inline bool
  196. MoveGen::inCheck(const Position& pos) {
  197.     int kingSq = pos.getKingSq(pos.isWhiteMove());
  198.     return sqAttacked(pos, kingSq);
  199. }
  200.  
  201. inline bool
  202. MoveGen::canTakeKing(Position& pos) {
  203.     pos.setWhiteMove(!pos.isWhiteMove());
  204.     bool ret = inCheck(pos);
  205.     pos.setWhiteMove(!pos.isWhiteMove());
  206.     return ret;
  207. }
  208.  
  209. inline bool
  210. MoveGen::sqAttacked(const Position& pos, int sq) {
  211.     const U64 occupied = pos.occupiedBB();
  212.     return sqAttacked(pos, sq, occupied);
  213. }
  214.  
  215. inline bool
  216. MoveGen::sqAttacked(const Position& pos, int sq, U64 occupied) {
  217.     return pos.isWhiteMove() ? sqAttacked<true>(pos, sq, occupied)
  218.                              : sqAttacked<false>(pos, sq, occupied);
  219. }
  220.  
  221. template <bool wtm>
  222. inline bool
  223. MoveGen::sqAttacked(const Position& pos, int sq, U64 occupied) {
  224.     using OtherColor = ColorTraits<!wtm>;
  225.     if ((BitBoard::knightAttacks[sq] & pos.pieceTypeBB(OtherColor::KNIGHT)) != 0)
  226.         return true;
  227.     if ((BitBoard::kingAttacks[sq] & pos.pieceTypeBB(OtherColor::KING)) != 0)
  228.         return true;
  229.     if (wtm) {
  230.         if ((BitBoard::wPawnAttacks[sq] & pos.pieceTypeBB(OtherColor::PAWN)) != 0)
  231.             return true;
  232.     } else {
  233.         if ((BitBoard::bPawnAttacks[sq] & pos.pieceTypeBB(OtherColor::PAWN)) != 0)
  234.             return true;
  235.     }
  236.     U64 bbQueen = pos.pieceTypeBB(OtherColor::QUEEN);
  237.     if ((BitBoard::bishopAttacks(sq, occupied) & (pos.pieceTypeBB(OtherColor::BISHOP) | bbQueen)) != 0)
  238.         return true;
  239.     if ((BitBoard::rookAttacks(sq, occupied) & (pos.pieceTypeBB(OtherColor::ROOK) | bbQueen)) != 0)
  240.         return true;
  241.     return false;
  242. }
  243.  
  244. inline int
  245. MoveGen::nextPiece(const Position& pos, int sq, int delta) {
  246.     while (true) {
  247.         sq += delta;
  248.         int p = pos.getPiece(sq);
  249.         if (p != Piece::EMPTY)
  250.             return p;
  251.     }
  252.     assert(false);
  253.     return -1;
  254. }
  255.  
  256. inline int
  257. MoveGen::nextPieceSafe(const Position& pos, int sq, int delta) {
  258.     int dx = 0, dy = 0;
  259.     switch (delta) {
  260.     case 1: dx=1; dy=0; break;
  261.     case 9: dx=1; dy=1; break;
  262.     case 8: dx=0; dy=1; break;
  263.     case 7: dx=-1; dy=1; break;
  264.     case -1: dx=-1; dy=0; break;
  265.     case -9: dx=-1; dy=-1; break;
  266.     case -8: dx=0; dy=-1; break;
  267.     case -7: dx=1; dy=-1; break;
  268.     }
  269.     int x = Position::getX(sq);
  270.     int y = Position::getY(sq);
  271.     while (true) {
  272.         x += dx;
  273.         y += dy;
  274.         if ((x < 0) || (x > 7) || (y < 0) || (y > 7)) {
  275.             return Piece::EMPTY;
  276.         }
  277.         int p = pos.getPiece(Position::getSquare(x, y));
  278.         if (p != Piece::EMPTY)
  279.             return p;
  280.     }
  281.     assert(false);
  282.     return -1;
  283. }
  284.  
  285. template <bool wtm>
  286. inline void
  287. MoveGen::addPawnMovesByMask(MoveList& moveList, U64 mask, int delta, bool allPromotions) {
  288.     using MyColor = ColorTraits<wtm>;
  289.     if (mask == 0)
  290.         return;
  291.     U64 promMask = mask & BitBoard::maskRow1Row8;
  292.     mask &= ~promMask;
  293.     while (promMask != 0) {
  294.         int sq = BitBoard::extractSquare(promMask);
  295.         int sq0 = sq + delta;
  296.         moveList.addMove(sq0, sq, MyColor::QUEEN);
  297.         moveList.addMove(sq0, sq, MyColor::KNIGHT);
  298.         if (allPromotions) {
  299.             moveList.addMove(sq0, sq, MyColor::ROOK);
  300.             moveList.addMove(sq0, sq, MyColor::BISHOP);
  301.         }
  302.     }
  303.     while (mask != 0) {
  304.         int sq = BitBoard::extractSquare(mask);
  305.         moveList.addMove(sq + delta, sq, Piece::EMPTY);
  306.     }
  307. }
  308.  
  309. inline void
  310. MoveGen::addPawnDoubleMovesByMask(MoveList& moveList, U64 mask, int delta) {
  311.     while (mask != 0) {
  312.         int sq = BitBoard::extractSquare(mask);
  313.         moveList.addMove(sq + delta, sq, Piece::EMPTY);
  314.     }
  315. }
  316.  
  317. inline void
  318. MoveGen::addMovesByMask(MoveList& moveList, int sq0, U64 mask) {
  319.     while (mask != 0) {
  320.         int sq = BitBoard::extractSquare(mask);
  321.         moveList.addMove(sq0, sq, Piece::EMPTY);
  322.     }
  323. }
  324.  
  325. #endif /* MOVEGEN_HPP_ */
  326.