//  GREKO Chess Engine
//  (c) 2002-2011 Vladimir Medvedev <vrm@bk.ru>
//  http://greko.110mb.com

//  position.h: position and game representation
//  modified: 1-Aug-2011

#ifndef POSITION_H
#define POSITION_H

#include "bitboards.h"

inline int   Col(FLD f) { return (f % 8); }
inline int   Row(FLD f) { return (f / 8); }
inline COLOR GetColor(PIECE p) { return (p & 1); }
inline COLOR Opp(COLOR side) { return (side ^ 1); }

class Move
{
public:

  Move() : m_data(0) {}
  Move(U32 x) : m_data(x) {}
  Move(FLD from, FLD to, PIECE piece) : 
    m_data(U32(from) | 
    (U32(to) << 6) | 
    (U32(piece) << 12)) {}
  Move(FLD from, FLD to, PIECE piece, PIECE captured) : 
    m_data(U32(from) | 
    (U32(to) << 6) | 
    (U32(piece) << 12) |
    (U32(captured) << 16)) {}
  Move(FLD from, FLD to, PIECE piece, PIECE captured, PIECE promotion) : 
    m_data(U32(from) | 
    (U32(to) << 6) | 
    (U32(piece) << 12) |
    (U32(captured) << 16) |
    (U32(promotion) << 20)) {}

  FLD From() const { return m_data & 0x3f; }
  FLD To() const { return (m_data >> 6) & 0x3f; }
  FLD Piece() const { return (m_data >> 12) & 0x0f; }
  FLD Captured() const { return (m_data >> 16) & 0x0f; }
  FLD Promotion() const { return (m_data >> 20) & 0x0f; }

  operator U32() const { return m_data; }

private:

  U32 m_data;
};
////////////////////////////////////////////////////////////////////////////////

class Position
{
public:

  PIECE operator[] (FLD f) const { return m_board[f]; }

  U64   Bits(PIECE p) const { return m_bits[p]; }
  U64   BitsAll(COLOR side) const { return m_bitsAll[side]; }
  U64   BitsAll() const { return m_bitsAll[WHITE] | m_bitsAll[BLACK]; }
  U8    Castlings() const { return m_castlings; }
  int   Count(PIECE p) const { return m_count[p]; }
  FLD   EP() const { return m_ep; }
  int   Fifty() const { return m_fifty; }
  bool  GameOver(char* comment) const;
  U64   GetAttacks(FLD to, COLOR side, U64 occupied) const;
  int   GetRepetitions() const;
  char* FEN(char* buf) const;
  U64   Hash() const { return m_hash ^ m_castlings ^ m_ep; }
  static void InitHashNumbers();
  bool  InCheck() const { return IsAttacked(King(Side()), Side() ^ 1); }
  bool  IsAttacked(FLD to, COLOR side) const;
  bool  IsDraw() const;
  FLD   King(COLOR side) const { return m_Kings[side]; }
  EVAL  Material(COLOR side) const { return m_material[side]; }
  int   MatIndex(COLOR side) const { return m_matIndex[side]; }
  U32   PawnHash() const { return m_hashPawn; }
  int   Ply() const { return m_ply; }
  void  Print() const;
  bool  SetFEN(const char* fen);
  void  SetInitial() { SetFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); }
  COLOR Side() const { return m_side; }

  bool MakeMove(Move mv);
  void MakeNullMove();
  void Mirror();
  void UnmakeMove();
  void UnmakeNullMove();

private:

  void Clear();
  void PutPiece(FLD f, PIECE p);
  void RemovePiece(FLD f);

  U64   m_bits[14];
  U64   m_bitsAll[2];
  PIECE m_board[64];
  U8    m_castlings;
  int   m_count[14];
  FLD   m_ep;
  int   m_fifty;
  U64   m_hash;
  U32   m_hashPawn;
  FLD   m_Kings[2];
  EVAL  m_material[2];
  int   m_matIndex[2];
  int   m_ply;
  COLOR m_side;

  struct Undo
  {
    U8   m_castlings;
    FLD  m_ep;
    int  m_fifty;
    U64  m_hash;
    Move m_mv;
  };

  enum { MAX_UNDO = 600 };
  Undo m_undos[MAX_UNDO];
  int  m_undoCnt; 

  static U64 s_Zobrist0;
  static U64 s_Zobrist[64][14];
  static U32 s_ZobristPawn[64][14];
};
////////////////////////////////////////////////////////////////////////////////

static const int DELTA[14] =
{ 0, 0, 0, 0, 3, 3, 3, 3, 5, 5, 10, 10, 0, 0 };

inline void Position::PutPiece(FLD f, PIECE p)
{
  assert(f <= H1);
  assert(p != NOPIECE);
  assert(m_board[f] == NOPIECE);

  m_board[f] = p;

  m_bits[p] ^= BB_SINGLE[f];
  m_bitsAll[GetColor(p)] ^= BB_SINGLE[f];

  m_hash ^= s_Zobrist[f][p];
  m_hashPawn ^= s_ZobristPawn[f][p];

  m_matIndex[GetColor(p)] += DELTA[p];
}
////////////////////////////////////////////////////////////////////////////////

inline void Position::RemovePiece(FLD f)
{
  assert(f <= H1);
  PIECE p = m_board[f];
  assert(p != NOPIECE);

  m_board[f] = NOPIECE;

  m_bits[p] ^= BB_SINGLE[f];
  m_bitsAll[GetColor(p)] ^= BB_SINGLE[f];

  m_hash ^= s_Zobrist[f][p];
  m_hashPawn ^= s_ZobristPawn[f][p];

  m_matIndex[GetColor(p)] -= DELTA[p];
}
////////////////////////////////////////////////////////////////////////////////

const FLD FLIP[64] =
{
  A1, B1, C1, D1, E1, F1, G1, H1,
  A2, B2, C2, D2, E2, F2, G2, H2,
  A3, B3, C3, D3, E3, F3, G3, H3,
  A4, B4, C4, D4, E4, F4, G4, H4,
  A5, B5, C5, D5, E5, F5, G5, H5,
  A6, B6, C6, D6, E6, F6, G6, H6,
  A7, B7, C7, D7, E7, F7, G7, H7,
  A8, B8, C8, D8, E8, F8, G8, H8
};

#endif

