/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
- Copyright (C) 2008 Marco Costalba
+ Copyright (C) 2008-2009 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <fstream>
#include <iostream>
+#include "bitcount.h"
#include "mersenne.h"
#include "movegen.h"
#include "movepick.h"
#include "san.h"
#include "ucioption.h"
+using std::string;
+
////
//// Variables
////
-extern SearchStack EmptySearchStack;
-
int Position::castleRightsMask[64];
Key Position::zobrist[2][8][64];
copy(pos);
}
-Position::Position(const std::string& fen) {
+Position::Position(const string& fen) {
from_fen(fen);
}
/// string. This function is not very robust - make sure that input FENs are
/// correct (this is assumed to be the responsibility of the GUI).
-void Position::from_fen(const std::string& fen) {
+void Position::from_fen(const string& fen) {
- static const std::string pieceLetters = "KQRBNPkqrbnp";
+ static const string pieceLetters = "KQRBNPkqrbnp";
static const Piece pieces[] = { WK, WQ, WR, WB, WN, WP, BK, BQ, BR, BB, BN, BP };
clear();
continue;
}
size_t idx = pieceLetters.find(fen[i]);
- if (idx == std::string::npos)
+ if (idx == string::npos)
{
std::cout << "Error in FEN at character " << i << std::endl;
return;
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::to_fen() converts the position object to a FEN string. This is
/// probably only useful for debugging.
-const std::string Position::to_fen() const {
+const string Position::to_fen() const {
- static const std::string pieceLetters = " PNBRQK pnbrqk";
- std::string fen;
+ static const string pieceLetters = " PNBRQK pnbrqk";
+ string fen;
int skip;
for (Rank rank = RANK_8; rank >= RANK_1; rank--)
void Position::print(Move m) const {
- static const std::string pieceLetters = " PNBRQK PNBRQK .";
+ static const string pieceLetters = " PNBRQK PNBRQK .";
// Check for reentrancy, as example when called from inside
// MovePicker that is used also here in move_to_san()
std::cout << std::endl;
if (m != MOVE_NONE)
{
- std::string col = (color_of_piece_on(move_from(m)) == BLACK ? ".." : "");
+ string col = (color_of_piece_on(move_from(m)) == BLACK ? ".." : "");
std::cout << "Move is: " << col << move_to_san(*this, m) << std::endl;
}
for (Rank rank = RANK_8; rank >= RANK_1; rank--)
}
/// 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 {
bool Position::pl_move_is_legal(Move m) const {
- return pl_move_is_legal(m, pinned_pieces(side_to_move()));
+ // If we're in check, all pseudo-legal moves are legal, because our
+ // check evasion generator only generates true legal moves.
+ return is_check() || pl_move_is_legal(m, pinned_pieces(side_to_move()));
}
bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
assert(is_ok());
assert(move_is_ok(m));
assert(pinned == pinned_pieces(side_to_move()));
-
- // If we're in check, all pseudo-legal moves are legal, because our
- // check evasion generator only generates true legal moves.
- if (is_check())
- return true;
+ assert(!is_check());
// Castling moves are checked for legality during move generation.
if (move_is_castle(m))
case BISHOP:
return (dcCandidates && bit_is_set(dcCandidates, from))
- || ( direction_between_squares(ksq, to) != DIR_NONE
- && bit_is_set(piece_attacks<BISHOP>(ksq), to));
+ || (direction_is_diagonal(ksq, to) && bit_is_set(piece_attacks<BISHOP>(ksq), to));
case ROOK:
return (dcCandidates && bit_is_set(dcCandidates, from))
- || ( direction_between_squares(ksq, to) != DIR_NONE
- && bit_is_set(piece_attacks<ROOK>(ksq), to));
+ || (direction_is_straight(ksq, to) && bit_is_set(piece_attacks<ROOK>(ksq), to));
case QUEEN:
// Discovered checks are impossible!
assert(!bit_is_set(dcCandidates, from));
- return ( direction_between_squares(ksq, to) != DIR_NONE
- && bit_is_set(piece_attacks<QUEEN>(ksq), to));
+ return ( (direction_is_straight(ksq, to) && bit_is_set(piece_attacks<ROOK>(ksq), to))
+ || (direction_is_diagonal(ksq, to) && bit_is_set(piece_attacks<BISHOP>(ksq), to)));
case KING:
// Discovered check?
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());
}
0, 0
};
- Bitboard attackers, occ, b;
+ Bitboard attackers, stmAttackers, occ, b;
assert(square_is_ok(from) || from == SQ_NONE);
assert(square_is_ok(to));
Square capQq = (side_to_move() == WHITE)? (to - DELTA_N) : (to - DELTA_S);
capture = piece_on(capQq);
-
assert(type_of_piece_on(capQq) == PAWN);
// Remove the captured pawn
}
// If the opponent has no attackers we are finished
- if ((attackers & pieces_of_color(them)) == EmptyBoardBB)
+ stmAttackers = attackers & pieces_of_color(them);
+ if (!stmAttackers)
return seeValues[capture];
attackers &= occ; // Remove the moving piece
// Locate the least valuable attacker for the side to move. The loop
// below looks like it is potentially infinite, but it isn't. We know
// that the side to move still has at least one attacker left.
- for (pt = PAWN; !(attackers & pieces_of_color_and_type(c, pt)); pt++)
+ for (pt = PAWN; !(stmAttackers & pieces_of_type(pt)); pt++)
assert(pt < KING);
// Remove the attacker we just found from the 'attackers' bitboard,
// and scan for new X-ray attacks behind the attacker.
- b = attackers & pieces_of_color_and_type(c, pt);
+ b = stmAttackers & pieces_of_type(pt);
occ ^= (b & (~b + 1));
attackers |= (rook_attacks_bb(to, occ) & rooks_and_queens())
| (bishop_attacks_bb(to, occ) & bishops_and_queens());
// before beginning the next iteration
lastCapturingPieceValue = seeValues[pt];
c = opposite_color(c);
+ stmAttackers = attackers & pieces_of_color(c);
// Stop after a king capture
- if (pt == KING && (attackers & pieces_of_color(c)))
+ if (pt == KING && stmAttackers)
{
assert(n < 32);
swapList[n++] = 100;
break;
}
- } while (attackers & pieces_of_color(c));
+ } while (stmAttackers);
// Having built the swap list, we negamax through it to find the best
// achievable score from the point of view of the side to move
void Position::init_zobrist() {
- for(Piece p = WP; p <= BK; p++)
- for(Square s = SQ_A1; s <= SQ_H8; s++)
- zobrist[color_of_piece(p)][type_of_piece(p)][s] = genrand_int64();
+ for (int i = 0; i < 2; i++)
+ for (int j = 0; j < 8; j++)
+ for (int k = 0; k < 64; k++)
+ zobrist[i][j][k] = Key(genrand_int64());
- zobEp[0] = 0ULL;
- for(int i = 1; i < 64; i++)
- zobEp[i] = genrand_int64();
+ for (int i = 0; i < 64; i++)
+ zobEp[i] = Key(genrand_int64());
- for(int i = 15; i >= 0; i--)
- zobCastle[(i&8) | (i&1) | ((i&2) << 1) | ((i&4) >> 1)] = genrand_int64();
+ for (int i = 0; i < 16; i++)
+ zobCastle[i] = genrand_int64();
zobSideToMove = genrand_int64();
for (int i = 0; i < 2; i++)
for (int j = 0; j < 8; j++)
for (int k = 0; k < 16; k++)
- zobMaterial[i][j][k] = (k > 0)? genrand_int64() : 0LL;
+ zobMaterial[i][j][k] = (k > 0)? Key(genrand_int64()) : Key(0LL);
for (int i = 0; i < 16; i++)
- zobMaterial[0][KING][i] = zobMaterial[1][KING][i] = 0ULL;
+ zobMaterial[0][KING][i] = zobMaterial[1][KING][i] = Key(0ULL);
}
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;
}