1
0
Fork 0

Remove more unrelated files

gcc_bug
root 2015-01-10 11:36:44 +00:00
parent ece8f0780f
commit f3cf782beb
8 changed files with 0 additions and 3091 deletions

View File

@ -1,418 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish 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.
Stockfish 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/>.
*/
#include <cassert>
#include "movegen.h"
#include "position.h"
namespace {
template<CastlingRight Cr, bool Checks, bool Chess960>
ExtMove* generate_castling(const Position& pos, ExtMove* moveList, Color us, const CheckInfo* ci) {
static const bool KingSide = (Cr == WHITE_OO || Cr == BLACK_OO);
if (pos.castling_impeded(Cr) || !pos.can_castle(Cr))
return moveList;
// After castling, the rook and king final positions are the same in Chess960
// as they would be in standard chess.
Square kfrom = pos.king_square(us);
Square rfrom = pos.castling_rook_square(Cr);
Square kto = relative_square(us, KingSide ? SQ_G1 : SQ_C1);
Bitboard enemies = pos.pieces(~us);
assert(!pos.checkers());
const Square K = Chess960 ? kto > kfrom ? DELTA_W : DELTA_E
: KingSide ? DELTA_W : DELTA_E;
for (Square s = kto; s != kfrom; s += K)
if (pos.attackers_to(s) & enemies)
return moveList;
// Because we generate only legal castling moves we need to verify that
// when moving the castling rook we do not discover some hidden checker.
// For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
if (Chess960 && (attacks_bb<ROOK>(kto, pos.pieces() ^ rfrom) & pos.pieces(~us, ROOK, QUEEN)))
return moveList;
Move m = make<CASTLING>(kfrom, rfrom);
if (Checks && !pos.gives_check(m, *ci))
return moveList;
(moveList++)->move = m;
return moveList;
}
template<GenType Type, Square Delta>
inline ExtMove* make_promotions(ExtMove* moveList, Square to, const CheckInfo* ci) {
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
(moveList++)->move = make<PROMOTION>(to - Delta, to, QUEEN);
if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS)
{
(moveList++)->move = make<PROMOTION>(to - Delta, to, ROOK);
(moveList++)->move = make<PROMOTION>(to - Delta, to, BISHOP);
(moveList++)->move = make<PROMOTION>(to - Delta, to, KNIGHT);
}
// Knight promotion is the only promotion that can give a direct check
// that's not already included in the queen promotion.
if (Type == QUIET_CHECKS && (StepAttacksBB[W_KNIGHT][to] & ci->ksq))
(moveList++)->move = make<PROMOTION>(to - Delta, to, KNIGHT);
else
(void)ci; // Silence a warning under MSVC
return moveList;
}
template<Color Us, GenType Type>
ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList,
Bitboard target, const CheckInfo* ci) {
// Compute our parametrized parameters at compile time, named according to
// the point of view of white side.
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
const Square Up = (Us == WHITE ? DELTA_N : DELTA_S);
const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW);
const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE);
Bitboard emptySquares;
Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB;
Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
Bitboard enemies = (Type == EVASIONS ? pos.pieces(Them) & target:
Type == CAPTURES ? target : pos.pieces(Them));
// Single and double pawn pushes, no promotions
if (Type != CAPTURES)
{
emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces());
Bitboard b1 = shift_bb<Up>(pawnsNotOn7) & emptySquares;
Bitboard b2 = shift_bb<Up>(b1 & TRank3BB) & emptySquares;
if (Type == EVASIONS) // Consider only blocking squares
{
b1 &= target;
b2 &= target;
}
if (Type == QUIET_CHECKS)
{
b1 &= pos.attacks_from<PAWN>(ci->ksq, Them);
b2 &= pos.attacks_from<PAWN>(ci->ksq, Them);
// Add pawn pushes which give discovered check. This is possible only
// if the pawn is not on the same file as the enemy king, because we
// don't generate captures. Note that a possible discovery check
// promotion has been already generated amongst the captures.
if (pawnsNotOn7 & ci->dcCandidates)
{
Bitboard dc1 = shift_bb<Up>(pawnsNotOn7 & ci->dcCandidates) & emptySquares & ~file_bb(ci->ksq);
Bitboard dc2 = shift_bb<Up>(dc1 & TRank3BB) & emptySquares;
b1 |= dc1;
b2 |= dc2;
}
}
while (b1)
{
Square to = pop_lsb(&b1);
(moveList++)->move = make_move(to - Up, to);
}
while (b2)
{
Square to = pop_lsb(&b2);
(moveList++)->move = make_move(to - Up - Up, to);
}
}
// Promotions and underpromotions
if (pawnsOn7 && (Type != EVASIONS || (target & TRank8BB)))
{
if (Type == CAPTURES)
emptySquares = ~pos.pieces();
if (Type == EVASIONS)
emptySquares &= target;
Bitboard b1 = shift_bb<Right>(pawnsOn7) & enemies;
Bitboard b2 = shift_bb<Left >(pawnsOn7) & enemies;
Bitboard b3 = shift_bb<Up >(pawnsOn7) & emptySquares;
while (b1)
moveList = make_promotions<Type, Right>(moveList, pop_lsb(&b1), ci);
while (b2)
moveList = make_promotions<Type, Left >(moveList, pop_lsb(&b2), ci);
while (b3)
moveList = make_promotions<Type, Up >(moveList, pop_lsb(&b3), ci);
}
// Standard and en-passant captures
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
{
Bitboard b1 = shift_bb<Right>(pawnsNotOn7) & enemies;
Bitboard b2 = shift_bb<Left >(pawnsNotOn7) & enemies;
while (b1)
{
Square to = pop_lsb(&b1);
(moveList++)->move = make_move(to - Right, to);
}
while (b2)
{
Square to = pop_lsb(&b2);
(moveList++)->move = make_move(to - Left, to);
}
if (pos.ep_square() != SQ_NONE)
{
assert(rank_of(pos.ep_square()) == relative_rank(Us, RANK_6));
// An en passant capture can be an evasion only if the checking piece
// is the double pushed pawn and so is in the target. Otherwise this
// is a discovery check and we are forced to do otherwise.
if (Type == EVASIONS && !(target & (pos.ep_square() - Up)))
return moveList;
b1 = pawnsNotOn7 & pos.attacks_from<PAWN>(pos.ep_square(), Them);
assert(b1);
while (b1)
(moveList++)->move = make<ENPASSANT>(pop_lsb(&b1), pos.ep_square());
}
}
return moveList;
}
template<PieceType Pt, bool Checks> FORCE_INLINE
ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Color us,
Bitboard target, const CheckInfo* ci) {
assert(Pt != KING && Pt != PAWN);
const Square* pl = pos.list<Pt>(us);
for (Square from = *pl; from != SQ_NONE; from = *++pl)
{
if (Checks)
{
if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN)
&& !(PseudoAttacks[Pt][from] & target & ci->checkSq[Pt]))
continue;
if (unlikely(ci->dcCandidates) && (ci->dcCandidates & from))
continue;
}
Bitboard b = pos.attacks_from<Pt>(from) & target;
if (Checks)
b &= ci->checkSq[Pt];
while (b)
(moveList++)->move = make_move(from, pop_lsb(&b));
}
return moveList;
}
template<Color Us, GenType Type> FORCE_INLINE
ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target,
const CheckInfo* ci = NULL) {
const bool Checks = Type == QUIET_CHECKS;
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target, ci);
moveList = generate_moves<KNIGHT, Checks>(pos, moveList, Us, target, ci);
moveList = generate_moves<BISHOP, Checks>(pos, moveList, Us, target, ci);
moveList = generate_moves< ROOK, Checks>(pos, moveList, Us, target, ci);
moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target, ci);
if (Type != QUIET_CHECKS && Type != EVASIONS)
{
Square ksq = pos.king_square(Us);
Bitboard b = pos.attacks_from<KING>(ksq) & target;
while (b)
(moveList++)->move = make_move(ksq, pop_lsb(&b));
}
if (Type != CAPTURES && Type != EVASIONS && pos.can_castle(Us))
{
if (pos.is_chess960())
{
moveList = generate_castling<MakeCastling<Us, KING_SIDE>::right, Checks, true>(pos, moveList, Us, ci);
moveList = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, true>(pos, moveList, Us, ci);
}
else
{
moveList = generate_castling<MakeCastling<Us, KING_SIDE>::right, Checks, false>(pos, moveList, Us, ci);
moveList = generate_castling<MakeCastling<Us, QUEEN_SIDE>::right, Checks, false>(pos, moveList, Us, ci);
}
}
return moveList;
}
} // namespace
/// generate<CAPTURES> generates all pseudo-legal captures and queen
/// promotions. Returns a pointer to the end of the move list.
///
/// generate<QUIETS> generates all pseudo-legal non-captures and
/// underpromotions. Returns a pointer to the end of the move list.
///
/// generate<NON_EVASIONS> generates all pseudo-legal captures and
/// non-captures. Returns a pointer to the end of the move list.
template<GenType Type>
ExtMove* generate(const Position& pos, ExtMove* moveList) {
assert(Type == CAPTURES || Type == QUIETS || Type == NON_EVASIONS);
assert(!pos.checkers());
Color us = pos.side_to_move();
Bitboard target = Type == CAPTURES ? pos.pieces(~us)
: Type == QUIETS ? ~pos.pieces()
: Type == NON_EVASIONS ? ~pos.pieces(us) : 0;
return us == WHITE ? generate_all<WHITE, Type>(pos, moveList, target)
: generate_all<BLACK, Type>(pos, moveList, target);
}
// Explicit template instantiations
template ExtMove* generate<CAPTURES>(const Position&, ExtMove*);
template ExtMove* generate<QUIETS>(const Position&, ExtMove*);
template ExtMove* generate<NON_EVASIONS>(const Position&, ExtMove*);
/// generate<QUIET_CHECKS> generates all pseudo-legal non-captures and knight
/// underpromotions that give check. Returns a pointer to the end of the move list.
template<>
ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* moveList) {
assert(!pos.checkers());
Color us = pos.side_to_move();
CheckInfo ci(pos);
Bitboard dc = ci.dcCandidates;
while (dc)
{
Square from = pop_lsb(&dc);
PieceType pt = type_of(pos.piece_on(from));
if (pt == PAWN)
continue; // Will be generated together with direct checks
Bitboard b = pos.attacks_from(Piece(pt), from) & ~pos.pieces();
if (pt == KING)
b &= ~PseudoAttacks[QUEEN][ci.ksq];
while (b)
(moveList++)->move = make_move(from, pop_lsb(&b));
}
return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, moveList, ~pos.pieces(), &ci)
: generate_all<BLACK, QUIET_CHECKS>(pos, moveList, ~pos.pieces(), &ci);
}
/// generate<EVASIONS> generates all pseudo-legal check evasions when the side
/// to move is in check. Returns a pointer to the end of the move list.
template<>
ExtMove* generate<EVASIONS>(const Position& pos, ExtMove* moveList) {
assert(pos.checkers());
Color us = pos.side_to_move();
Square ksq = pos.king_square(us);
Bitboard sliderAttacks = 0;
Bitboard sliders = pos.checkers() & ~pos.pieces(KNIGHT, PAWN);
// Find all the squares attacked by slider checkers. We will remove them from
// the king evasions in order to skip known illegal moves, which avoids any
// useless legality checks later on.
while (sliders)
{
Square checksq = pop_lsb(&sliders);
sliderAttacks |= LineBB[checksq][ksq] ^ checksq;
}
// Generate evasions for king, capture and non capture moves
Bitboard b = pos.attacks_from<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks;
while (b)
(moveList++)->move = make_move(ksq, pop_lsb(&b));
if (more_than_one(pos.checkers()))
return moveList; // Double check, only a king move can save the day
// Generate blocking evasions or captures of the checking piece
Square checksq = lsb(pos.checkers());
Bitboard target = between_bb(checksq, ksq) | checksq;
return us == WHITE ? generate_all<WHITE, EVASIONS>(pos, moveList, target)
: generate_all<BLACK, EVASIONS>(pos, moveList, target);
}
/// generate<LEGAL> generates all the legal moves in the given position
template<>
ExtMove* generate<LEGAL>(const Position& pos, ExtMove* moveList) {
Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
Square ksq = pos.king_square(pos.side_to_move());
ExtMove* cur = moveList;
moveList = pos.checkers() ? generate<EVASIONS >(pos, moveList)
: generate<NON_EVASIONS>(pos, moveList);
while (cur != moveList)
if ( (pinned || from_sq(cur->move) == ksq || type_of(cur->move) == ENPASSANT)
&& !pos.legal(cur->move, pinned))
cur->move = (--moveList)->move;
else
++cur;
return moveList;
}

View File

@ -1,58 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish 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.
Stockfish 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/>.
*/
#ifndef MOVEGEN_H_INCLUDED
#define MOVEGEN_H_INCLUDED
#include "types.h"
enum GenType {
CAPTURES,
QUIETS,
QUIET_CHECKS,
EVASIONS,
NON_EVASIONS,
LEGAL
};
class Position;
template<GenType>
ExtMove* generate(const Position& pos, ExtMove* moveList);
/// The MoveList struct is a simple wrapper around generate(). It sometimes comes
/// in handy to use this class instead of the low level generate() function.
template<GenType T>
struct MoveList {
explicit MoveList(const Position& pos) : cur(moveList), last(generate<T>(pos, moveList)) { last->move = MOVE_NONE; }
void operator++() { ++cur; }
Move operator*() const { return cur->move; }
size_t size() const { return last - moveList; }
bool contains(Move m) const {
for (const ExtMove* it(moveList); it != last; ++it) if (it->move == m) return true;
return false;
}
private:
ExtMove moveList[MAX_MOVES];
ExtMove *cur, *last;
};
#endif // #ifndef MOVEGEN_H_INCLUDED

View File

@ -1,385 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish 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.
Stockfish 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/>.
*/
#include <cassert>
#include "movepick.h"
#include "thread.h"
namespace {
enum Stages {
MAIN_SEARCH, CAPTURES_S1, KILLERS_S1, QUIETS_1_S1, QUIETS_2_S1, BAD_CAPTURES_S1,
EVASION, EVASIONS_S2,
QSEARCH_0, CAPTURES_S3, QUIET_CHECKS_S3,
QSEARCH_1, CAPTURES_S4,
PROBCUT, CAPTURES_S5,
RECAPTURE, CAPTURES_S6,
STOP
};
// Our insertion sort, which is guaranteed (and also needed) to be stable
void insertion_sort(ExtMove* begin, ExtMove* end)
{
ExtMove tmp, *p, *q;
for (p = begin + 1; p < end; ++p)
{
tmp = *p;
for (q = p; q != begin && *(q-1) < tmp; --q)
*q = *(q-1);
*q = tmp;
}
}
// Unary predicate used by std::partition to split positive values from remaining
// ones so as to sort the two sets separately, with the second sort delayed.
inline bool has_positive_value(const ExtMove& move) { return move.value > 0; }
// Picks the best move in the range (begin, end) and moves it to the front.
// It's faster than sorting all the moves in advance when there are few
// moves e.g. possible captures.
inline ExtMove* pick_best(ExtMove* begin, ExtMove* end)
{
std::swap(*begin, *std::max_element(begin, end));
return begin;
}
} // namespace
/// Constructors of the MovePicker class. As arguments we pass information
/// to help it to return the (presumably) good moves first, to decide which
/// moves to return (in the quiescence search, for instance, we only want to
/// search captures, promotions and some checks) and how important good move
/// ordering is at the current node.
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h,
Move* cm, Move* fm, Search::Stack* s) : pos(p), history(h), depth(d) {
assert(d > DEPTH_ZERO);
cur = end = moves;
endBadCaptures = moves + MAX_MOVES - 1;
countermoves = cm;
followupmoves = fm;
ss = s;
if (pos.checkers())
stage = EVASION;
else
stage = MAIN_SEARCH;
ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE);
end += (ttMove != MOVE_NONE);
}
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h,
Square s) : pos(p), history(h), cur(moves), end(moves) {
assert(d <= DEPTH_ZERO);
if (pos.checkers())
stage = EVASION;
else if (d > DEPTH_QS_NO_CHECKS)
stage = QSEARCH_0;
else if (d > DEPTH_QS_RECAPTURES)
stage = QSEARCH_1;
else
{
stage = RECAPTURE;
recaptureSquare = s;
ttm = MOVE_NONE;
}
ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE);
end += (ttMove != MOVE_NONE);
}
MovePicker::MovePicker(const Position& p, Move ttm, const HistoryStats& h, PieceType pt)
: pos(p), history(h), cur(moves), end(moves) {
assert(!pos.checkers());
stage = PROBCUT;
// In ProbCut we generate only captures that are better than the parent's
// captured piece.
captureThreshold = PieceValue[MG][pt];
ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE);
if (ttMove && (!pos.capture(ttMove) || pos.see(ttMove) <= captureThreshold))
ttMove = MOVE_NONE;
end += (ttMove != MOVE_NONE);
}
/// score() assign a numerical value to each move in a move list. The moves with
/// highest values will be picked first.
template<>
void MovePicker::score<CAPTURES>() {
// Winning and equal captures in the main search are ordered by MVV/LVA.
// Suprisingly, this appears to perform slightly better than SEE based
// move ordering. The reason is probably that in a position with a winning
// capture, capturing a more valuable (but sufficiently defended) piece
// first usually doesn't hurt. The opponent will have to recapture, and
// the hanging piece will still be hanging (except in the unusual cases
// where it is possible to recapture with the hanging piece). Exchanging
// big pieces before capturing a hanging piece probably helps to reduce
// the subtree size.
// In main search we want to push captures with negative SEE values to the
// badCaptures[] array, but instead of doing it now we delay until the move
// has been picked up in pick_move_from_list(). This way we save some SEE
// calls in case we get a cutoff.
Move m;
for (ExtMove* it = moves; it != end; ++it)
{
m = it->move;
it->value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m)));
if (type_of(m) == ENPASSANT)
it->value += PieceValue[MG][PAWN];
else if (type_of(m) == PROMOTION)
it->value += PieceValue[MG][promotion_type(m)] - PieceValue[MG][PAWN];
}
}
template<>
void MovePicker::score<QUIETS>() {
Move m;
for (ExtMove* it = moves; it != end; ++it)
{
m = it->move;
it->value = history[pos.moved_piece(m)][to_sq(m)];
}
}
template<>
void MovePicker::score<EVASIONS>() {
// Try good captures ordered by MVV/LVA, then non-captures if destination square
// is not under attack, ordered by history value, then bad-captures and quiet
// moves with a negative SEE. This last group is ordered by the SEE value.
Move m;
Value see;
for (ExtMove* it = moves; it != end; ++it)
{
m = it->move;
if ((see = pos.see_sign(m)) < VALUE_ZERO)
it->value = see - HistoryStats::Max; // At the bottom
else if (pos.capture(m))
it->value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m))) + HistoryStats::Max;
else
it->value = history[pos.moved_piece(m)][to_sq(m)];
}
}
/// generate_next_stage() generates, scores and sorts the next bunch of moves,
/// when there are no more moves to try for the current stage.
void MovePicker::generate_next_stage() {
cur = moves;
switch (++stage) {
case CAPTURES_S1: case CAPTURES_S3: case CAPTURES_S4: case CAPTURES_S5: case CAPTURES_S6:
end = generate<CAPTURES>(pos, moves);
score<CAPTURES>();
return;
case KILLERS_S1:
cur = killers;
end = cur + 2;
killers[0].move = ss->killers[0];
killers[1].move = ss->killers[1];
killers[2].move = killers[3].move = MOVE_NONE;
killers[4].move = killers[5].move = MOVE_NONE;
// Please note that following code is racy and could yield to rare (less
// than 1 out of a million) duplicated entries in SMP case. This is harmless.
// Be sure countermoves are different from killers
for (int i = 0; i < 2; ++i)
if ( countermoves[i] != (cur+0)->move
&& countermoves[i] != (cur+1)->move)
(end++)->move = countermoves[i];
// Be sure followupmoves are different from killers and countermoves
for (int i = 0; i < 2; ++i)
if ( followupmoves[i] != (cur+0)->move
&& followupmoves[i] != (cur+1)->move
&& followupmoves[i] != (cur+2)->move
&& followupmoves[i] != (cur+3)->move)
(end++)->move = followupmoves[i];
return;
case QUIETS_1_S1:
endQuiets = end = generate<QUIETS>(pos, moves);
score<QUIETS>();
end = std::partition(cur, end, has_positive_value);
insertion_sort(cur, end);
return;
case QUIETS_2_S1:
cur = end;
end = endQuiets;
if (depth >= 3 * ONE_PLY)
insertion_sort(cur, end);
return;
case BAD_CAPTURES_S1:
// Just pick them in reverse order to get MVV/LVA ordering
cur = moves + MAX_MOVES - 1;
end = endBadCaptures;
return;
case EVASIONS_S2:
end = generate<EVASIONS>(pos, moves);
if (end > moves + 1)
score<EVASIONS>();
return;
case QUIET_CHECKS_S3:
end = generate<QUIET_CHECKS>(pos, moves);
return;
case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT: case RECAPTURE:
stage = STOP;
/* Fall through */
case STOP:
end = cur + 1; // Avoid another next_phase() call
return;
default:
assert(false);
}
}
/// next_move() is the most important method of the MovePicker class. It returns
/// a new pseudo legal move every time it is called, until there are no more moves
/// left. It picks the move with the biggest value from a list of generated moves
/// taking care not to return the ttMove if it has already been searched.
template<>
Move MovePicker::next_move<false>() {
Move move;
while (true)
{
while (cur == end)
generate_next_stage();
switch (stage) {
case MAIN_SEARCH: case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT:
++cur;
return ttMove;
case CAPTURES_S1:
move = pick_best(cur++, end)->move;
if (move != ttMove)
{
if (pos.see_sign(move) >= VALUE_ZERO)
return move;
// Losing capture, move it to the tail of the array
(endBadCaptures--)->move = move;
}
break;
case KILLERS_S1:
move = (cur++)->move;
if ( move != MOVE_NONE
&& move != ttMove
&& pos.pseudo_legal(move)
&& !pos.capture(move))
return move;
break;
case QUIETS_1_S1: case QUIETS_2_S1:
move = (cur++)->move;
if ( move != ttMove
&& move != killers[0].move
&& move != killers[1].move
&& move != killers[2].move
&& move != killers[3].move
&& move != killers[4].move
&& move != killers[5].move)
return move;
break;
case BAD_CAPTURES_S1:
return (cur--)->move;
case EVASIONS_S2: case CAPTURES_S3: case CAPTURES_S4:
move = pick_best(cur++, end)->move;
if (move != ttMove)
return move;
break;
case CAPTURES_S5:
move = pick_best(cur++, end)->move;
if (move != ttMove && pos.see(move) > captureThreshold)
return move;
break;
case CAPTURES_S6:
move = pick_best(cur++, end)->move;
if (to_sq(move) == recaptureSquare)
return move;
break;
case QUIET_CHECKS_S3:
move = (cur++)->move;
if (move != ttMove)
return move;
break;
case STOP:
return MOVE_NONE;
default:
assert(false);
}
}
}
/// Version of next_move() to use at split point nodes where the move is grabbed
/// from the split point's shared MovePicker object. This function is not thread
/// safe so must be lock protected by the caller.
template<>
Move MovePicker::next_move<true>() { return ss->splitPoint->movePicker->next_move<false>(); }

View File

@ -1,112 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish 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.
Stockfish 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/>.
*/
#ifndef MOVEPICK_H_INCLUDED
#define MOVEPICK_H_INCLUDED
#include <algorithm> // For std::max
#include <cstring> // For std::memset
#include "movegen.h"
#include "position.h"
#include "search.h"
#include "types.h"
/// The Stats struct stores moves statistics. According to the template parameter
/// the class can store History, Gains and Countermoves. History records how often
/// different moves have been successful or unsuccessful during the current search
/// and is used for reduction and move ordering decisions. Gains records the move's
/// best evaluation gain from one ply to the next and is used for pruning decisions.
/// Countermoves store the move that refute a previous one. Entries are stored
/// using only the moving piece and destination square, hence two moves with
/// different origin but same destination and piece will be considered identical.
template<bool Gain, typename T>
struct Stats {
static const Value Max = Value(250);
const T* operator[](Piece pc) const { return table[pc]; }
void clear() { std::memset(table, 0, sizeof(table)); }
void update(Piece pc, Square to, Move m) {
if (m == table[pc][to].first)
return;
table[pc][to].second = table[pc][to].first;
table[pc][to].first = m;
}
void update(Piece pc, Square to, Value v) {
if (Gain)
table[pc][to] = std::max(v, table[pc][to] - 1);
else if (abs(table[pc][to] + v) < Max)
table[pc][to] += v;
}
private:
T table[PIECE_NB][SQUARE_NB];
};
typedef Stats< true, Value> GainsStats;
typedef Stats<false, Value> HistoryStats;
typedef Stats<false, std::pair<Move, Move> > MovesStats;
/// MovePicker class is used to pick one pseudo legal move at a time from the
/// current position. The most important method is next_move(), which returns a
/// new pseudo legal move each time it is called, until there are no moves left,
/// when MOVE_NONE is returned. In order to improve the efficiency of the alpha
/// beta algorithm, MovePicker attempts to return the moves which are most likely
/// to get a cut-off first.
class MovePicker {
MovePicker& operator=(const MovePicker&); // Silence a warning under MSVC
public:
MovePicker(const Position&, Move, Depth, const HistoryStats&, Square);
MovePicker(const Position&, Move, const HistoryStats&, PieceType);
MovePicker(const Position&, Move, Depth, const HistoryStats&, Move*, Move*, Search::Stack*);
template<bool SpNode> Move next_move();
private:
template<GenType> void score();
void generate_next_stage();
const Position& pos;
const HistoryStats& history;
Search::Stack* ss;
Move* countermoves;
Move* followupmoves;
Depth depth;
Move ttMove;
ExtMove killers[6];
Square recaptureSquare;
Value captureThreshold;
int stage;
ExtMove *cur, *end, *endQuiets, *endBadCaptures;
ExtMove moves[MAX_MOVES];
};
#endif // #ifndef MOVEPICK_H_INCLUDED

View File

@ -1,312 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish 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.
Stockfish 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/>.
*/
#include <algorithm>
#include <cassert>
#include "bitboard.h"
#include "bitcount.h"
#include "pawns.h"
#include "position.h"
#include "thread.h"
namespace {
#define V Value
#define S(mg, eg) make_score(mg, eg)
// Doubled pawn penalty by file
const Score Doubled[FILE_NB] = {
S(13, 43), S(20, 48), S(23, 48), S(23, 48),
S(23, 48), S(23, 48), S(20, 48), S(13, 43) };
// Isolated pawn penalty by opposed flag and file
const Score Isolated[2][FILE_NB] = {
{ S(37, 45), S(54, 52), S(60, 52), S(60, 52),
S(60, 52), S(60, 52), S(54, 52), S(37, 45) },
{ S(25, 30), S(36, 35), S(40, 35), S(40, 35),
S(40, 35), S(40, 35), S(36, 35), S(25, 30) } };
// Backward pawn penalty by opposed flag and file
const Score Backward[2][FILE_NB] = {
{ S(30, 42), S(43, 46), S(49, 46), S(49, 46),
S(49, 46), S(49, 46), S(43, 46), S(30, 42) },
{ S(20, 28), S(29, 31), S(33, 31), S(33, 31),
S(33, 31), S(33, 31), S(29, 31), S(20, 28) } };
// Connected pawn bonus by opposed, phalanx flags and rank
Score Connected[2][2][RANK_NB];
// Levers bonus by rank
const Score Lever[RANK_NB] = {
S( 0, 0), S( 0, 0), S(0, 0), S(0, 0),
S(20,20), S(40,40), S(0, 0), S(0, 0) };
// Unsupported pawn penalty
const Score UnsupportedPawnPenalty = S(20, 10);
// Weakness of our pawn shelter in front of the king by [distance from edge][rank]
const Value ShelterWeakness[][RANK_NB] = {
{ V(100), V(13), V(24), V(64), V(89), V( 93), V(104) },
{ V(110), V( 1), V(29), V(75), V(96), V(102), V(107) },
{ V(102), V( 0), V(39), V(74), V(88), V(101), V( 98) },
{ V( 88), V( 4), V(33), V(67), V(92), V( 94), V(107) } };
// Danger of enemy pawns moving toward our king by [type][distance from edge][rank]
const Value StormDanger[][4][RANK_NB] = {
{ { V( 0), V( 63), V( 128), V(43), V(27) },
{ V( 0), V( 62), V( 131), V(44), V(26) },
{ V( 0), V( 59), V( 121), V(50), V(28) },
{ V( 0), V( 62), V( 127), V(54), V(28) } },
{ { V(24), V( 40), V( 93), V(42), V(22) },
{ V(24), V( 28), V( 101), V(38), V(20) },
{ V(24), V( 32), V( 95), V(36), V(23) },
{ V(27), V( 24), V( 99), V(36), V(24) } },
{ { V( 0), V( 0), V( 81), V(16), V( 6) },
{ V( 0), V( 0), V( 165), V(29), V( 9) },
{ V( 0), V( 0), V( 163), V(23), V(12) },
{ V( 0), V( 0), V( 161), V(28), V(13) } },
{ { V( 0), V(-296), V(-299), V(55), V(25) },
{ V( 0), V( 67), V( 131), V(46), V(21) },
{ V( 0), V( 65), V( 135), V(50), V(31) },
{ V( 0), V( 62), V( 128), V(51), V(24) } } };
// Max bonus for king safety. Corresponds to start position with all the pawns
// in front of the king and no enemy pawn on the horizon.
const Value MaxSafetyBonus = V(257);
#undef S
#undef V
template<Color Us>
Score evaluate(const Position& pos, Pawns::Entry* e) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
const Square Up = (Us == WHITE ? DELTA_N : DELTA_S);
const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW);
const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE);
Bitboard b, p, doubled, connected;
Square s;
bool passed, isolated, opposed, phalanx, backward, unsupported, lever;
Score score = SCORE_ZERO;
const Square* pl = pos.list<PAWN>(Us);
const Bitboard* pawnAttacksBB = StepAttacksBB[make_piece(Us, PAWN)];
Bitboard ourPawns = pos.pieces(Us , PAWN);
Bitboard theirPawns = pos.pieces(Them, PAWN);
e->passedPawns[Us] = 0;
e->kingSquares[Us] = SQ_NONE;
e->semiopenFiles[Us] = 0xFF;
e->pawnAttacks[Us] = shift_bb<Right>(ourPawns) | shift_bb<Left>(ourPawns);
e->pawnsOnSquares[Us][BLACK] = popcount<Max15>(ourPawns & DarkSquares);
e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK];
// Loop through all pawns of the current color and score each pawn
while ((s = *pl++) != SQ_NONE)
{
assert(pos.piece_on(s) == make_piece(Us, PAWN));
File f = file_of(s);
// This file cannot be semi-open
e->semiopenFiles[Us] &= ~(1 << f);
// Previous rank
p = rank_bb(s - pawn_push(Us));
// Flag the pawn as passed, isolated, doubled,
// unsupported or connected (but not the backward one).
connected = ourPawns & adjacent_files_bb(f) & (rank_bb(s) | p);
phalanx = connected & rank_bb(s);
unsupported = !(ourPawns & adjacent_files_bb(f) & p);
isolated = !(ourPawns & adjacent_files_bb(f));
doubled = ourPawns & forward_bb(Us, s);
opposed = theirPawns & forward_bb(Us, s);
passed = !(theirPawns & passed_pawn_mask(Us, s));
lever = theirPawns & pawnAttacksBB[s];
// Test for backward pawn.
// If the pawn is passed, isolated, or connected it cannot be
// backward. If there are friendly pawns behind on adjacent files
// or if it can capture an enemy pawn it cannot be backward either.
if ( (passed | isolated | connected)
|| (ourPawns & pawn_attack_span(Them, s))
|| (pos.attacks_from<PAWN>(s, Us) & theirPawns))
backward = false;
else
{
// We now know that there are no friendly pawns beside or behind this
// pawn on adjacent files. We now check whether the pawn is
// backward by looking in the forward direction on the adjacent
// files, and picking the closest pawn there.
b = pawn_attack_span(Us, s) & (ourPawns | theirPawns);
b = pawn_attack_span(Us, s) & rank_bb(backmost_sq(Us, b));
// If we have an enemy pawn in the same or next rank, the pawn is
// backward because it cannot advance without being captured.
backward = (b | shift_bb<Up>(b)) & theirPawns;
}
assert(opposed | passed | (pawn_attack_span(Us, s) & theirPawns));
// Passed pawns will be properly scored in evaluation because we need
// full attack info to evaluate passed pawns. Only the frontmost passed
// pawn on each file is considered a true passed pawn.
if (passed && !doubled)
e->passedPawns[Us] |= s;
// Score this pawn
if (isolated)
score -= Isolated[opposed][f];
if (unsupported && !isolated)
score -= UnsupportedPawnPenalty;
if (doubled)
score -= Doubled[f] / distance<Rank>(s, frontmost_sq(Us, doubled));
if (backward)
score -= Backward[opposed][f];
if (connected)
score += Connected[opposed][phalanx][relative_rank(Us, s)];
if (lever)
score += Lever[relative_rank(Us, s)];
}
b = e->semiopenFiles[Us] ^ 0xFF;
e->pawnSpan[Us] = b ? int(msb(b) - lsb(b)) : 0;
return score;
}
} // namespace
namespace Pawns {
/// Pawns::init() initializes some tables needed by evaluation. Instead of using
/// hard-coded tables, when makes sense, we prefer to calculate them with a formula
/// to reduce independent parameters and to allow easier tuning and better insight.
void init()
{
static const int Seed[RANK_NB] = { 0, 6, 15, 10, 57, 75, 135, 258 };
for (int opposed = 0; opposed <= 1; ++opposed)
for (int phalanx = 0; phalanx <= 1; ++phalanx)
for (Rank r = RANK_2; r < RANK_8; ++r)
{
int bonus = Seed[r] + (phalanx ? (Seed[r + 1] - Seed[r]) / 2 : 0);
Connected[opposed][phalanx][r] = make_score(bonus / 2, bonus >> opposed);
}
}
/// Pawns::probe() looks up the current position's pawns configuration in
/// the pawns hash table. It returns a pointer to the Entry if the position
/// is found. Otherwise a new Entry is computed and stored there, so we don't
/// have to recompute all when the same pawns configuration occurs again.
Entry* probe(const Position& pos) {
Key key = pos.pawn_key();
Entry* e = pos.this_thread()->pawnsTable[key];
if (e->key == key)
return e;
e->key = key;
e->score = evaluate<WHITE>(pos, e) - evaluate<BLACK>(pos, e);
return e;
}
/// Entry::shelter_storm() calculates shelter and storm penalties for the file
/// the king is on, as well as the two adjacent files.
template<Color Us>
Value Entry::shelter_storm(const Position& pos, Square ksq) {
const Color Them = (Us == WHITE ? BLACK : WHITE);
enum { NoFriendlyPawn, Unblocked, BlockedByPawn, BlockedByKing };
Bitboard b = pos.pieces(PAWN) & (in_front_bb(Us, rank_of(ksq)) | rank_bb(ksq));
Bitboard ourPawns = b & pos.pieces(Us);
Bitboard theirPawns = b & pos.pieces(Them);
Value safety = MaxSafetyBonus;
File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq)));
for (File f = center - File(1); f <= center + File(1); ++f)
{
b = ourPawns & file_bb(f);
Rank rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1;
b = theirPawns & file_bb(f);
Rank rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
safety -= ShelterWeakness[std::min(f, FILE_H - f)][rkUs]
+ StormDanger
[f == file_of(ksq) && rkThem == relative_rank(Us, ksq) + 1 ? BlockedByKing :
rkUs == RANK_1 ? NoFriendlyPawn :
rkThem == rkUs + 1 ? BlockedByPawn : Unblocked]
[std::min(f, FILE_H - f)][rkThem];
}
return safety;
}
/// Entry::do_king_safety() calculates a bonus for king safety. It is called only
/// when king square changes, which is about 20% of total king_safety() calls.
template<Color Us>
Score Entry::do_king_safety(const Position& pos, Square ksq) {
kingSquares[Us] = ksq;
castlingRights[Us] = pos.can_castle(Us);
minKingPawnDistance[Us] = 0;
Bitboard pawns = pos.pieces(Us, PAWN);
if (pawns)
while (!(DistanceRingBB[ksq][minKingPawnDistance[Us]++] & pawns)) {}
if (relative_rank(Us, ksq) > RANK_4)
return make_score(0, -16 * minKingPawnDistance[Us]);
Value bonus = shelter_storm<Us>(pos, ksq);
// If we can castle use the bonus after the castling if it is bigger
if (pos.can_castle(MakeCastling<Us, KING_SIDE>::right))
bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_G1)));
if (pos.can_castle(MakeCastling<Us, QUEEN_SIDE>::right))
bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_C1)));
return make_score(bonus, -16 * minKingPawnDistance[Us]);
}
// Explicit template instantiation
template Score Entry::do_king_safety<WHITE>(const Position& pos, Square ksq);
template Score Entry::do_king_safety<BLACK>(const Position& pos, Square ksq);
} // namespace Pawns

View File

@ -1,87 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish 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.
Stockfish 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/>.
*/
#ifndef PAWNS_H_INCLUDED
#define PAWNS_H_INCLUDED
#include "misc.h"
#include "position.h"
#include "types.h"
namespace Pawns {
/// Pawns::Entry contains various information about a pawn structure. A lookup
/// to the pawn hash table (performed by calling the probe function) returns a
/// pointer to an Entry object.
struct Entry {
Score pawns_score() const { return score; }
Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; }
Bitboard passed_pawns(Color c) const { return passedPawns[c]; }
int semiopen_file(Color c, File f) const {
return semiopenFiles[c] & (1 << f);
}
int semiopen_side(Color c, File f, bool leftSide) const {
return semiopenFiles[c] & (leftSide ? (1 << f) - 1 : ~((1 << (f + 1)) - 1));
}
int pawn_span(Color c) const {
return pawnSpan[c];
}
int pawns_on_same_color_squares(Color c, Square s) const {
return pawnsOnSquares[c][!!(DarkSquares & s)];
}
template<Color Us>
Score king_safety(const Position& pos, Square ksq) {
return kingSquares[Us] == ksq && castlingRights[Us] == pos.can_castle(Us)
? kingSafety[Us] : (kingSafety[Us] = do_king_safety<Us>(pos, ksq));
}
template<Color Us>
Score do_king_safety(const Position& pos, Square ksq);
template<Color Us>
Value shelter_storm(const Position& pos, Square ksq);
Key key;
Score score;
Bitboard passedPawns[COLOR_NB];
Bitboard pawnAttacks[COLOR_NB];
Square kingSquares[COLOR_NB];
Score kingSafety[COLOR_NB];
int minKingPawnDistance[COLOR_NB];
int castlingRights[COLOR_NB];
int semiopenFiles[COLOR_NB];
int pawnSpan[COLOR_NB];
int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares]
};
typedef HashTable<Entry, 16384> Table;
void init();
Entry* probe(const Position& pos);
} // namespace Pawns
#endif // #ifndef PAWNS_H_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@ -1,439 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad
Stockfish 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.
Stockfish 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/>.
*/
#ifndef POSITION_H_INCLUDED
#define POSITION_H_INCLUDED
#include <cassert>
#include <cstddef> // For offsetof()
#include "bitboard.h"
#include "types.h"
class Position;
struct Thread;
/// CheckInfo struct is initialized at c'tor time and keeps info used to detect
/// if a move gives check.
struct CheckInfo {
explicit CheckInfo(const Position&);
Bitboard dcCandidates;
Bitboard pinned;
Bitboard checkSq[PIECE_TYPE_NB];
Square ksq;
};
/// StateInfo struct stores information needed to restore a Position object to
/// its previous state when we retract a move. Whenever a move is made on the
/// board (by calling Position::do_move), a StateInfo object must be passed.
struct StateInfo {
// Copied when making a move
Key pawnKey;
Key materialKey;
Value nonPawnMaterial[COLOR_NB];
int castlingRights;
int rule50;
int pliesFromNull;
Score psq;
Square epSquare;
// Not copied when making a move
Key key;
Bitboard checkersBB;
PieceType capturedType;
StateInfo* previous;
};
/// When making a move the current StateInfo up to 'key' excluded is copied to
/// the new one. Here we calculate the quad words (64 bit) needed to be copied.
const size_t StateCopySize64 = offsetof(StateInfo, key) / sizeof(uint64_t) + 1;
/// Position class stores information regarding the board representation as
/// pieces, side to move, hash keys, castling info, etc. Important methods are
/// do_move() and undo_move(), used by the search to update node info when
/// traversing the search tree.
class Position {
friend std::ostream& operator<<(std::ostream&, const Position&);
Position(const Position&); // Disable the default copy constructor
public:
static void init();
Position() {} // To define the global object RootPos
Position(const Position& pos, Thread* th) { *this = pos; thisThread = th; }
Position(const std::string& f, bool c960, Thread* th) { set(f, c960, th); }
Position& operator=(const Position&); // To assign RootPos from UCI
// FEN string input/output
void set(const std::string& fenStr, bool isChess960, Thread* th);
const std::string fen() const;
// Position representation
Bitboard pieces() const;
Bitboard pieces(PieceType pt) const;
Bitboard pieces(PieceType pt1, PieceType pt2) const;
Bitboard pieces(Color c) const;
Bitboard pieces(Color c, PieceType pt) const;
Bitboard pieces(Color c, PieceType pt1, PieceType pt2) const;
Piece piece_on(Square s) const;
Square king_square(Color c) const;
Square ep_square() const;
bool empty(Square s) const;
template<PieceType Pt> int count(Color c) const;
template<PieceType Pt> const Square* list(Color c) const;
// Castling
int can_castle(Color c) const;
int can_castle(CastlingRight cr) const;
bool castling_impeded(CastlingRight cr) const;
Square castling_rook_square(CastlingRight cr) const;
// Checking
Bitboard checkers() const;
Bitboard discovered_check_candidates() const;
Bitboard pinned_pieces(Color c) const;
// Attacks to/from a given square
Bitboard attackers_to(Square s) const;
Bitboard attackers_to(Square s, Bitboard occupied) const;
Bitboard attacks_from(Piece pc, Square s) const;
template<PieceType> Bitboard attacks_from(Square s) const;
template<PieceType> Bitboard attacks_from(Square s, Color c) const;
// Properties of moves
bool legal(Move m, Bitboard pinned) const;
bool pseudo_legal(const Move m) const;
bool capture(Move m) const;
bool capture_or_promotion(Move m) const;
bool gives_check(Move m, const CheckInfo& ci) const;
bool advanced_pawn_push(Move m) const;
Piece moved_piece(Move m) const;
PieceType captured_piece_type() const;
// Piece specific
bool pawn_passed(Color c, Square s) const;
bool pawn_on_7th(Color c) const;
bool opposite_bishops() const;
// Doing and undoing moves
void do_move(Move m, StateInfo& st);
void do_move(Move m, StateInfo& st, const CheckInfo& ci, bool moveIsCheck);
void undo_move(Move m);
void do_null_move(StateInfo& st);
void undo_null_move();
// Static exchange evaluation
Value see(Move m) const;
Value see_sign(Move m) const;
// Accessing hash keys
Key key() const;
Key key_after(Move m) const;
Key exclusion_key() const;
Key material_key() const;
Key pawn_key() const;
// Other properties of the position
Color side_to_move() const;
Phase game_phase() const;
int game_ply() const;
bool is_chess960() const;
Thread* this_thread() const;
uint64_t nodes_searched() const;
void set_nodes_searched(uint64_t n);
bool is_draw() const;
int rule50_count() const;
Score psq_score() const;
Value non_pawn_material(Color c) const;
// Position consistency check, for debugging
bool pos_is_ok(int* step = NULL) const;
void flip();
private:
// Initialization helpers (used while setting up a position)
void clear();
void set_castling_right(Color c, Square rfrom);
void set_state(StateInfo* si) const;
// Other helpers
Bitboard check_blockers(Color c, Color kingColor) const;
void put_piece(Square s, Color c, PieceType pt);
void remove_piece(Square s, Color c, PieceType pt);
void move_piece(Square from, Square to, Color c, PieceType pt);
template<bool Do>
void do_castling(Square from, Square& to, Square& rfrom, Square& rto);
// Data members
Piece board[SQUARE_NB];
Bitboard byTypeBB[PIECE_TYPE_NB];
Bitboard byColorBB[COLOR_NB];
int pieceCount[COLOR_NB][PIECE_TYPE_NB];
Square pieceList[COLOR_NB][PIECE_TYPE_NB][16];
int index[SQUARE_NB];
int castlingRightsMask[SQUARE_NB];
Square castlingRookSquare[CASTLING_RIGHT_NB];
Bitboard castlingPath[CASTLING_RIGHT_NB];
StateInfo startState;
uint64_t nodes;
int gamePly;
Color sideToMove;
Thread* thisThread;
StateInfo* st;
bool chess960;
};
inline Color Position::side_to_move() const {
return sideToMove;
}
inline bool Position::empty(Square s) const {
return board[s] == NO_PIECE;
}
inline Piece Position::piece_on(Square s) const {
return board[s];
}
inline Piece Position::moved_piece(Move m) const {
return board[from_sq(m)];
}
inline Bitboard Position::pieces() const {
return byTypeBB[ALL_PIECES];
}
inline Bitboard Position::pieces(PieceType pt) const {
return byTypeBB[pt];
}
inline Bitboard Position::pieces(PieceType pt1, PieceType pt2) const {
return byTypeBB[pt1] | byTypeBB[pt2];
}
inline Bitboard Position::pieces(Color c) const {
return byColorBB[c];
}
inline Bitboard Position::pieces(Color c, PieceType pt) const {
return byColorBB[c] & byTypeBB[pt];
}
inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const {
return byColorBB[c] & (byTypeBB[pt1] | byTypeBB[pt2]);
}
template<PieceType Pt> inline int Position::count(Color c) const {
return pieceCount[c][Pt];
}
template<PieceType Pt> inline const Square* Position::list(Color c) const {
return pieceList[c][Pt];
}
inline Square Position::king_square(Color c) const {
return pieceList[c][KING][0];
}
inline Square Position::ep_square() const {
return st->epSquare;
}
inline int Position::can_castle(CastlingRight cr) const {
return st->castlingRights & cr;
}
inline int Position::can_castle(Color c) const {
return st->castlingRights & ((WHITE_OO | WHITE_OOO) << (2 * c));
}
inline bool Position::castling_impeded(CastlingRight cr) const {
return byTypeBB[ALL_PIECES] & castlingPath[cr];
}
inline Square Position::castling_rook_square(CastlingRight cr) const {
return castlingRookSquare[cr];
}
template<PieceType Pt>
inline Bitboard Position::attacks_from(Square s) const {
return Pt == BISHOP || Pt == ROOK ? attacks_bb<Pt>(s, byTypeBB[ALL_PIECES])
: Pt == QUEEN ? attacks_from<ROOK>(s) | attacks_from<BISHOP>(s)
: StepAttacksBB[Pt][s];
}
template<>
inline Bitboard Position::attacks_from<PAWN>(Square s, Color c) const {
return StepAttacksBB[make_piece(c, PAWN)][s];
}
inline Bitboard Position::attacks_from(Piece pc, Square s) const {
return attacks_bb(pc, s, byTypeBB[ALL_PIECES]);
}
inline Bitboard Position::attackers_to(Square s) const {
return attackers_to(s, byTypeBB[ALL_PIECES]);
}
inline Bitboard Position::checkers() const {
return st->checkersBB;
}
inline Bitboard Position::discovered_check_candidates() const {
return check_blockers(sideToMove, ~sideToMove);
}
inline Bitboard Position::pinned_pieces(Color c) const {
return check_blockers(c, c);
}
inline bool Position::pawn_passed(Color c, Square s) const {
return !(pieces(~c, PAWN) & passed_pawn_mask(c, s));
}
inline bool Position::advanced_pawn_push(Move m) const {
return type_of(moved_piece(m)) == PAWN
&& relative_rank(sideToMove, from_sq(m)) > RANK_4;
}
inline Key Position::key() const {
return st->key;
}
inline Key Position::pawn_key() const {
return st->pawnKey;
}
inline Key Position::material_key() const {
return st->materialKey;
}
inline Score Position::psq_score() const {
return st->psq;
}
inline Value Position::non_pawn_material(Color c) const {
return st->nonPawnMaterial[c];
}
inline int Position::game_ply() const {
return gamePly;
}
inline int Position::rule50_count() const {
return st->rule50;
}
inline uint64_t Position::nodes_searched() const {
return nodes;
}
inline void Position::set_nodes_searched(uint64_t n) {
nodes = n;
}
inline bool Position::opposite_bishops() const {
return pieceCount[WHITE][BISHOP] == 1
&& pieceCount[BLACK][BISHOP] == 1
&& opposite_colors(pieceList[WHITE][BISHOP][0], pieceList[BLACK][BISHOP][0]);
}
inline bool Position::pawn_on_7th(Color c) const {
return pieces(c, PAWN) & rank_bb(relative_rank(c, RANK_7));
}
inline bool Position::is_chess960() const {
return chess960;
}
inline bool Position::capture_or_promotion(Move m) const {
assert(is_ok(m));
return type_of(m) != NORMAL ? type_of(m) != CASTLING : !empty(to_sq(m));
}
inline bool Position::capture(Move m) const {
// Castling is encoded as "king captures the rook"
assert(is_ok(m));
return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == ENPASSANT;
}
inline PieceType Position::captured_piece_type() const {
return st->capturedType;
}
inline Thread* Position::this_thread() const {
return thisThread;
}
inline void Position::put_piece(Square s, Color c, PieceType pt) {
board[s] = make_piece(c, pt);
byTypeBB[ALL_PIECES] |= s;
byTypeBB[pt] |= s;
byColorBB[c] |= s;
index[s] = pieceCount[c][pt]++;
pieceList[c][pt][index[s]] = s;
pieceCount[c][ALL_PIECES]++;
}
inline void Position::move_piece(Square from, Square to, Color c, PieceType pt) {
// index[from] is not updated and becomes stale. This works as long as index[]
// is accessed just by known occupied squares.
Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to];
byTypeBB[ALL_PIECES] ^= from_to_bb;
byTypeBB[pt] ^= from_to_bb;
byColorBB[c] ^= from_to_bb;
board[from] = NO_PIECE;
board[to] = make_piece(c, pt);
index[to] = index[from];
pieceList[c][pt][index[to]] = to;
}
inline void Position::remove_piece(Square s, Color c, PieceType pt) {
// WARNING: This is not a reversible operation. If we remove a piece in
// do_move() and then replace it in undo_move() we will put it at the end of
// the list and not in its original place, it means index[] and pieceList[]
// are not guaranteed to be invariant to a do_move() + undo_move() sequence.
byTypeBB[ALL_PIECES] ^= s;
byTypeBB[pt] ^= s;
byColorBB[c] ^= s;
/* board[s] = NO_PIECE; Not needed, overwritten by the capturing one */
Square lastSquare = pieceList[c][pt][--pieceCount[c][pt]];
index[lastSquare] = index[s];
pieceList[c][pt][index[lastSquare]] = lastSquare;
pieceList[c][pt][pieceCount[c][pt]] = SQ_NONE;
pieceCount[c][ALL_PIECES]--;
}
#endif // #ifndef POSITION_H_INCLUDED