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

  1. // Copyright 1994 by Jon Dart.  All Rights Reserved.
  2.  
  3. #include "board.h"
  4. #include "rmove.h"
  5. #include "constant.h"
  6. #include "bhash.h"
  7. #include "util.h"
  8. #include "bearing.h"
  9. #include <strstream.h>
  10. #include <ctype.h>
  11.  
  12. enum {BoardSize = 64};
  13.  
  14. void Board::set_secondary_vars()
  15. {
  16.     int index[2], i;
  17.  
  18.     index[Black] = index[White] = 0;
  19.  
  20.     for (i=0;i<16;i++)
  21.        my_PiecePos[i][White] = my_PiecePos[i][Black] = Square::Invalid();
  22.     my_Material[White].clear();
  23.     my_Material[Black].clear();
  24.     for (i=0;i<8;i++)
  25.     {
  26.       my_PFileCount[i][White] = my_PFileCount[i][Black] = 0;
  27.       my_RFileCount[i][White] = my_RFileCount[i][Black] = 0;
  28.     }
  29.     for (i=0;i<BoardSize;i++)
  30.     {
  31.         Square sq(i);
  32.         if (!my_Contents[sq].IsEmpty())
  33.     {
  34.         const Piece piece = my_Contents[sq];
  35.         const ColorType color = piece.Color();
  36.         my_PiecePos[index[color]++][color] = sq;
  37.         my_Material[color].add_piece(piece.Type());
  38.         if (piece.Type() == Piece::King)
  39.            my_KingPos[color] = sq;
  40.         if (piece.Type() == Piece::Pawn)
  41.         {
  42.            my_PFileCount[sq.File()-1][color]++;
  43.         }
  44.         else if (piece.Type() == Piece::Rook)
  45.         {
  46.            my_RFileCount[sq.File()-1][color]++;
  47.         }
  48.     }
  49.     }
  50.     my_HashCode = Board_Hash::HashCode(*this);
  51.     my_attacks.clear();
  52.     my_attacks.compute_attacks(*this,White);
  53.     my_attacks.compute_attacks(*this,Black);
  54. }
  55.  
  56. void Board::Reset()
  57. {
  58.     static Piece::PieceType pieces[] =
  59.     {
  60.        Piece::Rook,
  61.        Piece::Knight,
  62.        Piece::Bishop,
  63.        Piece::Queen,
  64.        Piece::King,
  65.        Piece::Bishop,
  66.        Piece::Knight,
  67.        Piece::Rook
  68.     };
  69.  
  70.     my_Side = White;
  71.  
  72.     for (int i=0;i<BoardSize;i++)
  73.     {
  74.        const Square sq(i);
  75.        if (sq.Rank(White) == 1)
  76.        my_Contents[sq] = Piece( pieces[sq.File()-1], White );
  77.        else if (sq.Rank(Black) == 1)
  78.        my_Contents[sq] = Piece( pieces[sq.File()-1], Black );
  79.        else if (sq.Rank(White) == 2)
  80.        my_Contents[sq] = Piece( Piece::Pawn, White);
  81.        else if (sq.Rank(Black) == 2)
  82.        my_Contents[sq] = Piece( Piece::Pawn, Black);
  83.        else
  84.            my_Contents[sq] = Piece::EmptyPiece();
  85.     }
  86.     my_EnPassantSq[White] = my_EnPassantSq[Black] = Square::Invalid();
  87.     my_CastleStatus[White] = my_CastleStatus[Black] = CanCastleEitherSide;
  88.     set_secondary_vars();
  89. }
  90.  
  91. Board::Board()
  92. {
  93.     Reset();
  94. }
  95.  
  96. #ifdef RANGE_CHECK
  97. const Piece &Board::operator[]( const Square sq ) const
  98. {
  99.      assert(sq.OnBoard());
  100.      return my_Contents[sq];
  101. }
  102. #endif
  103.  
  104. Piece Board::GetPiece( const Square start, const int dir, Square &dest ) const
  105. // returns 1st piece in the given direction from "start".  Also 
  106. // sets "dest", where it is
  107. {
  108.     dest = start;
  109.     do {
  110.        dest = dest + dir;
  111.     } while (!dest.OnEdge() && my_Contents[dest].IsEmpty());
  112.  
  113.     return my_Contents[dest];
  114. }
  115.    
  116.  
  117. Board::~Board()
  118. {
  119. }
  120.  
  121. void Board::UpdateCastleStatus( const ColorType side, 
  122.                          const Square sq )
  123. // after a move of or capture of the rook on 'sq', update castle status
  124. // for 'side'
  125. {
  126.      CastleType cs = CastleStatus(side);
  127.      if ((cs != CastledKSide) && (cs != CastledQSide))
  128.      {
  129.          if (sq.File() == 1) // Queen Rook moved or captured
  130.      {
  131.          if (cs == CanCastleEitherSide)
  132.            my_CastleStatus[side] = CanCastleKSide;
  133.              else if (cs == CanCastleQSide)
  134.                my_CastleStatus[side] = CantCastleEitherSide;
  135.      }
  136.      else if (sq.File() == 8) // King Rook moved or captured
  137.      {
  138.          if (cs == CanCastleEitherSide)
  139.            my_CastleStatus[side] = CanCastleQSide;
  140.              else if (cs == CanCastleKSide)
  141.                my_CastleStatus[side] = CantCastleEitherSide;
  142.      }
  143.      }
  144. }
  145.  
  146. int Board::Direction( const Square &sq1, const Square &sq2 ) const
  147. {
  148.      if (sq2 == sq1)
  149.         return 0;
  150.      int offset;
  151.      int abs = (sq2 > sq1) ? (int)sq2 - (int)sq1 : (int)sq1 - (int)sq2;
  152.      if (sq1.File() == sq2.File())
  153.         offset = RankIncr;
  154.      else if (sq1.Rank(White) == sq2.Rank(White))
  155.         offset = 1;
  156.      else if (sq1.Color() == sq2.Color())
  157.      {
  158.        if (abs % (RankIncr+1) == 0)
  159.           offset = RankIncr+1;
  160.        else if (abs % (RankIncr-1) == 0)
  161.           offset = RankIncr-1;
  162.        else
  163.           return 0;
  164.      }
  165.      else 
  166.         return 0;
  167.      return (sq2 > sq1) ? offset : -offset;
  168. }
  169.  
  170. int Board::Between( const Square &sq1, const Square &sq2, 
  171.             Square *squares) const
  172. {
  173.      int offset = Direction(sq1,sq2);
  174.      Square sq(sq1);
  175.      int n = 0;
  176.      for (;;)
  177.      {
  178.          sq += offset;
  179.      if (sq == sq2)
  180.         break;
  181.      squares[n++] = sq;
  182.      }
  183.      return n;
  184. }
  185.  
  186.  
  187. Boolean Board::Clear( const Square &sq1, const Square &sq2 ) const
  188. {
  189.      Square BtwnSquares[9];
  190.      int m = Between(sq1,sq2,BtwnSquares);
  191.      Boolean is_clear = True;
  192.      if (m == 0)
  193.         return True;
  194.      else
  195.      {
  196.         int k = 0;
  197.     do
  198.     {
  199.         is_clear = my_Contents[BtwnSquares[k++]].IsEmpty();
  200.     } while (is_clear && (k<m));
  201.      }
  202.      return is_clear;
  203. }
  204.  
  205. void Board::MakeMove( const ExtendedMove &move )
  206. {
  207.      int i,j;
  208.      const ColorType oside = OppositeSide();
  209.      const ColorType side = Side();
  210.      Square kp,target;
  211.  
  212.      if (move.IsNull())
  213.      {
  214.           my_Side = oside;
  215.          Board_Hash::UpdateHash( *this, move, my_HashCode, my_HashCode );
  216.          return;
  217.      }
  218.      else
  219.          Board_Hash::UpdateHash( *this, move, my_HashCode, my_HashCode );
  220.  
  221.  
  222.      if (move.Special() == ExtendedMove::KCastle)
  223.      {
  224.     const Square kp = KingPos(side);
  225.     my_attacks.remove_attacks(*this,kp,side);
  226.     my_attacks.remove_attacks(*this,kp+3,side);
  227.         i = 0;
  228.     while (i < 16 && PiecePos(side,i) != kp)
  229.       i++;
  230.     assert(i<16);
  231.     my_KingPos[side] = kp + 2;
  232.     my_PiecePos[i][side] = my_KingPos[side];
  233.     my_CastleStatus[side] = CastledKSide;
  234.     // find old square of rook
  235.     Square oldrooksq = kp + 3;
  236.     Square newrooksq = kp + 1;
  237.     i = 0;
  238.     while (i < 16 && PiecePos(side,i) != oldrooksq)
  239.        i++;
  240.     assert(i<16);
  241.         my_PiecePos[i][side] = newrooksq; // update rook position
  242.     my_Contents[kp] = my_Contents[oldrooksq] = Piece::EmptyPiece();
  243.     my_Contents[newrooksq] = Piece(Piece::Rook,side);
  244.     my_Contents[kp+2] = Piece(Piece::King,side);
  245.     my_RFileCount[oldrooksq.File()-1][side]--;
  246.     my_RFileCount[newrooksq.File()-1][side]++;
  247.     my_attacks.add_attacks(*this,kp+1,side);
  248.     my_attacks.add_attacks(*this,kp+2,side);
  249.         my_attacks.add_discovered_attacks(*this,
  250.        kp,kp+1);
  251.      }
  252.      else if (move.Special() == ExtendedMove::QCastle)
  253.      {
  254.     const Square kp = KingPos(side);
  255.     my_attacks.remove_attacks(*this,kp,side);
  256.     my_attacks.remove_attacks(*this,kp-4,side);
  257.     i = 0;
  258.     while (i < 16 && PiecePos(side,i) != kp)
  259.       i++;
  260.     assert(i < 16);
  261.     my_KingPos[side] = kp - 2;
  262.     my_PiecePos[i][side] = my_KingPos[side];
  263.     my_CastleStatus[side] = CastledQSide;
  264.     // find old square of rook
  265.     Square oldrooksq = kp - 4;
  266.     Square newrooksq = kp - 1;
  267.     i = 0;
  268.     while (i < 16 && PiecePos(side,i) != oldrooksq)
  269.        i++;
  270.     assert(i<16);
  271.         my_PiecePos[i][side] = newrooksq; // update rook position
  272.     my_Contents[kp] = my_Contents[oldrooksq] = Piece::EmptyPiece();
  273.     my_Contents[newrooksq] = Piece(Piece::Rook,side);
  274.     my_Contents[kp-2] = Piece(Piece::King,side);
  275.     my_RFileCount[oldrooksq.File()-1][side]--;
  276.     my_RFileCount[newrooksq.File()-1][side]++;
  277.     my_attacks.add_attacks(*this,kp-1,side);
  278.     my_attacks.add_attacks(*this,kp-2,side);
  279.         my_attacks.add_discovered_attacks(*this,
  280.        kp,kp-1);
  281.      }
  282.      else // not castling
  283.      {
  284.         Square target;
  285.         if (move.Special() == ExtendedMove::EnPassant)
  286.         target = my_EnPassantSq[oside];
  287.         else
  288.         target = move.DestSquare();
  289.     my_attacks.remove_attacks(*this,move.StartSquare(),side);
  290.     Square sq;
  291.         i = 0;
  292.     j = -1;
  293.     while (i < 16 && ((sq = PiecePos(side,i)) != move.StartSquare()))
  294.     {
  295.         if (sq == Square::Invalid() && j==-1)
  296.             j = i;
  297.         i++;
  298.     }
  299.     assert (i < 16);
  300.     // keep pieces near the start of the PiecePos array, if possible:
  301.     if (j == -1)
  302.         my_PiecePos[i][side] = move.DestSquare();
  303.     else
  304.     {
  305.         my_PiecePos[j][side] = move.DestSquare();
  306.         my_PiecePos[i][side] = Square::Invalid();
  307.     }
  308.     if (!move.Capture().IsEmpty())
  309.         my_attacks.remove_attacks(*this,target,oside);
  310.     if (move.Special() == ExtendedMove::Promotion)
  311.        my_Contents[move.DestSquare()] = Piece(move.PromoteTo(),side);
  312.         else
  313.        my_Contents[move.DestSquare()] = move.PieceMoved();
  314.     my_Contents[move.StartSquare()] = Piece::EmptyPiece();
  315.     my_EnPassantSq[side] = Square::Invalid();
  316.     if (move.PieceMoved().Type() == Piece::King)
  317.     {
  318.         my_KingPos[side] = move.DestSquare();
  319.         if ((CastleStatus(side) != CastledQSide) &&
  320.             (CastleStatus(side) != CastledKSide))
  321.             my_CastleStatus[side] = CantCastleEitherSide;
  322.     }
  323.     else if (move.PieceMoved().Type() == Piece::Rook)
  324.     {
  325.         my_RFileCount[move.StartSquare().File()-1][side]--;
  326.         my_RFileCount[move.DestSquare().File()-1][side]++;
  327.         UpdateCastleStatus(side,move.StartSquare());
  328.     }
  329.     else if (move.PieceMoved().Type() == Piece::Pawn)
  330.     {
  331.         if (Util::Abs(move.StartSquare().Rank(side) -
  332.                   move.DestSquare().Rank(side)) == 2)
  333.             {
  334.            my_EnPassantSq[side] = move.DestSquare();
  335.         }
  336.         if (move.Special() == ExtendedMove::Promotion)
  337.         {
  338.            my_Material[side].remove_piece(Piece::Pawn);
  339.            my_Material[side].add_piece(move.PromoteTo());
  340.            if (move.PromoteTo() == Piece::Rook)
  341.            {
  342.              my_RFileCount[move.StartSquare().File()-1][side]--;
  343.              my_RFileCount[move.DestSquare().File()-1][side]++;
  344.            }
  345.            my_PFileCount[move.StartSquare().File()-1][side]--;
  346.         }
  347.     }
  348.     if (!move.Capture().IsEmpty())
  349.     {
  350.         my_Material[oside].remove_piece(move.Capture().Type());
  351.         i = 0;
  352.         while (i < 16 && PiecePos(oside,i) != target)
  353.            i++;
  354.         //assert(i < 16);
  355.         if (i>=16)
  356.            i = 0; // break here
  357.         //if (move.Special() == ExtendedMove::EnPassant)
  358.         //   my_Contents[target] = Piece::EmptyPiece();
  359.         my_PiecePos[i][oside] = Square::Invalid();
  360.         if (move.Capture().Type() == Piece::Pawn)
  361.             {
  362.            my_PFileCount[target.File()-1][oside]--;
  363.         }
  364.         else if (move.Capture().Type() == Piece::Rook)
  365.         {
  366.            my_RFileCount[move.DestSquare().File()-1][oside]--;
  367.            UpdateCastleStatus(oside,move.DestSquare());
  368.         }
  369.         if (my_Contents[move.DestSquare()].Type() == Piece::Pawn &&
  370.             move.Special() != ExtendedMove::Promotion)
  371.             {
  372.            my_PFileCount[move.StartSquare().File()-1][side]--;
  373.            my_PFileCount[move.DestSquare().File()-1][side]++;
  374.         }
  375.     }
  376.     my_attacks.add_attacks(*this,move.DestSquare(),side);
  377.         if (move.Special() == ExtendedMove::EnPassant)
  378.         {
  379.         my_attacks.add_discovered_attacks(*this,
  380.            move.StartSquare(),move.DestSquare());
  381.          my_attacks.remove_discovered_attacks(*this,
  382.             move.DestSquare(),move.StartSquare());
  383.  
  384.         my_Contents[target] = Piece::EmptyPiece();
  385.  
  386.           my_attacks.add_discovered_attacks(*this,
  387.           target,Square::Invalid());
  388.         }
  389.     else
  390.     {
  391.           my_attacks.add_discovered_attacks(*this,
  392.             move.StartSquare(),move.DestSquare());
  393.         if (move.Capture().IsEmpty())
  394.               my_attacks.remove_discovered_attacks(*this,
  395.                 move.DestSquare(),move.StartSquare());
  396.     }
  397.      }
  398.      my_EnPassantSq[oside] = Square::Invalid();
  399.      my_Side = OppositeSide();
  400. #ifdef DEBUG_ATTACKS
  401.      {
  402.          Attacks new_attacks;
  403.          new_attacks.compute_attacks(*this,White);
  404.          new_attacks.compute_attacks(*this,Black);
  405.      assert(new_attacks == my_attacks);
  406.      }
  407. #endif
  408. }
  409.  
  410. void Board::undo_castling(const Square &kp,
  411.     const Square &oldkingsq, const Square &newrooksq,
  412.         const Square &oldrooksq)
  413. {
  414.     my_attacks.remove_attacks(*this,kp,my_Side);
  415.     my_attacks.remove_attacks(*this,newrooksq,my_Side);
  416.  
  417.     my_Contents[kp] = Piece::EmptyPiece();
  418.     my_Contents[oldrooksq] = Piece(Piece::Rook,my_Side);
  419.     my_Contents[newrooksq] = Piece::EmptyPiece();
  420.     my_Contents[oldkingsq] = Piece(Piece::King,my_Side);
  421.     my_KingPos[my_Side] = oldkingsq;
  422.     
  423.     my_RFileCount[oldrooksq.File()-1][my_Side]++;
  424.     my_RFileCount[newrooksq.File()-1][my_Side]--;
  425.     int i = 0;
  426.     Boolean fixed_rook = False;
  427.     Boolean fixed_king = False;
  428.     while (i<16)
  429.     {
  430.        Square sq(PiecePos(my_Side,i));
  431.        if (sq == newrooksq)
  432.        {
  433.           my_PiecePos[i][my_Side] = Square::Invalid();
  434.           if (fixed_rook && fixed_king) i++;
  435.        }
  436.        else if (sq == kp)
  437.        {
  438.           my_PiecePos[i][my_Side] = Square::Invalid();
  439.           if (fixed_rook && fixed_king) i++;
  440.        }
  441.        else if (sq == Square::Invalid() && !fixed_rook)
  442.        {
  443.           my_PiecePos[i][my_Side] = oldrooksq;
  444.           fixed_rook = True;
  445.           i++;
  446.        }
  447.        else if (sq == Square::Invalid() && !fixed_king)
  448.        {
  449.           my_PiecePos[i][my_Side] = oldkingsq;
  450.           fixed_king = True;
  451.           i++;
  452.        }
  453.        else
  454.          i++;
  455.     }
  456.     my_attacks.add_attacks(*this,oldkingsq,my_Side);
  457.     my_attacks.add_attacks(*this,oldrooksq,my_Side);
  458.     my_attacks.remove_discovered_attacks(*this,oldkingsq,newrooksq);
  459. }
  460.  
  461. void Board::UndoMove( const ReversibleMove &rmove )
  462. {
  463.     my_Side = OppositeColor(my_Side);
  464.     if (!rmove.IsNull())
  465.     {
  466.  
  467.     const ColorType opp_side = OppositeColor(my_Side);
  468.     int i;
  469.     if (rmove.Special() == ExtendedMove::KCastle)
  470.     {
  471.         Square kp = KingPos(my_Side);
  472.     Square oldrooksq(kp+1);
  473.     Square newrooksq(kp-1);
  474.     Square oldkingsq(kp-2);
  475.     undo_castling(kp,oldkingsq,newrooksq,oldrooksq);
  476.      }
  477.     else if (rmove.Special() == ExtendedMove::QCastle)
  478.     {
  479.         Square kp = KingPos(my_Side);
  480.     Square oldrooksq(kp-2);
  481.     Square newrooksq(kp+1);
  482.     Square oldkingsq(kp+2);
  483.     undo_castling(kp,oldkingsq,newrooksq,oldrooksq);
  484.     }
  485.     else
  486.     {
  487.         // not castling
  488.     my_attacks.remove_attacks(*this,rmove.DestSquare(),my_Side);
  489.     Square target;
  490.     if (!rmove.Capture().IsEmpty())
  491.     {
  492.          if (rmove.Special() == ExtendedMove::EnPassant)
  493.           target = (my_Side == White) ? rmove.DestSquare() + RankIncr :
  494.                              rmove.DestSquare() - RankIncr;
  495.            else
  496.           target = rmove.DestSquare();
  497.     }
  498.     // fix up start square:
  499.     if (rmove.Special() == ExtendedMove::Promotion)
  500.         {
  501.        my_Contents[rmove.StartSquare()] = Piece(Piece::Pawn,my_Side);
  502.        my_PFileCount[rmove.StartSquare().File()-1][my_Side]++;
  503.         }
  504.         else
  505.         {
  506.        if (rmove.Special() != ExtendedMove::EnPassant)
  507.           my_Contents[rmove.StartSquare()] = rmove.PieceMoved();
  508.        switch (rmove.PieceMoved().Type())
  509.        {
  510.        case Piece::Pawn:
  511.           my_PFileCount[rmove.StartSquare().File()-1][my_Side]++;
  512.           my_PFileCount[rmove.DestSquare().File()-1][my_Side]--;
  513.           break;
  514.        case Piece::Rook:
  515.           my_RFileCount[rmove.StartSquare().File()-1][my_Side]++;
  516.           my_RFileCount[rmove.DestSquare().File()-1][my_Side]--;
  517.           break;
  518.        case Piece::King:
  519.           my_KingPos[my_Side] = rmove.StartSquare();
  520.           break;
  521.        default:
  522.           break;
  523.            }
  524.         }
  525.     Boolean start_fix_up = False;
  526.     i = 0; int j = 0;
  527.     while (i<16)
  528.     {
  529.        if ( !start_fix_up && PiecePos(my_Side,i) == Square::Invalid() )
  530.        {
  531.            my_PiecePos[i][my_Side] = rmove.StartSquare();
  532.            start_fix_up = True;
  533.            i++;
  534.        }
  535.        else if (PiecePos(my_Side,i) == rmove.DestSquare())
  536.        {
  537.            my_PiecePos[i][my_Side] = Square::Invalid();
  538.            if (start_fix_up) i++;
  539.            j++;
  540.        }
  541.        else
  542.          i++;
  543.     }
  544.     assert(j>0);
  545.     // fix up dest square
  546.         if (rmove.Special() == ExtendedMove::EnPassant)
  547.     {
  548.        my_Contents[rmove.DestSquare()] = Piece::EmptyPiece();
  549.            my_Contents[target] = Piece(Piece::Pawn,opp_side);
  550.        my_PFileCount[rmove.DestSquare().File()-1][opp_side]++;
  551.        my_Material[opp_side].add_piece(Piece::Pawn);
  552.        for (i = 0; i < 16; i++)
  553.        {
  554.           if( PiecePos(opp_side,i) == Square::Invalid())
  555.           {
  556.                my_PiecePos[i][opp_side] = target;
  557.                break;
  558.           }
  559.        }
  560.        // It tricky fixing up the attacks.  Pretend we
  561.        // made two moves: a capture "sideways" then a
  562.        // pawn move forward, and undo them in reverse order.
  563.            my_attacks.add_attacks(*this,target,opp_side);
  564.            my_attacks.add_discovered_attacks(*this,
  565.            rmove.DestSquare(),target);
  566.            my_attacks.remove_discovered_attacks(
  567.                *this,target,rmove.DestSquare());
  568.  
  569.        my_Contents[rmove.StartSquare()] = rmove.PieceMoved();
  570.  
  571.            my_attacks.add_attacks(*this,rmove.StartSquare(),my_Side);
  572.            my_attacks.remove_discovered_attacks(
  573.                *this,rmove.StartSquare(),target);
  574.     }
  575.     else
  576.     {
  577.        my_Contents[rmove.DestSquare()] = rmove.Capture();
  578.        my_EnPassantSq[opp_side] = Square::Invalid();
  579.        if (rmove.Special() == ExtendedMove::Promotion)
  580.        {
  581.           my_Material[my_Side].add_piece(Piece::Pawn);
  582.           my_Material[my_Side].remove_piece(rmove.PromoteTo());
  583.        }
  584.        if (!rmove.Capture().IsEmpty())
  585.        {
  586.           my_Material[opp_side].add_piece(rmove.Capture().Type());
  587.           for (i = 0; i < 16; i++)
  588.           {
  589.             if( PiecePos(opp_side,i) == Square::Invalid())
  590.             {
  591.                my_PiecePos[i][opp_side] = rmove.DestSquare();
  592.                break;
  593.         }
  594.           }
  595.           if (rmove.Capture().Type() == Piece::Rook)
  596.           {
  597.             my_RFileCount[rmove.DestSquare().File()-1][opp_side]++;
  598.           }
  599.           else if (rmove.Capture().Type() == Piece::Pawn)
  600.           {
  601.             my_PFileCount[rmove.DestSquare().File()-1][opp_side]++;
  602.           }
  603.               my_attacks.add_attacks(*this,rmove.StartSquare(),my_Side);
  604.               my_attacks.add_attacks(*this,target,OppositeColor(my_Side));
  605.               my_attacks.remove_discovered_attacks(
  606.              *this,rmove.StartSquare(),rmove.DestSquare());
  607.        }
  608.          else
  609.         {
  610.            // not a capture move
  611.                my_attacks.add_attacks(*this,rmove.StartSquare(),my_Side);
  612.                my_attacks.add_discovered_attacks(*this,
  613.               rmove.DestSquare(),rmove.StartSquare());
  614.                my_attacks.remove_discovered_attacks(
  615.               *this,rmove.StartSquare(),rmove.DestSquare());
  616.        }
  617.     }
  618.     }
  619.     my_EnPassantSq[my_Side] = rmove.Old_EnPassantSq(my_Side);
  620.     my_EnPassantSq[OppositeColor(my_Side)] = rmove.Old_EnPassantSq(
  621.         OppositeColor(my_Side));
  622.     my_CastleStatus[my_Side] = rmove.Old_CastleStatus(my_Side);
  623.     my_CastleStatus[OppositeColor(my_Side)] = 
  624.         rmove.Old_CastleStatus(OppositeColor(my_Side));
  625.     }
  626.     my_HashCode = rmove.Old_HashCode();
  627. #ifdef DEBUG_ATTACKS
  628.      {
  629.          Attacks new_attacks;
  630.          new_attacks.compute_attacks(*this,White);
  631.          new_attacks.compute_attacks(*this,Black);
  632.      assert (new_attacks == my_attacks);
  633.      }
  634. #endif
  635. }
  636.     
  637. Board::CheckStatusType Board::CheckStatus() const
  638. {
  639.      if (num_attacks(KingPos(Side()),OppositeSide()) > 0)
  640.         return InCheck;
  641.      else
  642.     return NotInCheck;
  643. }
  644.  
  645. static void set_bad( istream &i )
  646. {
  647.     i.clear( ios::badbit | i.rdstate() );
  648. }
  649.  
  650. istream & operator >> (istream &i, Board &board)
  651. {
  652.     // read in a board position in Forsythe-Edwards (FEN) notation.
  653.     static char buf[128];
  654.  
  655.     for (int j=0;j<BoardSize;j++)
  656.     {
  657.        board.my_Contents[j] = Piece::EmptyPiece();
  658.     }
  659.  
  660.     i.getline(buf,128);
  661.     if (!i)
  662.       return i;
  663.  
  664.     Square sq;
  665.     char *bp = buf;
  666.     char c;
  667.     while (isspace(*bp)) bp++;
  668.     for (int line = 0; line < 8; line++)
  669.     {
  670.        int sqval = line*RankIncr;
  671.        while ((c = *bp) != ' ' && c != '/')
  672.        {
  673.       Piece piece;
  674.       if (isdigit(c))
  675.       {
  676.          sqval += (*bp - '0');
  677.          bp++;
  678.       }
  679.           else if (isalnum(c))
  680.       {
  681.          if (!Square(sqval).OnBoard())
  682.          {
  683.             set_bad(i);
  684.         return i;
  685.          }
  686.          switch(c)
  687.          {
  688.          case 'p': piece = Piece(Piece::Pawn,Black); 
  689.                     break;
  690.          case 'n': piece = Piece(Piece::Knight,Black);
  691.                        break;
  692.          case 'b': piece = Piece(Piece::Bishop,Black);
  693.                    break;
  694.          case 'r': piece = Piece(Piece::Rook,Black);
  695.                     break;
  696.          case 'q': piece = Piece(Piece::Queen,Black); 
  697.                     break;
  698.          case 'k': piece = Piece(Piece::King,Black);
  699.                     break;
  700.          case 'P': piece = Piece(Piece::Pawn,White);
  701.                     break;
  702.          case 'N': piece = Piece(Piece::Knight,White);
  703.                    break;
  704.          case 'B': piece = Piece(Piece::Bishop,White);
  705.                    break;
  706.          case 'R': piece = Piece(Piece::Rook,White);
  707.                        break;
  708.          case 'Q': piece = Piece(Piece::Queen,White);
  709.                        break;
  710.          case 'K': piece = Piece(Piece::King,White);
  711.                        break;
  712.          default:
  713.             set_bad(i);
  714.         return i;
  715.          }
  716.          board.my_Contents[sqval] = piece;
  717.          sqval++;
  718.          bp++;
  719.       }
  720.       else // not a letter or a digit
  721.       {
  722.          set_bad(i);
  723.          return i;
  724.       }
  725.        }
  726.        if (c=='/') ++bp;  // skip delimiter
  727.     }
  728.     while (isspace(*bp)) bp++;
  729.     ColorType side;
  730.     if (toupper(*bp) == 'W')
  731.        board.my_Side = White;
  732.     else if (toupper(*bp) == 'B')
  733.        board.my_Side = Black;
  734.     else
  735.     {
  736.        set_bad(i);
  737.        return i;
  738.     }
  739.     bp++;
  740.     while (isspace(*bp)) bp++;
  741.     c = *bp;
  742.     if (c == '-')
  743.     {
  744.        board.my_CastleStatus[White] = 
  745.        board.my_CastleStatus[Black] = Board::CantCastleEitherSide;
  746.        bp++;
  747.     }
  748.     else
  749.     {
  750.        int k = 0;
  751.        for (; !isspace(*bp); bp++)
  752.        {
  753.           if (*bp == 'K')
  754.          k += 1;
  755.       else if (*bp == 'Q')
  756.          k += 2;
  757.       else if (*bp == 'k')
  758.          k += 4;
  759.       else if (*bp == 'q')
  760.          k += 8;
  761.       else
  762.       {
  763.          set_bad(i);
  764.          return i;
  765.       }
  766.        }
  767.        static Board::CastleType vals[4] = 
  768.           { Board::CantCastleEitherSide, Board::CanCastleKSide,
  769.                Board::CanCastleQSide, Board::CanCastleEitherSide };
  770.        board.my_CastleStatus[White] = vals[k % 4];
  771.        board.my_CastleStatus[Black] = vals[k / 4];
  772.     }
  773.     while (isspace(*bp)) bp++;
  774.     c = *bp;
  775.     if (c == '-')
  776.     {
  777.        board.my_EnPassantSq[White].SetInvalid();
  778.        board.my_EnPassantSq[Black].SetInvalid();
  779.     }
  780.     else if (isalpha(c))
  781.     {
  782.        char sqbuf[2];
  783.        sqbuf[0] = *bp++;
  784.        sqbuf[1] = *bp++;
  785.        Square epsq = Square::Value(sqbuf);
  786.        if (epsq.IsInvalid())
  787.        {
  788.           set_bad(i);
  789.       return i;
  790.        }
  791.        board.my_EnPassantSq[board.Side()].SetInvalid();
  792.        board.my_EnPassantSq[board.OppositeSide()] = 
  793.                Square::Value(sqbuf) - (RankIncr * Direction[board.Side()]);
  794.     }
  795.     else
  796.     {
  797.         set_bad(i);
  798.     return i;
  799.     }
  800.     board.set_secondary_vars();
  801.     return i;
  802. }
  803.  
  804. ostream & operator << (ostream &o, Board &board)
  805. {
  806.     // write out the board in Forsythe-Edwards (FEN) notation.
  807.     for (int i=1;i<=8;i++)
  808.     {
  809.       int j = 1;
  810.       while (j <= 8)
  811.       {
  812.      int n = 0;
  813.      Square sq;
  814.      Piece p;
  815.      do
  816.      {
  817.             sq = Square(j,i,Black);
  818.         p = board.my_Contents[sq];
  819.         if (!p.IsEmpty())
  820.             break;
  821.         ++j; ++n;
  822.      } while (j <= 8);
  823.      if (n)
  824.         o << (char)(n + '0');
  825.      if (!p.IsEmpty())
  826.      {
  827.         char img = Piece::Image(p.Type());
  828.         if (p.Color() == Black) img = tolower(img);
  829.         o << img;
  830.         j++;
  831.      }
  832.       }
  833.       if (i != 8) o << '/';
  834.     }
  835.     if (board.Side() == White)
  836.        o << " w";
  837.     else
  838.        o << " b";
  839.  
  840.     // used in I/O of castling data:
  841.     const Boolean kcastle[6] = { True, True, False, False, False, False };
  842.     const Boolean qcastle[6] = { True, False, True, False, False, False };
  843.  
  844.     // note : unfortunately FEN doesn't allow recording if castling
  845.     // has taken place, only whether or not it is possible.
  846.     Board::CastleType wcs = board.CastleStatus(White);
  847.     Board::CastleType bcs = board.CastleStatus(Black);
  848.     o << ' ';
  849.     if (!kcastle[(int)wcs] && !qcastle[(int)bcs])
  850.        o << '-';
  851.     else
  852.     {
  853.        if (kcastle[(int)wcs])
  854.           o << 'K';
  855.        if (qcastle[(int)wcs])
  856.           o << 'Q';
  857.        if (kcastle[(int)bcs])
  858.           o << 'k';
  859.        if (qcastle[(int)bcs])
  860.           o << 'q';
  861.     }
  862.     o << ' ';
  863.     Square epsq(board.EnPassantSq(board.OppositeSide()));
  864.     if (epsq.IsInvalid())
  865.        o << '-';
  866.     else
  867.     {
  868.        // FEN stores the destination square for an en passant capture;
  869.        // we store the location of the capturable pawn.
  870.        Square target(epsq + (RankIncr * Direction[board.Side()]));
  871.        o << target.FileImage() << target.RankImage();
  872.     }
  873.     // FEN is supposed to include the halfmove and fullmove numbers,
  874.     // but these are attributes of the game - they are not stored in
  875.     // the board.
  876.     o << " 0 1";
  877.     o << endl;
  878.     return o;
  879. }
  880.  
  881.