home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / ARASAN_S.ZIP / MOVEGEN.CPP < prev    next >
C/C++ Source or Header  |  1994-08-12  |  9KB  |  290 lines

  1. // Copyright 1994 by Jon Dart.  All Rights Reserved.
  2.  
  3. #include "movegen.h"
  4. #include "bearing.h"
  5. #include "emove.h"
  6. #include "rmove.h"
  7. #include "scoring.h"
  8. #include "moveord.h"
  9. #include "util.h"
  10. #include <iostream.h>
  11. #ifdef RANGE_CHECK
  12. #include <assert.h>
  13. #endif
  14.  
  15. Move_Generator::Move_Generator(const Board & ABoard,
  16.    const unsigned ply, const Move & last_move):
  17.    board(ABoard), my_ply(ply), my_last_move(last_move)
  18. {
  19. }
  20.  
  21. Move_Generator::~Move_Generator()
  22. {
  23. }
  24.  
  25. inline void Move_Generator::
  26. SetMove(const Square source, const Square dest,
  27.     const Piece::PieceType promotion, Move * moves, unsigned &NumMoves)
  28. {
  29. #ifdef RANGE_CHECK
  30.    assert(source.OnBoard());
  31.    assert(dest.OnBoard());
  32.    assert(NumMoves <= Move_Generator::MaxMoves);
  33. #endif
  34.    moves[NumMoves] = Move(source, dest, promotion);
  35.    ++NumMoves;
  36. }
  37.  
  38. int Move_Generator::
  39. Generate_Moves(Move * moves, const Boolean captures_only,
  40.            const Boolean repeatable)
  41. {
  42.    unsigned NumMoves;
  43.    if (board.CheckStatus() == Board::InCheck)
  44.    {
  45.       NumMoves = Check_Evasions(moves);
  46.    }
  47.    else
  48.    {
  49.       NumMoves = 0;
  50.  
  51.       // castling moves
  52.       if (!captures_only)
  53.       {
  54.      const ColorType side = board.Side();
  55.          Board::CastleType CS = board.CastleStatus(side);
  56.          if ((CS == Board::CanCastleEitherSide) ||
  57.              (CS == Board::CanCastleKSide))
  58.      {
  59.         const Square kp = board.KingPos(side);
  60.         if (board[kp + 1].IsEmpty() &&
  61.             board[kp + 2].IsEmpty() &&
  62.         board.num_attacks(kp,OppositeColor(side)) == 0 &&
  63.         board.num_attacks(kp + 1,OppositeColor(side)) == 0 &&
  64.         board.num_attacks(kp + 2,OppositeColor(side)) == 0)
  65.           // can castle
  66.           SetMove(kp, kp + 2,
  67.                       Piece::Invalid,
  68.               moves, NumMoves);
  69.      }
  70.          if ((CS == Board::CanCastleEitherSide) ||
  71.              (CS == Board::CanCastleQSide))
  72.      {
  73.         const Square kp = board.KingPos(side);
  74.         if (board[kp - 1].IsEmpty() &&
  75.             board[kp - 2].IsEmpty() &&
  76.             board[kp - 3].IsEmpty() &&
  77.         board.num_attacks(kp,OppositeColor(side)) == 0 &&
  78.         board.num_attacks(kp - 1,OppositeColor(side)) == 0 &&
  79.         board.num_attacks(kp - 2,OppositeColor(side)) == 0)
  80.             // can castle
  81.             SetMove(kp, kp - 2,
  82.                         Piece::Invalid,
  83.                 moves, NumMoves);
  84.      }
  85.       }
  86.       // other moves
  87.       static Square squares[Bearing::MaxBearSq];
  88.  
  89.       for (int i = 0; i < 16; i++)
  90.       {
  91.      Square loc = board.PiecePos(board.Side(), i);
  92.      if (!loc.IsInvalid())
  93.      {
  94.         int n = Bearing::BearSq(board, loc, squares);
  95.         const Piece piecemoved = board[loc];
  96.         for (int j = 0; j < n; j++)
  97.         {
  98.            const Square dest(squares[j]);
  99.            int promotion =
  100.            piecemoved.Type() == Piece::Pawn &&
  101.            dest.Rank(board.Side()) == 8;
  102.            if (promotion)
  103.            {
  104.               SetMove(loc, dest, Piece::Queen, moves, NumMoves);
  105.               SetMove(loc, dest, Piece::Rook, moves, NumMoves);
  106.               SetMove(loc, dest, Piece::Bishop, moves, NumMoves);
  107.               SetMove(loc, dest, Piece::Knight, moves, NumMoves);
  108.            }
  109.                else if (captures_only)
  110.            {
  111.           if (!board[dest].IsEmpty() ||
  112.                     ((piecemoved.Type() == Piece::Pawn) &&
  113.                (dest.File() != loc.File())))
  114.                  SetMove(loc, dest, Piece::Invalid, moves, NumMoves);
  115.            } 
  116.                else
  117.               SetMove(loc, dest, Piece::Invalid, moves, NumMoves);
  118.         }
  119.      }
  120.       }
  121.    }
  122.  
  123.    if (repeatable)
  124.    {
  125.       int *scores = new int[NumMoves];
  126.       for (int i = 0; i < NumMoves; i++)
  127.       {
  128.      scores[i] = moves[i].StartSquare() & (moves[i].DestSquare() << 7);
  129.      switch (moves[i].PromoteTo())
  130.      {
  131.      case Piece::Queen:
  132.         scores[i] &= 0xB000;
  133.         break;
  134.      case Piece::Rook:
  135.         scores[i] &= 0x8000;
  136.         break;
  137.      case Piece::Bishop:
  138.         scores[i] &= 0x4000;
  139.         break;
  140.      default:
  141.         break;
  142.      }
  143.       }
  144.       Move_Ordering::sort_moves(moves, scores, NumMoves);
  145.       delete[] scores;
  146.    }
  147.    return NumMoves;
  148. }
  149.  
  150. static Boolean is_pinned(const Board & board, const Square source,
  151.       const Square dest)
  152. {
  153.    Boolean pin = False;
  154.    if (board.num_attacks(source, board.OppositeSide()) > 0)
  155.    {
  156.       // It is possible that the piece we plan to move is pinned.
  157.       Piece PinnedByPiece;
  158.       Square PinnedBySquare;
  159.       int dir;
  160.       if (Bearing::Pinned(board, source, PinnedByPiece,
  161.       PinnedBySquare, dir))
  162.       {
  163.      // This code checks for moves in the direction of the pin,
  164.      // which are ok:
  165.      int dir1 = Util::Abs((int) source - (int) dest);
  166.      int dir2 = Util::Abs(dir);
  167.      if (dir2 == 1 && source.Rank() != dest.Rank())
  168.         pin = True;
  169.      else if (dir2 == RankIncr && source.File() != dest.File())
  170.         pin = True;
  171.      else if (dir1 % dir2)
  172.         pin = True;
  173.       }
  174.    }
  175.    return pin;
  176. }
  177.  
  178. unsigned Move_Generator::Check_Evasions(Move * moves)
  179. {
  180.    int num_moves = 0;
  181.    unsigned n;
  182.    unsigned i;
  183.    static Square squares[36];
  184.    Square source;
  185.    const Square kp = board.KingPos(board.Side());
  186.    unsigned num_attacks = board.num_attacks(kp, board.OppositeSide());
  187.    const int double_check = num_attacks > 1;
  188.    if (!double_check)
  189.    {
  190.       // try to capture checking piece
  191.       unsigned n = Bearing::Attack(board, kp, board.OppositeSide(), squares);
  192.       assert(n);
  193.       source = squares[0];
  194. #ifdef RANGE_CHECK
  195.       assert(!board[source].IsEmpty() && board[source].Type() != Piece::King);
  196. #endif
  197.       n = Bearing::Attack(board, source, board.Side(), squares);
  198.       for (i = 0; i < n; i++)
  199.       {
  200.          if (board[squares[i]].Type() == Piece::King)
  201.      {
  202.         // We can capture with the king only if the piece
  203.         // checking us is undefended.
  204.         if (board.num_attacks(source, board.OppositeSide()) == 0)
  205.            moves[num_moves++] = Move(squares[i], source);
  206.      }
  207.          else
  208.      {
  209.         if (!is_pinned(board, squares[i], source))
  210.            moves[num_moves++] = Move(squares[i], source);
  211.      }
  212.       }
  213.       // Bearing::Attack does not return en passant captures, so try
  214.       // this as a special case
  215.       if (board.EnPassantSq(board.OppositeSide()) == source)
  216.       {
  217.      Square dest(source + RankIncr * Direction[board.Side()]);
  218.      Piece myPawn(Piece::Pawn,board.Side());
  219.      if (source.File() != 8 && board[source + 1] == myPawn)
  220.      {
  221.         Piece tmp(board[source]);
  222.         Piece &place = (Piece &)board[source];
  223.         place = Piece::EmptyPiece(); // imagine me gone
  224.         if (!is_pinned(board, source + 1, dest))
  225.            moves[num_moves++] = Move(source + 1, dest);
  226.         place = tmp;
  227.      }
  228.      if (source.File() != 1 && board[source - 1] == myPawn)
  229.      {
  230.         Piece tmp(board[source]);
  231.         Piece &place = (Piece &)board[source];
  232.         place = Piece::EmptyPiece(); // imagine me gone
  233.         if (!is_pinned(board, source - 1, dest))
  234.            moves[num_moves++] = Move(source - 1, dest);
  235.         place = tmp;
  236.      }
  237.       }
  238.       // try to interpose a piece
  239.       if (board[source].Type() != Piece::Knight &&
  240.           board[source].Type() != Piece::Pawn)
  241.       {
  242.      Square btwn_squares[8];
  243.      unsigned nbsq = board.Between(source, kp, btwn_squares);
  244.      for (i = 0; i < nbsq; i++)
  245.      {
  246.             n = Bearing::Attack(board, btwn_squares[i],
  247.            board.Side(), squares);
  248.         for (unsigned j = 0; j < n; j++)
  249.         {
  250.            if (board[squares[j]].Type() != Piece::King &&
  251.            !is_pinned(board, squares[j], btwn_squares[i]))
  252.           moves[num_moves++] = Move(squares[j], btwn_squares[i]);
  253.         }
  254.      }
  255.       }
  256.    }
  257.    // generate evasive moves
  258.    n = Bearing::BearSq(board, kp, squares);
  259.    Square atck_squares[8];
  260.    unsigned num_attackers = Bearing::Attack(board, kp,
  261.                     board.OppositeSide(), atck_squares);
  262.    for (i = 0; i < n; i++)
  263.    {
  264.       if (board.num_attacks(squares[i], board.OppositeSide()) == 0)
  265.      if (double_check || squares[i] != source)
  266.      {
  267.         // We need to do some extra checking, since the board
  268.         // info on attacks reflects the state before the move,
  269.         // and we need to be sure that the destination square
  270.         // is not attacked after the move.
  271.         Boolean illegal = False;
  272.         for (int j = 0; j < num_attackers && !illegal; j++)
  273.         {
  274.            Piece attacker(board[atck_squares[j]]);
  275.            if (attacker.sliding())
  276.            {
  277.           int dir = board.Direction(atck_squares[j], squares[i]);
  278.           // check for movement in the direction of the
  279.           // attacker:
  280.           if (dir != 0 && (kp + dir == squares[i]))
  281.              illegal = True;
  282.            }
  283.         }
  284.         if (!illegal)
  285.            moves[num_moves++] = Move(kp, squares[i]);
  286.      }
  287.    }
  288.    return num_moves;
  289. }
  290.