// Copyright 1994 by Jon Dart.  All Rights Reserved.

#ifndef _BOARD_H
#define _BOARD_H

#include "types.h"
#include "square.h"
#include "piece.h"
#include "attacks.h"
#include "bitmap.h"
#include "material.h"
#include <iostream.h>

class ExtendedMove;
class ReversibleMove;

class Board
{
   // This class encapsulates the chess board, and provides functions
   // for making and undoing moves.          

public: 

   friend class ReversibleMove;
   friend class ChessIO;
   
   enum CheckStatusType { InCheck, NotInCheck };

   enum CastleType { CanCastleEitherSide,
                     CanCastleKSide,
                     CanCastleQSide,
                     CastledKSide,
                     CastledQSide,
                     CantCastleEitherSide};
          
   Board();
   // returns a board set up in its initial position, White to move.
           
  ~Board();

   void Reset();
   // resets it to initial position
           
#ifdef _DEBUG
   const Piece &operator[]( const Square sq ) const;
#else
   const Piece &operator[]( const Square sq ) const
   {
       return my_Contents[sq];
   }
#endif

   void Set_Contents( const Piece &p, const Square sq )
   {
       my_Contents[sq] = p;
   }
   
   CastleType CastleStatus( const ColorType side ) const
   {
       return my_CastleStatus[side];        
   }
   
   void Set_CastleStatus( const CastleType t, const ColorType side )
   {
       my_CastleStatus[side] = t;
   }

   ColorType Side() const
   // side to move         
   {
       return my_Side;       
   }
   
   ColorType OppositeSide() const
   {
       return OppositeColor(my_Side);
   }
   
   void Set_Side( const ColorType side )
   {
       my_Side = side;
   }
   
   const Square& PiecePos( const ColorType side, const int i ) const
   {
       ASSERT((i>=0) && (i<16));
       return my_PiecePos[i][side];
   }
   
   const Material &getMaterial( const ColorType side ) const
   {
       return my_Material[side];
   }
   
   const Bitmap &PawnBits( const ColorType side ) const
   {
       return pawn_bits[side];
   }
   
   byte PFileCount( const int rank, const ColorType side ) const
   {
       return my_PFileCount[rank][side];
   }

   byte RFileCount( const int rank, const ColorType side ) const
   {
       return my_RFileCount[rank][side];
   }

   const Square EnPassantSq( const ColorType side ) const
   {
       return my_EnPassantSq[side];     
   }
           
   void Set_EnPassantSq( const Square sq, const ColorType side )
   {
       my_EnPassantSq[side] = sq;
   }
           
   CheckStatusType CheckStatus( ) const;

   const Square &KingPos( const ColorType side ) const
   {
        return my_KingPos[side];           
   }
           
   hash_t HashCode() const
   {
       return my_HashCode;
   }
   
   int operator == ( const Board &ABoard )
   {
       return my_HashCode == ABoard.HashCode();
   }
   
   int Direction( const Square &sq1, const Square &sq2 ) const;
   // If sq1 and sq2 are in a straight line, return its direction
   // (increment by which a piece at sq1 could move to sq2).  Other-
   // wise, return 0.      
   
   int Between( const Square &sq1, const Square &sq2, 
                Square *squares) const;
   // fills "squares" with a list of squares between sq1 and sq2 (in
   // a straight line), returns the # of squares.
   
   BOOL Clear( const Square &sq1, const Square &sq2 ) const;
   // returns "true" if there is a clear path between sq1 and sq2

   void MakeMove( const ExtendedMove &move );
   // makes a move

   void UndoMove( const ReversibleMove &rmove );
   // undoes a previous move.
           
   unsigned num_attacks( const Square &sq, const ColorType side) const
   {
       return my_attacks.num_attacks(sq,side);
   }
           
   const Attack_Entry &get_attacks( const Square sq, const ColorType side ) const
   { 
        return my_attacks.get_attacks(sq,side);
   }

   unsigned pawn_attacks( const Square &sq, const ColorType side) const
   {
       return my_attacks.pawn_attacks(sq,side);
   }
           
   friend istream & operator >> (istream &i, Board &board);
   friend ostream & operator << (ostream &o, Board &board);

#if !defined(_WINDOWS) && defined(DEBUG_ATTACKS)
   // for debugging :
   void dump_attacks()
   {
       my_attacks.dump_attacks();           
   }
#endif   
   
   private:
           
   Piece my_Contents[64];
   ColorType my_Side;
   Square my_PiecePos[16][2];
   Square my_KingPos[2];
   Material my_Material[2];
   byte my_PFileCount[10][2];
   byte my_RFileCount[10][2];
   Square my_EnPassantSq[2];
   CastleType my_CastleStatus[2];
   hash_t my_HashCode;
   Attacks my_attacks;
   Bitmap pawn_bits[2];
   
   void set_secondary_vars();
   // update all fields of the board, based on the piece positions.

   void UpdateCastleStatus( const ColorType side, 
                            const Square sq );
   void undo_castling(const Square &kp,const Square &oldkingsq,
           const Square &newrooksq, const Square &oldrooksq);
};
  
#endif

