#include <fstream>
#include <iostream>
+#include "bitcount.h"
#include "mersenne.h"
#include "movegen.h"
#include "movepick.h"
st->materialKey = compute_material_key();
st->mgValue = compute_value<MidGame>();
st->egValue = compute_value<EndGame>();
- npMaterial[WHITE] = compute_non_pawn_material(WHITE);
- npMaterial[BLACK] = compute_non_pawn_material(BLACK);
+ st->npMaterial[WHITE] = compute_non_pawn_material(WHITE);
+ st->npMaterial[BLACK] = compute_non_pawn_material(BLACK);
}
/// Position::copy() creates a copy of the input position.
-void Position::copy(const Position &pos) {
+void Position::copy(const Position& pos) {
memcpy(this, &pos, sizeof(Position));
+ saveState(); // detach and copy state info
}
}
/// Position::attacks_to() computes a bitboard containing all pieces which
-/// attacks a given square. There are two versions of this function: One
-/// which finds attackers of both colors, and one which only finds the
-/// attackers for one side.
+/// attacks a given square.
Bitboard Position::attacks_to(Square s) const {
const bool Rook = (Piece == QUEEN || Piece == ROOK);
const bool Slider = Bishop || Rook;
+ // Direct checks
if ( ( (Bishop && bit_is_set(BishopPseudoAttacks[ksq], to))
|| (Rook && bit_is_set(RookPseudoAttacks[ksq], to)))
&& bit_is_set(piece_attacks<Piece>(ksq), to)) // slow, try to early skip
&& bit_is_set(piece_attacks<Piece>(ksq), to))
set_bit(pCheckersBB, to);
+ // Discovery checks
if (Piece != QUEEN && bit_is_set(dcCandidates, from))
{
if (Piece != ROOK)
int castleRights, rule50;
Square epSquare;
Value mgValue, egValue;
+ Value npMaterial[2];
};
memcpy(&newSt, st, sizeof(ReducedStateInfo));
do_capture_move(st->capture, them, to);
// Move the piece
- clear_bit(&(byColorBB[us]), from);
- clear_bit(&(byTypeBB[piece]), from);
- clear_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares
- set_bit(&(byColorBB[us]), to);
- set_bit(&(byTypeBB[piece]), to);
- set_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares
+ Bitboard move_bb = make_move_bb(from, to);
+ do_move_bb(&(byColorBB[us]), move_bb);
+ do_move_bb(&(byTypeBB[piece]), move_bb);
+ do_move_bb(&(byTypeBB[0]), move_bb); // HACK: byTypeBB[0] == occupied squares
+
board[to] = board[from];
board[from] = EMPTY;
// Remove captured piece
clear_bit(&(byColorBB[them]), to);
clear_bit(&(byTypeBB[capture]), to);
+ clear_bit(&(byTypeBB[0]), to);
// Update hash key
st->key ^= zobrist[them][capture][to];
// Update material
if (capture != PAWN)
- npMaterial[them] -= piece_value_midgame(capture);
+ st->npMaterial[them] -= piece_value_midgame(capture);
// Update material hash key
st->materialKey ^= zobMaterial[them][capture][pieceCount[them][capture]];
st->capture = type_of_piece_on(to);
if (st->capture)
- do_capture_move(st->capture, them, to);
+ do_capture_move(st->capture, them, to);
// Remove pawn
clear_bit(&(byColorBB[us]), from);
st->egValue += pst<EndGame>(us, promotion, to);
// Update material
- npMaterial[us] += piece_value_midgame(promotion);
+ st->npMaterial[us] += piece_value_midgame(promotion);
// Clear the en passant square
if (st->epSquare != SQ_NONE)
assert(piece_on(from) == piece_of_color_and_type(us, PAWN));
assert(piece_on(capsq) == piece_of_color_and_type(them, PAWN));
- // Remove captured piece
+ // Remove captured pawn
clear_bit(&(byColorBB[them]), capsq);
clear_bit(&(byTypeBB[PAWN]), capsq);
clear_bit(&(byTypeBB[0]), capsq); // HACK: byTypeBB[0] == occupied squares
board[capsq] = EMPTY;
- // Remove moving piece from source square
- clear_bit(&(byColorBB[us]), from);
- clear_bit(&(byTypeBB[PAWN]), from);
- clear_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares
-
- // Put moving piece on destination square
- set_bit(&(byColorBB[us]), to);
- set_bit(&(byTypeBB[PAWN]), to);
- set_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares
+ // Move capturing pawn
+ Bitboard move_bb = make_move_bb(from, to);
+ do_move_bb(&(byColorBB[us]), move_bb);
+ do_move_bb(&(byTypeBB[PAWN]), move_bb);
+ do_move_bb(&(byTypeBB[0]), move_bb); // HACK: byTypeBB[0] == occupied squares
board[to] = board[from];
board[from] = EMPTY;
assert(color_of_piece_on(to) == us);
// Put the piece back at the source square
+ Bitboard move_bb = make_move_bb(to, from);
piece = type_of_piece_on(to);
- set_bit(&(byColorBB[us]), from);
- set_bit(&(byTypeBB[piece]), from);
- set_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares
+ do_move_bb(&(byColorBB[us]), move_bb);
+ do_move_bb(&(byTypeBB[piece]), move_bb);
+ do_move_bb(&(byTypeBB[0]), move_bb); // HACK: byTypeBB[0] == occupied squares
board[from] = piece_of_color_and_type(us, piece);
- // Clear the destination square
- clear_bit(&(byColorBB[us]), to);
- clear_bit(&(byTypeBB[piece]), to);
- clear_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares
-
// If the moving piece was a king, update the king square
if (piece == KING)
kingSquare[us] = from;
{
assert(st->capture != KING);
- // Replace the captured piece
+ // Restore the captured piece
set_bit(&(byColorBB[them]), to);
set_bit(&(byTypeBB[st->capture]), to);
set_bit(&(byTypeBB[0]), to);
board[to] = piece_of_color_and_type(them, st->capture);
- // Update material
- if (st->capture != PAWN)
- npMaterial[them] += piece_value_midgame(st->capture);
-
// Update piece list
pieceList[them][st->capture][pieceCount[them][st->capture]] = to;
index[to] = pieceCount[them][st->capture];
set_bit(&(byTypeBB[0]), from); // HACK: byTypeBB[0] == occupied squares
board[from] = piece_of_color_and_type(us, PAWN);
- // Update material
- npMaterial[us] -= piece_value_midgame(promotion);
-
// Update piece list
pieceList[us][PAWN][pieceCount[us][PAWN]] = from;
index[from] = pieceCount[us][PAWN];
set_bit(&(byTypeBB[0]), to); // HACK: byTypeBB[0] == occupied squares
board[to] = piece_of_color_and_type(them, st->capture);
- // Update material. Because the move is a promotion move, we know
- // that the captured piece cannot be a pawn.
- assert(st->capture != PAWN);
- npMaterial[them] += piece_value_midgame(st->capture);
-
// Update piece list
pieceList[them][st->capture][pieceCount[them][st->capture]] = to;
index[to] = pieceCount[them][st->capture];
assert(piece_on(from) == EMPTY);
assert(piece_on(capsq) == EMPTY);
- // Replace captured piece
+ // Restore captured pawn
set_bit(&(byColorBB[them]), capsq);
set_bit(&(byTypeBB[PAWN]), capsq);
set_bit(&(byTypeBB[0]), capsq);
board[capsq] = piece_of_color_and_type(them, PAWN);
- // Remove moving piece from destination square
- clear_bit(&(byColorBB[us]), to);
- clear_bit(&(byTypeBB[PAWN]), to);
- clear_bit(&(byTypeBB[0]), to);
+ // Move capturing pawn back to source square
+ Bitboard move_bb = make_move_bb(to, from);
+ do_move_bb(&(byColorBB[us]), move_bb);
+ do_move_bb(&(byTypeBB[PAWN]), move_bb);
+ do_move_bb(&(byTypeBB[0]), move_bb);
board[to] = EMPTY;
-
- // Replace moving piece at source square
- set_bit(&(byColorBB[us]), from);
- set_bit(&(byTypeBB[PAWN]), from);
- set_bit(&(byTypeBB[0]), from);
board[from] = piece_of_color_and_type(us, PAWN);
- // Update piece list:
+ // Update piece list
pieceList[us][PAWN][index[to]] = from;
index[from] = index[to];
pieceList[them][PAWN][pieceCount[them][PAWN]] = capsq;
index[capsq] = pieceCount[them][PAWN];
- // Update piece count:
+ // Update piece count
pieceCount[them][PAWN]++;
}
assert(!is_check());
// Back up the information necessary to undo the null move to the supplied
- // StateInfo object. In the case of a null move, the only thing we need to
- // remember is the last move made and the en passant square.
+ // StateInfo object.
// Note that differently from normal case here backupSt is actually used as
// a backup storage not as a new state to be used.
- backupSt.lastMove = st->lastMove;
backupSt.epSquare = st->epSquare;
+ backupSt.key = st->key;
+ backupSt.mgValue = st->mgValue;
+ backupSt.egValue = st->egValue;
backupSt.previous = st->previous;
st->previous = &backupSt;
assert(!is_check());
// Restore information from the our backup StateInfo object
- st->lastMove = st->previous->lastMove;
st->epSquare = st->previous->epSquare;
+ st->key = st->previous->key;
+ st->mgValue = st->previous->mgValue;
+ st->egValue = st->previous->egValue;
st->previous = st->previous->previous;
- if (st->epSquare != SQ_NONE)
- st->key ^= zobEp[st->epSquare];
-
// Update the necessary information
sideToMove = opposite_color(sideToMove);
st->rule50--;
gamePly--;
- st->key ^= zobSideToMove;
-
- st->mgValue += (sideToMove == WHITE)? TempoValueMidgame : -TempoValueMidgame;
- st->egValue += (sideToMove == WHITE)? TempoValueEndgame : -TempoValueEndgame;
assert(is_ok());
}
if (pt == KING && stmAttackers)
{
assert(n < 32);
- swapList[n++] = 100;
+ swapList[n++] = QueenValueMidgame*10;
break;
}
} while (stmAttackers);
}
-/// Position::setStartState() copies the content of the argument
+/// Position::saveState() copies the content of the current state
/// inside startState and makes st point to it. This is needed
/// when the st pointee could become stale, as example because
/// the caller is about to going out of scope.
-void Position::setStartState(const StateInfo& s) {
+void Position::saveState() {
- startState = s;
+ startState = *st;
st = &startState;
+ st->previous = NULL; // as a safe guard
}
/// the white and black sides reversed. This is only useful for debugging,
/// especially for finding evaluation symmetry bugs.
-void Position::flipped_copy(const Position &pos) {
+void Position::flipped_copy(const Position& pos) {
assert(pos.is_ok());
st->egValue = compute_value<EndGame>();
// Material
- npMaterial[WHITE] = compute_non_pawn_material(WHITE);
- npMaterial[BLACK] = compute_non_pawn_material(BLACK);
+ st->npMaterial[WHITE] = compute_non_pawn_material(WHITE);
+ st->npMaterial[BLACK] = compute_non_pawn_material(BLACK);
assert(is_ok());
}
if (failedStep) (*failedStep)++;
if (debugNonPawnMaterial)
{
- if (npMaterial[WHITE] != compute_non_pawn_material(WHITE))
+ if (st->npMaterial[WHITE] != compute_non_pawn_material(WHITE))
return false;
- if (npMaterial[BLACK] != compute_non_pawn_material(BLACK))
+ if (st->npMaterial[BLACK] != compute_non_pawn_material(BLACK))
return false;
}