#include "misc.h"
#include "movegen.h"
#include "position.h"
-#include "psqtab.h"
#include "thread.h"
#include "tt.h"
#include "uci.h"
namespace {
const string PieceToChar(" PNBRQK pnbrqk");
-Score psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
// min_attacker() is a helper function used by see() to locate the least
// valuable attacker for the side to move, remove the attacker we just found
// from the bitboards and scan for new X-ray attacks behind it.
-template<int Pt> FORCE_INLINE
+template<int Pt>
PieceType min_attacker(const Bitboard* bb, const Square& to, const Bitboard& stmAttackers,
Bitboard& occupied, Bitboard& attackers) {
return (PieceType)Pt;
}
-template<> FORCE_INLINE
+template<>
PieceType min_attacker<KING>(const Bitboard*, const Square&, const Bitboard&, Bitboard&, Bitboard&) {
return KING; // No need to update bitboards: it is the last cycle
}
/// Position::init() initializes at startup the various arrays used to compute
-/// hash keys and the piece square tables. The latter is a two-step operation:
-/// Firstly, the white halves of the tables are copied from PSQT[] tables.
-/// Secondly, the black halves of the tables are initialized by flipping and
-/// changing the sign of the white scores.
+/// hash keys.
void Position::init() {
for (int cr = NO_CASTLING; cr <= ANY_CASTLING; ++cr)
{
+ Zobrist::castling[cr] = 0;
Bitboard b = cr;
while (b)
{
Zobrist::side = rng.rand<Key>();
Zobrist::exclusion = rng.rand<Key>();
-
- for (PieceType pt = PAWN; pt <= KING; ++pt)
- {
- PieceValue[MG][make_piece(BLACK, pt)] = PieceValue[MG][pt];
- PieceValue[EG][make_piece(BLACK, pt)] = PieceValue[EG][pt];
-
- Score v = make_score(PieceValue[MG][pt], PieceValue[EG][pt]);
-
- for (Square s = SQ_A1; s <= SQ_H8; ++s)
- {
- psq[WHITE][pt][ s] = (v + PSQT[pt][s]);
- psq[BLACK][pt][~s] = -(v + PSQT[pt][s]);
- }
- }
}
Position& Position::operator=(const Position& pos) {
std::memcpy(this, &pos, sizeof(Position));
- startState = *st;
+ std::memcpy(&startState, st, sizeof(StateInfo));
st = &startState;
nodes = 0;
else if ((idx = PieceToChar.find(token)) != string::npos)
{
- put_piece(sq, color_of(Piece(idx)), type_of(Piece(idx)));
+ put_piece(color_of(Piece(idx)), type_of(Piece(idx)), sq);
++sq;
}
}
Square s = pop_lsb(&b);
Piece pc = piece_on(s);
si->key ^= Zobrist::psq[color_of(pc)][type_of(pc)][s];
- si->psq += psq[color_of(pc)][type_of(pc)][s];
+ si->psq += PSQT::psq[color_of(pc)][type_of(pc)][s];
}
- if (ep_square() != SQ_NONE)
- si->key ^= Zobrist::enpassant[file_of(ep_square())];
+ if (si->epSquare != SQ_NONE)
+ si->key ^= Zobrist::enpassant[file_of(si->epSquare)];
if (sideToMove == BLACK)
si->key ^= Zobrist::side;
return (attacks_from<PAWN>(s, BLACK) & pieces(WHITE, PAWN))
| (attacks_from<PAWN>(s, WHITE) & pieces(BLACK, PAWN))
| (attacks_from<KNIGHT>(s) & pieces(KNIGHT))
- | (attacks_bb<ROOK>(s, occupied) & pieces(ROOK, QUEEN))
+ | (attacks_bb<ROOK >(s, occupied) & pieces(ROOK, QUEEN))
| (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN))
| (attacks_from<KING>(s) & pieces(KING));
}
return MoveList<LEGAL>(*this).contains(m);
// Is not a promotion, so promotion piece must be empty
- if (promotion_type(m) - 2 != NO_PIECE_TYPE)
+ if (promotion_type(m) - KNIGHT != NO_PIECE_TYPE)
return false;
// If the 'from' square is not occupied by a piece belonging to the side to
return false;
if ( !(attacks_from<PAWN>(from, us) & pieces(~us) & to) // Not a capture
-
&& !((from + pawn_push(us) == to) && empty(to)) // Not a single push
-
&& !( (from + 2 * pawn_push(us) == to) // Not a double push
&& (rank_of(from) == relative_rank(us, RANK_2))
&& empty(to)
Square from = from_sq(m);
Square to = to_sq(m);
- PieceType pt = type_of(piece_on(from));
// Is there a direct check?
- if (ci.checkSq[pt] & to)
+ if (ci.checkSq[type_of(piece_on(from))] & to)
return true;
// Is there a discovered check?
/// to a StateInfo object. The move is assumed to be legal. Pseudo-legal
/// moves should be filtered out before this function is called.
-void Position::do_move(Move m, StateInfo& newSt) {
-
- CheckInfo ci(*this);
- do_move(m, newSt, ci, gives_check(m, ci));
-}
-
-void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool givesCheck) {
+void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
assert(is_ok(m));
assert(&newSt != st);
assert(pt == KING);
Square rfrom, rto;
- do_castling<true>(from, to, rfrom, rto);
+ do_castling<true>(us, from, to, rfrom, rto);
captured = NO_PIECE_TYPE;
- st->psq += psq[us][ROOK][rto] - psq[us][ROOK][rfrom];
+ st->psq += PSQT::psq[us][ROOK][rto] - PSQT::psq[us][ROOK][rfrom];
k ^= Zobrist::psq[us][ROOK][rfrom] ^ Zobrist::psq[us][ROOK][rto];
}
st->nonPawnMaterial[them] -= PieceValue[MG][captured];
// Update board and piece lists
- remove_piece(capsq, them, captured);
+ remove_piece(them, captured, capsq);
// Update material hash key and prefetch access to materialTable
k ^= Zobrist::psq[them][captured][capsq];
prefetch(thisThread->materialTable[st->materialKey]);
// Update incremental scores
- st->psq -= psq[them][captured][capsq];
+ st->psq -= PSQT::psq[them][captured][capsq];
// Reset rule 50 counter
st->rule50 = 0;
// Move the piece. The tricky Chess960 castling is handled earlier
if (type_of(m) != CASTLING)
- move_piece(from, to, us, pt);
+ move_piece(us, pt, from, to);
// If the moving piece is a pawn do some special extra work
if (pt == PAWN)
assert(relative_rank(us, to) == RANK_8);
assert(promotion >= KNIGHT && promotion <= QUEEN);
- remove_piece(to, us, PAWN);
- put_piece(to, us, promotion);
+ remove_piece(us, PAWN, to);
+ put_piece(us, promotion, to);
// Update hash keys
k ^= Zobrist::psq[us][PAWN][to] ^ Zobrist::psq[us][promotion][to];
^ Zobrist::psq[us][PAWN][pieceCount[us][PAWN]];
// Update incremental score
- st->psq += psq[us][promotion][to] - psq[us][PAWN][to];
+ st->psq += PSQT::psq[us][promotion][to] - PSQT::psq[us][PAWN][to];
// Update material
st->nonPawnMaterial[us] += PieceValue[MG][promotion];
}
// Update incremental scores
- st->psq += psq[us][pt][to] - psq[us][pt][from];
+ st->psq += PSQT::psq[us][pt][to] - PSQT::psq[us][pt][from];
// Set capture piece
st->capturedType = captured;
// Update the key with the final value
st->key = k;
- // Update checkers bitboard: piece must be already moved due to attacks_from()
- st->checkersBB = 0;
-
- if (givesCheck)
- {
- if (type_of(m) != NORMAL)
- st->checkersBB = attackers_to(king_square(them)) & pieces(us);
- else
- {
- // Direct checks
- if (ci.checkSq[pt] & to)
- st->checkersBB |= to;
-
- // Discovered checks
- if (ci.dcCandidates && (ci.dcCandidates & from))
- {
- assert(pt != QUEEN);
-
- if (pt != ROOK)
- st->checkersBB |= attacks_from<ROOK>(king_square(them)) & pieces(us, QUEEN, ROOK);
-
- if (pt != BISHOP)
- st->checkersBB |= attacks_from<BISHOP>(king_square(them)) & pieces(us, QUEEN, BISHOP);
- }
- }
- }
+ // Calculate checkers bitboard (if move gives check)
+ st->checkersBB = givesCheck ? attackers_to(king_square(them)) & pieces(us) : 0;
sideToMove = ~sideToMove;
assert(pt == promotion_type(m));
assert(pt >= KNIGHT && pt <= QUEEN);
- remove_piece(to, us, pt);
- put_piece(to, us, PAWN);
+ remove_piece(us, pt, to);
+ put_piece(us, PAWN, to);
pt = PAWN;
}
if (type_of(m) == CASTLING)
{
Square rfrom, rto;
- do_castling<false>(from, to, rfrom, rto);
+ do_castling<false>(us, from, to, rfrom, rto);
}
else
{
- move_piece(to, from, us, pt); // Put the piece back at the source square
+ move_piece(us, pt, to, from); // Put the piece back at the source square
if (st->capturedType)
{
assert(st->capturedType == PAWN);
}
- put_piece(capsq, ~us, st->capturedType); // Restore the captured piece
+ put_piece(~us, st->capturedType, capsq); // Restore the captured piece
}
}
/// Position::do_castling() is a helper used to do/undo a castling move. This
/// is a bit tricky, especially in Chess960.
template<bool Do>
-void Position::do_castling(Square from, Square& to, Square& rfrom, Square& rto) {
+void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto) {
bool kingSide = to > from;
rfrom = to; // Castling is encoded as "king captures friendly rook"
- rto = relative_square(sideToMove, kingSide ? SQ_F1 : SQ_D1);
- to = relative_square(sideToMove, kingSide ? SQ_G1 : SQ_C1);
+ rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
+ to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
// Remove both pieces first since squares could overlap in Chess960
- remove_piece(Do ? from : to, sideToMove, KING);
- remove_piece(Do ? rfrom : rto, sideToMove, ROOK);
+ remove_piece(us, KING, Do ? from : to);
+ remove_piece(us, ROOK, Do ? rfrom : rto);
board[Do ? from : to] = board[Do ? rfrom : rto] = NO_PIECE; // Since remove_piece doesn't do it for us
- put_piece(Do ? to : from, sideToMove, KING);
- put_piece(Do ? rto : rfrom, sideToMove, ROOK);
+ put_piece(us, KING, Do ? to : from);
+ put_piece(us, ROOK, Do ? rto : rfrom);
}
}
-/// Position::is_draw() tests whether the position is drawn by material, 50 moves
-/// rule or repetition. It does not detect stalemates.
+/// Position::is_draw() tests whether the position is drawn by 50-move rule
+/// or by repetition. It does not detect stalemates.
bool Position::is_draw() const {