/*
 
    Texel - A UCI chess engine.
 
    Copyright (C) 2012-2014  Peter Ă–sterlund, peterosterlund2@gmail.com
 
 
 
    This program is free software: you can redistribute it and/or modify
 
    it under the terms of the GNU General Public License as published by
 
    the Free Software Foundation, either version 3 of the License, or
 
    (at your option) any later version.
 
 
 
    This program is distributed in the hope that it will be useful,
 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
    GNU General Public License for more details.
 
 
 
    You should have received a copy of the GNU General Public License
 
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 
 
 
/*
 
 * position.hpp
 
 *
 
 *  Created on: Feb 25, 2012
 
 *      Author: petero
 
 */
 
 
 
#ifndef POSITION_HPP_
 
#define POSITION_HPP_
 
 
 
#include <iosfwd>
 
 
 
#include "move.hpp"
 
#include "undoInfo.hpp"
 
#include "bitBoard.hpp"
 
#include "piece.hpp"
 
#include "material.hpp"
 
#include <algorithm>
 
#include <iostream>
 
 
 
/**
 
 * Stores the state of a chess position.
 
 * All required state is stored, except for all previous positions
 
 * since the last capture or pawn move. That state is only needed
 
 * for three-fold repetition draw detection, and is better stored
 
 * in a separate hash table.
 
 */
 
class Position {
 
public:
 
    /** Bit definitions for the castleMask bit mask. */
 
    static const int A1_CASTLE = 0; /** White long castle. */
 
    static const int H1_CASTLE = 1; /** White short castle. */
 
    static const int A8_CASTLE = 2; /** Black long castle. */
 
    static const int H8_CASTLE = 3; /** Black short castle. */
 
 
 
    /** Initialize board to empty position. */
 
    Position();
 
 
 
    bool equals(const Position& other) const;
 
 
 
    /**
 
     * Return Zobrist hash value for the current position.
 
     * Everything except the move counters are included in the hash value.
 
     */
 
    U64 zobristHash() const;
 
    U64 pawnZobristHash() const;
 
    U64 kingZobristHash() const;
 
 
 
    /** Zobrist hash including the halfMove clock.
 
     *  Only large halfMove clock values affect the hash. */
 
    U64 historyHash() const;
 
    /** Hash including halfMoveClock, to avoid opening book cycles. */
 
    U64 bookHash() const;
 
 
 
    /** Compute zobrist hash for position after "move" has been made.
 
     * May be incorrect in some cases, intended for prefetch. */
 
    U64 hashAfterMove(const Move& move) const;
 
 
 
    /** Return the material identifier. */
 
    int materialId() const;
 
 
 
    /**
 
     * Decide if two positions are equal in the sense of the draw by repetition rule.
 
     * @return True if positions are equal, false otherwise.
 
     */
 
    bool drawRuleEquals(Position other) const;
 
 
 
    bool isWhiteMove() const;
 
 
 
    void setWhiteMove(bool whiteMove);
 
 
 
    /** Return piece occupying a square. */
 
    int getPiece(int square) const;
 
 
 
    /** Set a square to a piece value. */
 
    void setPiece(int square, int piece);
 
 
 
    /**
 
     * Set a square to a piece value.
 
     * Special version that only updates enough of the state for the SEE function to be happy.
 
     */
 
    void setSEEPiece(int square, int piece);
 
 
 
    /** Return true if white long castling right has not been lost. */
 
    bool a1Castle() const;
 
 
 
    /** Return true if white short castling right has not been lost. */
 
    bool h1Castle() const;
 
 
 
    /** Return true if black long castling right has not been lost. */
 
    bool a8Castle() const;
 
 
 
    /** Return true if black short castling right has not been lost. */
 
    bool h8Castle() const;
 
 
 
    /** Bitmask describing castling rights. */
 
    int getCastleMask() const;
 
    void setCastleMask(int castleMask);
 
 
 
    /** En passant square, or -1 if no en passant possible. */
 
    int getEpSquare() const;
 
 
 
    void setEpSquare(int epSquare);
 
 
 
    int getKingSq(bool white) const;
 
 
 
    /** Apply a move to the current position. */
 
    void makeMove(const Move& move, UndoInfo& ui);
 
 
 
    void unMakeMove(const Move& move, const UndoInfo& ui);
 
 
 
    /** Special make move functions used by MoveGen::isLegal(). Does not update all data members. */
 
    void makeMoveB(const Move& move, UndoInfo& ui);
 
    void unMakeMoveB(const Move& move, const UndoInfo& ui);
 
    void setPieceB(int square, int piece);
 
 
 
    /**
 
     * Apply a move to the current position.
 
     * Special version that only updates enough of the state for the SEE function to be happy.
 
     */
 
    void makeSEEMove(const Move& move, UndoInfo& ui);
 
 
 
    void unMakeSEEMove(const Move& move, const UndoInfo& ui);
 
 
 
    int getFullMoveCounter() const;
 
    void setFullMoveCounter(int fm);
 
    int getHalfMoveClock() const;
 
    void setHalfMoveClock(int hm);
 
 
 
    /** Return incrementally updated piece square table score for middle game and endgame. */
 
    int psScore1(int piece) const;
 
    int psScore2(int piece) const;
 
 
 
    /** BitBoard for all squares occupied by a piece type. */
 
    U64 pieceTypeBB(Piece::Type piece) const;
 
    /** BitBoard for all squares occupied by several piece types. */
 
    template <typename Piece0, typename... Pieces> U64 pieceTypeBB(Piece0 piece0, Pieces... pieces) const;
 
 
 
    /** BitBoard for all squares occupied by white pieces. */
 
    U64 whiteBB() const;
 
    /** BitBoard for all squares occupied by black pieces. */
 
    U64 blackBB() const;
 
    /** BitBoard for all squares occupied by white or black pieces. */
 
    U64 colorBB(int wtm) const;
 
 
 
    /** BitBoard for all squares occupied by white and black pieces. */
 
    U64 occupiedBB() const;
 
 
 
    int wKingSq() const;
 
    int bKingSq() const;
 
 
 
    /** Total white/black material value. */
 
    int wMtrl() const;
 
    int bMtrl() const;
 
    /** White/black material value for all pawns. */
 
    int wMtrlPawns() const;
 
    int bMtrlPawns() const;
 
 
 
 
 
    /** Return index in squares[] vector corresponding to (x,y). */
 
    static int getSquare(int x, int y);
 
 
 
    /** Return x position (file) corresponding to a square. */
 
    static int getX(int square);
 
 
 
    /** Return y position (rank) corresponding to a square. */
 
    static int getY(int square);
 
 
 
    /** Return getSquare(getX(square),7-getY(square)). */
 
    static int mirrorY(int square);
 
 
 
    /** Return true if (x,y) is a dark square. */
 
    static bool darkSquare(int x, int y);
 
 
 
    /** Compute the Zobrist hash value non-incrementally. Only useful for testing. */
 
    U64 computeZobristHash();
 
 
 
    /** Initialize static data. */
 
    static void staticInitialize();
 
 
 
    /** Get hash key for a piece at a square. */
 
    static U64 getHashKey(int piece, int square);
 
 
 
 
 
    /** Serialization. Used by tree logging code. */
 
    struct SerializeData {
 
        U64 v[5];
 
    };
 
    void serialize(SerializeData& data) const;
 
    void deSerialize(const SerializeData& data);
 
 
 
private:
 
    /** Move a non-pawn piece to an empty square. */
 
    void movePieceNotPawn(int from, int to);
 
    void movePieceNotPawnB(int from, int to);
 
 
 
    void removeCastleRights(int square);
 
 
 
    static U64 getRandomHashVal(int rndNo);
 
 
 
 
 
    int wKingSq_, bKingSq_;  // Cached king positions
 
    int wMtrl_;              // Total value of all white pieces and pawns
 
    int bMtrl_;              // Total value of all black pieces and pawns
 
    int wMtrlPawns_;         // Total value of all white pawns
 
    int bMtrlPawns_;         // Total value of all black pawns
 
 
 
    int squares[64];
 
 
 
    // Piece square table scores
 
    short psScore1_[Piece::nPieceTypes];
 
    short psScore2_[Piece::nPieceTypes];
 
 
 
    // Bitboards
 
    U64 pieceTypeBB_[Piece::nPieceTypes];
 
    U64 whiteBB_, blackBB_;
 
 
 
    bool whiteMove;
 
 
 
    /** Number of half-moves since last 50-move reset. */
 
    int halfMoveClock;
 
 
 
    /** Game move number, starting from 1. */
 
    int fullMoveCounter;
 
 
 
    int castleMask;
 
    int epSquare;
 
 
 
    U64 hashKey;           // Cached Zobrist hash key
 
    U64 pHashKey;          // Cached Zobrist pawn hash key
 
    MatId matId;           // Cached material identifier
 
 
 
    static U64 psHashKeys[Piece::nPieceTypes][64];    // [piece][square]
 
 
 
    static U64 whiteHashKey;
 
    static U64 castleHashKeys[16];   // [castleMask]
 
    static U64 epHashKeys[9];        // [epFile + 1] (epFile==-1 for no ep)
 
    static U64 moveCntKeys[101];     // [min(halfMoveClock, 100)]
 
 
 
    static const U64 zobristRndKeys[];
 
};
 
 
 
/** For debugging. */
 
std::ostream& operator<<(std::ostream& os, const Position& pos);
 
 
 
inline bool
 
Position::equals(const Position& other) const {
 
    if (!drawRuleEquals(other))
 
        return false;
 
    if (halfMoveClock != other.halfMoveClock)
 
        return false;
 
    if (fullMoveCounter != other.fullMoveCounter)
 
        return false;
 
    if (hashKey != other.hashKey)
 
        return false;
 
    if (pHashKey != other.pHashKey)
 
        return false;
 
    if (matId() != other.matId())
 
        return false;
 
    return true;
 
}
 
 
 
inline U64
 
Position::zobristHash() const {
 
    return hashKey;
 
}
 
 
 
inline U64
 
Position::pawnZobristHash() const {
 
    return pHashKey;
 
}
 
 
 
inline U64
 
Position::kingZobristHash() const {
 
    return psHashKeys[Piece::WKING][wKingSq()] ^
 
           psHashKeys[Piece::BKING][bKingSq()];
 
}
 
 
 
inline U64
 
Position::historyHash() const {
 
    U64 ret = hashKey;
 
    if (halfMoveClock >= 40) {
 
        if (halfMoveClock < 80)
 
            ret ^= moveCntKeys[halfMoveClock / 10];
 
        else
 
            ret ^= moveCntKeys[std::min(halfMoveClock, 100)];
 
    }
 
    return ret;
 
}
 
 
 
inline U64
 
Position::bookHash() const {
 
    U64 ret = hashKey;
 
    ret ^= moveCntKeys[std::min(halfMoveClock, 100)];
 
    return ret;
 
}
 
 
 
inline int
 
Position::materialId() const {
 
    return matId();
 
}
 
 
 
inline bool
 
Position::drawRuleEquals(Position other) const {
 
    for (int i = 0; i < 64; i++)
 
        if (squares[i] != other.squares[i])
 
            return false;
 
    if (whiteMove != other.whiteMove)
 
        return false;
 
    if (castleMask != other.castleMask)
 
        return false;
 
    if (epSquare != other.epSquare)
 
        return false;
 
    return true;
 
}
 
 
 
inline bool
 
Position::isWhiteMove() const {
 
    return whiteMove;
 
}
 
 
 
inline void
 
Position::setWhiteMove(bool whiteMove) {
 
    if (whiteMove != this->whiteMove) {
 
        hashKey ^= whiteHashKey;
 
        this->whiteMove = whiteMove;
 
    }
 
}
 
 
 
inline int
 
Position::getPiece(int square) const {
 
    return squares[square];
 
}
 
 
 
inline void
 
Position::setSEEPiece(int square, int piece) {
 
    int removedPiece = squares[square];
 
 
 
    // Update board
 
    squares[square] = piece;
 
 
 
    // Update bitboards
 
    U64 sqMask = 1ULL << square;
 
    pieceTypeBB_[removedPiece] &= ~sqMask;
 
    pieceTypeBB_[piece] |= sqMask;
 
    if (removedPiece != Piece::EMPTY) {
 
        if (Piece::isWhite(removedPiece))
 
            whiteBB_ &= ~sqMask;
 
        else
 
            blackBB_ &= ~sqMask;
 
    }
 
    if (piece != Piece::EMPTY) {
 
        if (Piece::isWhite(piece))
 
            whiteBB_ |= sqMask;
 
        else
 
            blackBB_ |= sqMask;
 
    }
 
}
 
 
 
inline bool
 
Position::a1Castle() const {
 
    return (castleMask & (1 << A1_CASTLE)) != 0;
 
}
 
 
 
inline bool
 
Position::h1Castle() const {
 
    return (castleMask & (1 << H1_CASTLE)) != 0;
 
}
 
 
 
inline bool
 
Position::a8Castle() const {
 
    return (castleMask & (1 << A8_CASTLE)) != 0;
 
}
 
 
 
inline bool
 
Position::h8Castle() const {
 
    return (castleMask & (1 << H8_CASTLE)) != 0;
 
}
 
 
 
inline int
 
Position::getCastleMask() const {
 
    return castleMask;
 
}
 
 
 
inline void
 
Position::setCastleMask(int castleMask) {
 
    hashKey ^= castleHashKeys[this->castleMask];
 
    hashKey ^= castleHashKeys[castleMask];
 
    this->castleMask = castleMask;
 
}
 
 
 
inline int
 
Position::getEpSquare() const {
 
    return epSquare;
 
}
 
 
 
inline void
 
Position::setEpSquare(int epSquare) {
 
    if (this->epSquare != epSquare) {
 
        hashKey ^= epHashKeys[(this->epSquare >= 0) ? getX(this->epSquare) + 1 : 0];
 
        hashKey ^= epHashKeys[(epSquare >= 0) ? getX(epSquare) + 1 : 0];
 
        this->epSquare = epSquare;
 
    }
 
}
 
 
 
inline int
 
Position::getKingSq(bool white) const {
 
    return white ? wKingSq() : bKingSq();
 
}
 
 
 
inline void
 
Position::unMakeMove(const Move& move, const UndoInfo& ui) {
 
    hashKey ^= whiteHashKey;
 
    whiteMove = !whiteMove;
 
    int p = squares[move.to()];
 
    setPiece(move.from(), p);
 
    setPiece(move.to(), ui.capturedPiece);
 
    setCastleMask(ui.castleMask);
 
    setEpSquare(ui.epSquare);
 
    halfMoveClock = ui.halfMoveClock;
 
    bool wtm = whiteMove;
 
    if (move.promoteTo() != Piece::EMPTY) {
 
        p = wtm ? Piece::WPAWN : Piece::BPAWN;
 
        setPiece(move.from(), p);
 
    }
 
    if (!wtm)
 
        fullMoveCounter--;
 
 
 
    // Handle castling
 
    int king = wtm ? Piece::WKING : Piece::BKING;
 
    if (p == king) {
 
        int k0 = move.from();
 
        if (move.to() == k0 + 2) { // O-O
 
            movePieceNotPawn(k0 + 1, k0 + 3);
 
        } else if (move.to() == k0 - 2) { // O-O-O
 
            movePieceNotPawn(k0 - 1, k0 - 4);
 
        }
 
    }
 
 
 
    // Handle en passant
 
    if (move.to() == epSquare) {
 
        if (p == Piece::WPAWN) {
 
            setPiece(move.to() - 8, Piece::BPAWN);
 
        } else if (p == Piece::BPAWN) {
 
            setPiece(move.to() + 8, Piece::WPAWN);
 
        }
 
    }
 
}
 
 
 
inline void
 
Position::unMakeMoveB(const Move& move, const UndoInfo& ui) {
 
    int p = squares[move.to()];
 
    setPieceB(move.from(), p);
 
    setPieceB(move.to(), ui.capturedPiece);
 
    bool wtm = whiteMove;
 
    if (move.promoteTo() != Piece::EMPTY) {
 
        p = wtm ? Piece::WPAWN : Piece::BPAWN;
 
        setPieceB(move.from(), p);
 
    }
 
 
 
    // Handle castling
 
    int king = wtm ? Piece::WKING : Piece::BKING;
 
    if (p == king) {
 
        int k0 = move.from();
 
        if (move.to() == k0 + 2) { // O-O
 
            movePieceNotPawnB(k0 + 1, k0 + 3);
 
        } else if (move.to() == k0 - 2) { // O-O-O
 
            movePieceNotPawnB(k0 - 1, k0 - 4);
 
        }
 
    }
 
 
 
    // Handle en passant
 
    if (move.to() == epSquare) {
 
        if (p == Piece::WPAWN) {
 
            setPieceB(move.to() - 8, Piece::BPAWN);
 
        } else if (p == Piece::BPAWN) {
 
            setPieceB(move.to() + 8, Piece::WPAWN);
 
        }
 
    }
 
}
 
 
 
inline void
 
Position::setPieceB(int square, int piece) {
 
    int removedPiece = squares[square];
 
    squares[square] = piece;
 
 
 
    // Update bitboards
 
    const U64 sqMask = 1ULL << square;
 
    pieceTypeBB_[removedPiece] &= ~sqMask;
 
    pieceTypeBB_[piece] |= sqMask;
 
 
 
    if (removedPiece != Piece::EMPTY) {
 
        if (Piece::isWhite(removedPiece))
 
            whiteBB_ &= ~sqMask;
 
        else
 
            blackBB_ &= ~sqMask;
 
    }
 
 
 
    if (piece != Piece::EMPTY) {
 
        if (Piece::isWhite(piece)) {
 
            whiteBB_ |= sqMask;
 
            if (piece == Piece::WKING)
 
                wKingSq_ = square;
 
        } else {
 
            blackBB_ |= sqMask;
 
            if (piece == Piece::BKING)
 
                bKingSq_ = square;
 
        }
 
    }
 
}
 
 
 
inline void
 
Position::movePieceNotPawnB(int from, int to) {
 
    const int piece = squares[from];
 
 
 
    squares[from] = Piece::EMPTY;
 
    squares[to] = piece;
 
 
 
    const U64 sqMaskF = 1ULL << from;
 
    const U64 sqMaskT = 1ULL << to;
 
    pieceTypeBB_[piece] &= ~sqMaskF;
 
    pieceTypeBB_[piece] |= sqMaskT;
 
    if (Piece::isWhite(piece)) {
 
        whiteBB_ &= ~sqMaskF;
 
        whiteBB_ |= sqMaskT;
 
        if (piece == Piece::WKING)
 
            wKingSq_ = to;
 
    } else {
 
        blackBB_ &= ~sqMaskF;
 
        blackBB_ |= sqMaskT;
 
        if (piece == Piece::BKING)
 
            bKingSq_ = to;
 
    }
 
}
 
 
 
inline void
 
Position::makeSEEMove(const Move& move, UndoInfo& ui) {
 
    ui.capturedPiece = squares[move.to()];
 
    int p = squares[move.from()];
 
 
 
    // Handle en passant
 
    if (move.to() == epSquare) {
 
        if (p == Piece::WPAWN) {
 
            setSEEPiece(move.to() - 8, Piece::EMPTY);
 
        } else if (p == Piece::BPAWN) {
 
            setSEEPiece(move.to() + 8, Piece::EMPTY);
 
        }
 
    }
 
 
 
    // Perform move
 
    setSEEPiece(move.from(), Piece::EMPTY);
 
    setSEEPiece(move.to(), p);
 
    whiteMove = !whiteMove;
 
}
 
 
 
inline void
 
Position::unMakeSEEMove(const Move& move, const UndoInfo& ui) {
 
    whiteMove = !whiteMove;
 
    int p = squares[move.to()];
 
    setSEEPiece(move.from(), p);
 
    setSEEPiece(move.to(), ui.capturedPiece);
 
 
 
    // Handle en passant
 
    if (move.to() == epSquare) {
 
        if (p == Piece::WPAWN) {
 
            setSEEPiece(move.to() - 8, Piece::BPAWN);
 
        } else if (p == Piece::BPAWN) {
 
            setSEEPiece(move.to() + 8, Piece::WPAWN);
 
        }
 
    }
 
}
 
 
 
inline int
 
Position::getSquare(int x, int y) {
 
    return y * 8 + x;
 
}
 
 
 
/** Return x position (file) corresponding to a square. */
 
inline int
 
Position::getX(int square) {
 
    return square & 7;
 
}
 
 
 
/** Return y position (rank) corresponding to a square. */
 
inline int
 
Position::getY(int square) {
 
    return square >> 3;
 
}
 
 
 
inline int
 
Position::mirrorY(int square) {
 
    return square ^ 56;
 
}
 
 
 
/** Return true if (x,y) is a dark square. */
 
inline bool
 
Position::darkSquare(int x, int y) {
 
    return (x & 1) == (y & 1);
 
}
 
 
 
inline void
 
Position::removeCastleRights(int square) {
 
    if (square == getSquare(0, 0)) {
 
        setCastleMask(castleMask & ~(1 << A1_CASTLE));
 
    } else if (square == getSquare(7, 0)) {
 
        setCastleMask(castleMask & ~(1 << H1_CASTLE));
 
    } else if (square == getSquare(0, 7)) {
 
        setCastleMask(castleMask & ~(1 << A8_CASTLE));
 
    } else if (square == getSquare(7, 7)) {
 
        setCastleMask(castleMask & ~(1 << H8_CASTLE));
 
    }
 
}
 
 
 
inline int Position::getFullMoveCounter() const {
 
    return fullMoveCounter;
 
}
 
 
 
inline void Position::setFullMoveCounter(int fm) {
 
    fullMoveCounter = fm;
 
}
 
 
 
inline int Position::getHalfMoveClock() const {
 
    return halfMoveClock;
 
}
 
 
 
inline void Position::setHalfMoveClock(int hm) {
 
    halfMoveClock = hm;
 
}
 
 
 
inline int Position::psScore1(int piece) const {
 
    return psScore1_[piece];
 
}
 
 
 
inline int Position::psScore2(int piece) const {
 
    return psScore2_[piece];
 
}
 
 
 
inline U64 Position::pieceTypeBB(Piece::Type piece) const {
 
    return pieceTypeBB_[piece];
 
}
 
 
 
template <typename Piece0, typename... Pieces>
 
inline U64 Position::pieceTypeBB(Piece0 piece0, Pieces... pieces) const {
 
    return pieceTypeBB(piece0) | pieceTypeBB(pieces...);
 
}
 
 
 
inline U64 Position::whiteBB() const {
 
    return whiteBB_;
 
}
 
 
 
inline U64 Position::blackBB() const {
 
    return blackBB_;
 
};
 
 
 
inline U64 Position::colorBB(int wtm) const {
 
    return wtm ? whiteBB_ : blackBB_;
 
}
 
 
 
inline U64 Position::occupiedBB() const {
 
    return whiteBB() | blackBB();
 
}
 
 
 
inline int Position::wKingSq() const {
 
    return wKingSq_;
 
}
 
 
 
inline int Position::bKingSq() const {
 
    return bKingSq_;
 
}
 
 
 
inline int Position::wMtrl() const {
 
    return wMtrl_;
 
}
 
 
 
inline int Position::bMtrl() const {
 
    return bMtrl_;
 
}
 
 
 
inline int Position::wMtrlPawns() const {
 
    return wMtrlPawns_;
 
}
 
 
 
inline int Position::bMtrlPawns() const {
 
    return bMtrlPawns_;
 
}
 
 
 
inline U64 Position::getHashKey(int piece, int square) {
 
    return psHashKeys[piece][square];
 
}
 
 
 
#endif /* POSITION_HPP_ */