mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2024-11-27 14:15:16 +01:00
DroidFish: Updated stockfish engine to git version from 2016-09-17.
This commit is contained in:
parent
ad63e43412
commit
c144bb9800
|
@ -206,21 +206,15 @@ namespace {
|
|||
#undef S
|
||||
#undef V
|
||||
|
||||
// King danger constants and variables. The king danger scores are looked-up
|
||||
// in KingDanger[]. Various little "meta-bonuses" measuring the strength
|
||||
// of the enemy attack are added up into an integer, which is used as an
|
||||
// index to KingDanger[].
|
||||
Score KingDanger[512];
|
||||
|
||||
// KingAttackWeights[PieceType] contains king attack weights by piece type
|
||||
const int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 7, 5, 4, 1 };
|
||||
const int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 78, 56, 45, 11 };
|
||||
|
||||
// Penalties for enemy's safe checks
|
||||
const int QueenContactCheck = 89;
|
||||
const int QueenCheck = 62;
|
||||
const int RookCheck = 57;
|
||||
const int BishopCheck = 48;
|
||||
const int KnightCheck = 78;
|
||||
const int QueenContactCheck = 997;
|
||||
const int QueenCheck = 695;
|
||||
const int RookCheck = 638;
|
||||
const int BishopCheck = 538;
|
||||
const int KnightCheck = 874;
|
||||
|
||||
|
||||
// eval_init() initializes king and attack bitboards for a given color
|
||||
|
@ -360,7 +354,8 @@ namespace {
|
|||
if (Pt == QUEEN)
|
||||
{
|
||||
// Penalty if any relative pin or discovered attack against the queen
|
||||
if (pos.slider_blockers(pos.pieces(Them, ROOK, BISHOP), s))
|
||||
Bitboard pinners;
|
||||
if (pos.slider_blockers(pos.pieces(Them, ROOK, BISHOP), s, pinners))
|
||||
score -= WeakQueen;
|
||||
}
|
||||
}
|
||||
|
@ -400,7 +395,7 @@ namespace {
|
|||
const Square Up = (Us == WHITE ? DELTA_N : DELTA_S);
|
||||
|
||||
Bitboard undefended, b, b1, b2, safe, other;
|
||||
int attackUnits;
|
||||
int kingDanger;
|
||||
const Square ksq = pos.square<KING>(Us);
|
||||
|
||||
// King shelter and enemy pawns storm
|
||||
|
@ -418,24 +413,24 @@ namespace {
|
|||
b = ei.attackedBy[Them][ALL_PIECES] & ~ei.attackedBy[Us][ALL_PIECES]
|
||||
& ei.kingRing[Us] & ~pos.pieces(Them);
|
||||
|
||||
// Initialize the 'attackUnits' variable, which is used later on as an
|
||||
// index into the KingDanger[] array. The initial value is based on the
|
||||
// Initialize the 'kingDanger' variable, which will be transformed
|
||||
// later into a king danger score. The initial value is based on the
|
||||
// number and types of the enemy's attacking pieces, the number of
|
||||
// attacked and undefended squares around our king and the quality of
|
||||
// the pawn shelter (current 'score' value).
|
||||
attackUnits = std::min(72, ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them])
|
||||
+ 9 * ei.kingAdjacentZoneAttacksCount[Them]
|
||||
+ 21 * popcount(undefended)
|
||||
+ 12 * (popcount(b) + !!ei.pinnedPieces[Us])
|
||||
- 64 * !pos.count<QUEEN>(Them)
|
||||
- mg_value(score) / 8;
|
||||
kingDanger = std::min(807, ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them])
|
||||
+ 101 * ei.kingAdjacentZoneAttacksCount[Them]
|
||||
+ 235 * popcount(undefended)
|
||||
+ 134 * (popcount(b) + !!ei.pinnedPieces[Us])
|
||||
- 717 * !pos.count<QUEEN>(Them)
|
||||
- 7 * mg_value(score) / 5 - 5;
|
||||
|
||||
// Analyse the enemy's safe queen contact checks. Firstly, find the
|
||||
// undefended squares around the king reachable by the enemy queen...
|
||||
b = undefended & ei.attackedBy[Them][QUEEN] & ~pos.pieces(Them);
|
||||
|
||||
// ...and keep squares supported by another enemy piece
|
||||
attackUnits += QueenContactCheck * popcount(b & ei.attackedBy2[Them]);
|
||||
kingDanger += QueenContactCheck * popcount(b & ei.attackedBy2[Them]);
|
||||
|
||||
// Analyse the safe enemy's checks which are possible on next move...
|
||||
safe = ~(ei.attackedBy[Us][ALL_PIECES] | pos.pieces(Them));
|
||||
|
@ -450,7 +445,7 @@ namespace {
|
|||
|
||||
// Enemy queen safe checks
|
||||
if ((b1 | b2) & ei.attackedBy[Them][QUEEN] & safe)
|
||||
attackUnits += QueenCheck, score -= SafeCheck;
|
||||
kingDanger += QueenCheck, score -= SafeCheck;
|
||||
|
||||
// For other pieces, also consider the square safe if attacked twice,
|
||||
// and only defended by a queen.
|
||||
|
@ -460,14 +455,14 @@ namespace {
|
|||
|
||||
// Enemy rooks safe and other checks
|
||||
if (b1 & ei.attackedBy[Them][ROOK] & safe)
|
||||
attackUnits += RookCheck, score -= SafeCheck;
|
||||
kingDanger += RookCheck, score -= SafeCheck;
|
||||
|
||||
else if (b1 & ei.attackedBy[Them][ROOK] & other)
|
||||
score -= OtherCheck;
|
||||
|
||||
// Enemy bishops safe and other checks
|
||||
if (b2 & ei.attackedBy[Them][BISHOP] & safe)
|
||||
attackUnits += BishopCheck, score -= SafeCheck;
|
||||
kingDanger += BishopCheck, score -= SafeCheck;
|
||||
|
||||
else if (b2 & ei.attackedBy[Them][BISHOP] & other)
|
||||
score -= OtherCheck;
|
||||
|
@ -475,14 +470,14 @@ namespace {
|
|||
// Enemy knights safe and other checks
|
||||
b = pos.attacks_from<KNIGHT>(ksq) & ei.attackedBy[Them][KNIGHT];
|
||||
if (b & safe)
|
||||
attackUnits += KnightCheck, score -= SafeCheck;
|
||||
kingDanger += KnightCheck, score -= SafeCheck;
|
||||
|
||||
else if (b & other)
|
||||
score -= OtherCheck;
|
||||
|
||||
// Finally, extract the king danger score from the KingDanger[]
|
||||
// array and subtract the score from the evaluation.
|
||||
score -= KingDanger[std::max(std::min(attackUnits, 399), 0)];
|
||||
// Compute the king danger score and subtract it from the evaluation
|
||||
if (kingDanger > 0)
|
||||
score -= make_score(std::min(kingDanger * kingDanger / 4096, 2 * int(BishopValueMg)), 0);
|
||||
}
|
||||
|
||||
// King tropism: firstly, find squares that opponent attacks in our king flank
|
||||
|
@ -706,9 +701,9 @@ namespace {
|
|||
// ...count safe + (behind & safe) with a single popcount
|
||||
int bonus = popcount((Us == WHITE ? safe << 32 : safe >> 32) | (behind & safe));
|
||||
bonus = std::min(16, bonus);
|
||||
int weight = pos.count<ALL_PIECES>(Us);
|
||||
int weight = pos.count<ALL_PIECES>(Us) - 2 * ei.pi->open_files();
|
||||
|
||||
return make_score(bonus * weight * weight / 22, 0);
|
||||
return make_score(bonus * weight * weight / 18, 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -779,23 +774,22 @@ Value Eval::evaluate(const Position& pos) {
|
|||
|
||||
assert(!pos.checkers());
|
||||
|
||||
Score mobility[COLOR_NB] = { SCORE_ZERO, SCORE_ZERO };
|
||||
EvalInfo ei;
|
||||
Score score, mobility[COLOR_NB] = { SCORE_ZERO, SCORE_ZERO };
|
||||
|
||||
// Initialize score by reading the incrementally updated scores included in
|
||||
// the position object (material + piece square tables). Score is computed
|
||||
// internally from the white point of view.
|
||||
score = pos.psq_score();
|
||||
|
||||
// Probe the material hash table
|
||||
ei.me = Material::probe(pos);
|
||||
score += ei.me->imbalance();
|
||||
|
||||
// If we have a specialized evaluation function for the current material
|
||||
// configuration, call it and return.
|
||||
if (ei.me->specialized_eval_exists())
|
||||
return ei.me->evaluate(pos);
|
||||
|
||||
// Initialize score by reading the incrementally updated scores included in
|
||||
// the position object (material + piece square tables) and the material
|
||||
// imbalance. Score is computed internally from the white point of view.
|
||||
Score score = pos.psq_score() + ei.me->imbalance();
|
||||
|
||||
// Probe the pawn hash table
|
||||
ei.pi = Pawns::probe(pos);
|
||||
score += ei.pi->pawns_score();
|
||||
|
@ -920,19 +914,3 @@ std::string Eval::trace(const Position& pos) {
|
|||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
/// init() computes evaluation weights, usually at startup
|
||||
|
||||
void Eval::init() {
|
||||
|
||||
const int MaxSlope = 322;
|
||||
const int Peak = 47410;
|
||||
int t = 0;
|
||||
|
||||
for (int i = 0; i < 400; ++i)
|
||||
{
|
||||
t = std::min(Peak, std::min(i * i - 16, t + MaxSlope));
|
||||
KingDanger[i] = make_score(t * 268 / 7700, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ namespace Eval {
|
|||
|
||||
const Value Tempo = Value(20); // Must be visible to search
|
||||
|
||||
void init();
|
||||
std::string trace(const Position& pos);
|
||||
|
||||
template<bool DoTrace = false>
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <iostream>
|
||||
|
||||
#include "bitboard.h"
|
||||
#include "evaluate.h"
|
||||
#include "position.h"
|
||||
#include "search.h"
|
||||
#include "thread.h"
|
||||
|
@ -29,6 +28,10 @@
|
|||
#include "uci.h"
|
||||
#include "syzygy/tbprobe.h"
|
||||
|
||||
namespace PSQT {
|
||||
void init();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
std::cout << engine_info() << std::endl;
|
||||
|
@ -39,7 +42,6 @@ int main(int argc, char* argv[]) {
|
|||
Position::init();
|
||||
Bitbases::init();
|
||||
Search::init();
|
||||
Eval::init();
|
||||
Pawns::init();
|
||||
Threads.init();
|
||||
Tablebases::init(Options["SyzygyPath"]);
|
||||
|
|
|
@ -31,13 +31,10 @@ namespace {
|
|||
|
||||
// Polynomial material imbalance parameters
|
||||
|
||||
// pair pawn knight bishop rook queen
|
||||
const int Linear[6] = { 1667, -168, -1027, -166, 238, -138 };
|
||||
|
||||
const int QuadraticOurs[][PIECE_TYPE_NB] = {
|
||||
// OUR PIECES
|
||||
// pair pawn knight bishop rook queen
|
||||
{ 0 }, // Bishop pair
|
||||
{1667 }, // Bishop pair
|
||||
{ 40, 2 }, // Pawn
|
||||
{ 32, 255, -3 }, // Knight OUR PIECES
|
||||
{ 0, 104, 4, 0 }, // Bishop
|
||||
|
@ -100,7 +97,7 @@ namespace {
|
|||
if (!pieceCount[Us][pt1])
|
||||
continue;
|
||||
|
||||
int v = Linear[pt1];
|
||||
int v = 0;
|
||||
|
||||
for (int pt2 = NO_PIECE_TYPE; pt2 <= pt1; ++pt2)
|
||||
v += QuadraticOurs[pt1][pt2] * pieceCount[Us][pt2]
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace {
|
|||
|
||||
/// Version number. If Version is left empty, then compile date in the format
|
||||
/// DD-MM-YY and show in engine_info.
|
||||
const string Version = "2016-08-28";
|
||||
const string Version = "2016-09-17";
|
||||
|
||||
/// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
|
||||
/// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
|
||||
|
|
|
@ -26,13 +26,12 @@
|
|||
namespace {
|
||||
|
||||
enum Stages {
|
||||
MAIN_SEARCH, GOOD_CAPTURES, KILLERS, QUIET, BAD_CAPTURES,
|
||||
EVASION, ALL_EVASIONS,
|
||||
QSEARCH_WITH_CHECKS, QCAPTURES_1, CHECKS,
|
||||
QSEARCH_WITHOUT_CHECKS, QCAPTURES_2,
|
||||
PROBCUT, PROBCUT_CAPTURES,
|
||||
RECAPTURE, RECAPTURES,
|
||||
STOP
|
||||
MAIN_SEARCH, CAPTURES_INIT, GOOD_CAPTURES, KILLERS, COUNTERMOVE, QUIET_INIT, QUIET, BAD_CAPTURES,
|
||||
EVASION, EVASIONS_INIT, ALL_EVASIONS,
|
||||
PROBCUT, PROBCUT_INIT, PROBCUT_CAPTURES,
|
||||
QSEARCH_WITH_CHECKS, QCAPTURES_1_INIT, QCAPTURES_1, QCHECKS,
|
||||
QSEARCH_NO_CHECKS, QCAPTURES_2_INIT, QCAPTURES_2,
|
||||
QSEARCH_RECAPTURES, QRECAPTURES
|
||||
};
|
||||
|
||||
// Our insertion sort, which is guaranteed to be stable, as it should be
|
||||
|
@ -77,7 +76,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Search::Stack* s)
|
|||
|
||||
stage = pos.checkers() ? EVASION : MAIN_SEARCH;
|
||||
ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
|
||||
endMoves += (ttMove != MOVE_NONE);
|
||||
stage += (ttMove == MOVE_NONE);
|
||||
}
|
||||
|
||||
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Square s)
|
||||
|
@ -92,17 +91,17 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Square s)
|
|||
stage = QSEARCH_WITH_CHECKS;
|
||||
|
||||
else if (d > DEPTH_QS_RECAPTURES)
|
||||
stage = QSEARCH_WITHOUT_CHECKS;
|
||||
stage = QSEARCH_NO_CHECKS;
|
||||
|
||||
else
|
||||
{
|
||||
stage = RECAPTURE;
|
||||
stage = QSEARCH_RECAPTURES;
|
||||
recaptureSquare = s;
|
||||
ttm = MOVE_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
|
||||
endMoves += (ttMove != MOVE_NONE);
|
||||
stage += (ttMove == MOVE_NONE);
|
||||
}
|
||||
|
||||
MovePicker::MovePicker(const Position& p, Move ttm, Value th)
|
||||
|
@ -118,7 +117,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Value th)
|
|||
&& pos.capture(ttm)
|
||||
&& pos.see(ttm) > threshold ? ttm : MOVE_NONE;
|
||||
|
||||
endMoves += (ttMove != MOVE_NONE);
|
||||
stage += (ttMove == MOVE_NONE);
|
||||
}
|
||||
|
||||
|
||||
|
@ -180,70 +179,6 @@ void MovePicker::score<EVASIONS>() {
|
|||
}
|
||||
|
||||
|
||||
/// 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() {
|
||||
|
||||
assert(stage != STOP);
|
||||
|
||||
cur = moves;
|
||||
|
||||
switch (++stage) {
|
||||
|
||||
case GOOD_CAPTURES: case QCAPTURES_1: case QCAPTURES_2:
|
||||
case PROBCUT_CAPTURES: case RECAPTURES:
|
||||
endMoves = generate<CAPTURES>(pos, moves);
|
||||
score<CAPTURES>();
|
||||
break;
|
||||
|
||||
case KILLERS:
|
||||
killers[0] = ss->killers[0];
|
||||
killers[1] = ss->killers[1];
|
||||
killers[2] = countermove;
|
||||
cur = killers;
|
||||
endMoves = cur + 2 + (countermove != killers[0] && countermove != killers[1]);
|
||||
break;
|
||||
|
||||
case QUIET:
|
||||
endMoves = generate<QUIETS>(pos, moves);
|
||||
score<QUIETS>();
|
||||
if (depth < 3 * ONE_PLY)
|
||||
{
|
||||
ExtMove* goodQuiet = std::partition(cur, endMoves, [](const ExtMove& m)
|
||||
{ return m.value > VALUE_ZERO; });
|
||||
insertion_sort(cur, goodQuiet);
|
||||
} else
|
||||
insertion_sort(cur, endMoves);
|
||||
break;
|
||||
|
||||
case BAD_CAPTURES:
|
||||
// Just pick them in reverse order to get correct ordering
|
||||
cur = moves + MAX_MOVES - 1;
|
||||
endMoves = endBadCaptures;
|
||||
break;
|
||||
|
||||
case ALL_EVASIONS:
|
||||
endMoves = generate<EVASIONS>(pos, moves);
|
||||
if (endMoves - moves > 1)
|
||||
score<EVASIONS>();
|
||||
break;
|
||||
|
||||
case CHECKS:
|
||||
endMoves = generate<QUIET_CHECKS>(pos, moves);
|
||||
break;
|
||||
|
||||
case EVASION: case QSEARCH_WITH_CHECKS: case QSEARCH_WITHOUT_CHECKS:
|
||||
case PROBCUT: case RECAPTURE: case STOP:
|
||||
stage = STOP;
|
||||
break;
|
||||
|
||||
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
|
||||
|
@ -253,80 +188,170 @@ Move MovePicker::next_move() {
|
|||
|
||||
Move move;
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (cur == endMoves && stage != STOP)
|
||||
generate_next_stage();
|
||||
|
||||
switch (stage) {
|
||||
|
||||
case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS:
|
||||
case QSEARCH_WITHOUT_CHECKS: case PROBCUT:
|
||||
++cur;
|
||||
case QSEARCH_NO_CHECKS: case PROBCUT:
|
||||
++stage;
|
||||
return ttMove;
|
||||
|
||||
case CAPTURES_INIT:
|
||||
endBadCaptures = cur = moves;
|
||||
endMoves = generate<CAPTURES>(pos, cur);
|
||||
score<CAPTURES>();
|
||||
++stage;
|
||||
|
||||
case GOOD_CAPTURES:
|
||||
while (cur < endMoves)
|
||||
{
|
||||
move = pick_best(cur++, endMoves);
|
||||
if (move != ttMove)
|
||||
{
|
||||
if (pos.see_sign(move) >= VALUE_ZERO)
|
||||
return move;
|
||||
|
||||
// Losing capture, move it to the tail of the array
|
||||
*endBadCaptures-- = move;
|
||||
// Losing capture, move it to the beginning of the array
|
||||
*endBadCaptures++ = move;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case KILLERS:
|
||||
move = *cur++;
|
||||
++stage;
|
||||
move = ss->killers[0]; // First killer move
|
||||
if ( move != MOVE_NONE
|
||||
&& move != ttMove
|
||||
&& pos.pseudo_legal(move)
|
||||
&& !pos.capture(move))
|
||||
return move;
|
||||
break;
|
||||
|
||||
case KILLERS:
|
||||
++stage;
|
||||
move = ss->killers[1]; // Second killer move
|
||||
if ( move != MOVE_NONE
|
||||
&& move != ttMove
|
||||
&& pos.pseudo_legal(move)
|
||||
&& !pos.capture(move))
|
||||
return move;
|
||||
|
||||
case COUNTERMOVE:
|
||||
++stage;
|
||||
move = countermove;
|
||||
if ( move != MOVE_NONE
|
||||
&& move != ttMove
|
||||
&& move != ss->killers[0]
|
||||
&& move != ss->killers[1]
|
||||
&& pos.pseudo_legal(move)
|
||||
&& !pos.capture(move))
|
||||
return move;
|
||||
|
||||
case QUIET_INIT:
|
||||
cur = endBadCaptures;
|
||||
endMoves = generate<QUIETS>(pos, cur);
|
||||
score<QUIETS>();
|
||||
if (depth < 3 * ONE_PLY)
|
||||
{
|
||||
ExtMove* goodQuiet = std::partition(cur, endMoves, [](const ExtMove& m)
|
||||
{ return m.value > VALUE_ZERO; });
|
||||
insertion_sort(cur, goodQuiet);
|
||||
} else
|
||||
insertion_sort(cur, endMoves);
|
||||
++stage;
|
||||
|
||||
case QUIET:
|
||||
while (cur < endMoves)
|
||||
{
|
||||
move = *cur++;
|
||||
if ( move != ttMove
|
||||
&& move != killers[0]
|
||||
&& move != killers[1]
|
||||
&& move != killers[2])
|
||||
&& move != ss->killers[0]
|
||||
&& move != ss->killers[1]
|
||||
&& move != countermove)
|
||||
return move;
|
||||
break;
|
||||
}
|
||||
++stage;
|
||||
cur = moves; // Point to beginning of bad captures
|
||||
|
||||
case BAD_CAPTURES:
|
||||
return *cur--;
|
||||
if (cur < endBadCaptures)
|
||||
return *cur++;
|
||||
break;
|
||||
|
||||
case ALL_EVASIONS: case QCAPTURES_1: case QCAPTURES_2:
|
||||
case EVASIONS_INIT:
|
||||
cur = moves;
|
||||
endMoves = generate<EVASIONS>(pos, cur);
|
||||
if (endMoves - cur - (ttMove != MOVE_NONE) > 1)
|
||||
score<EVASIONS>();
|
||||
++stage;
|
||||
|
||||
case ALL_EVASIONS:
|
||||
while (cur < endMoves)
|
||||
{
|
||||
move = pick_best(cur++, endMoves);
|
||||
if (move != ttMove)
|
||||
return move;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROBCUT_INIT:
|
||||
cur = moves;
|
||||
endMoves = generate<CAPTURES>(pos, cur);
|
||||
score<CAPTURES>();
|
||||
++stage;
|
||||
|
||||
case PROBCUT_CAPTURES:
|
||||
while (cur < endMoves)
|
||||
{
|
||||
move = pick_best(cur++, endMoves);
|
||||
if (move != ttMove && pos.see(move) > threshold)
|
||||
if ( move != ttMove
|
||||
&& pos.see(move) > threshold)
|
||||
return move;
|
||||
}
|
||||
break;
|
||||
|
||||
case RECAPTURES:
|
||||
case QCAPTURES_1_INIT: case QCAPTURES_2_INIT:
|
||||
cur = moves;
|
||||
endMoves = generate<CAPTURES>(pos, cur);
|
||||
score<CAPTURES>();
|
||||
++stage;
|
||||
|
||||
case QCAPTURES_1: case QCAPTURES_2:
|
||||
while (cur < endMoves)
|
||||
{
|
||||
move = pick_best(cur++, endMoves);
|
||||
if (move != ttMove)
|
||||
return move;
|
||||
}
|
||||
if (stage == QCAPTURES_2)
|
||||
break;
|
||||
cur = moves;
|
||||
endMoves = generate<QUIET_CHECKS>(pos, cur);
|
||||
++stage;
|
||||
|
||||
case QCHECKS:
|
||||
while (cur < endMoves)
|
||||
{
|
||||
move = cur++->move;
|
||||
if (move != ttMove)
|
||||
return move;
|
||||
}
|
||||
break;
|
||||
|
||||
case QSEARCH_RECAPTURES:
|
||||
cur = moves;
|
||||
endMoves = generate<CAPTURES>(pos, cur);
|
||||
score<CAPTURES>();
|
||||
++stage;
|
||||
|
||||
case QRECAPTURES:
|
||||
while (cur < endMoves)
|
||||
{
|
||||
move = pick_best(cur++, endMoves);
|
||||
if (to_sq(move) == recaptureSquare)
|
||||
return move;
|
||||
}
|
||||
break;
|
||||
|
||||
case CHECKS:
|
||||
move = *cur++;
|
||||
if (move != ttMove)
|
||||
return move;
|
||||
break;
|
||||
|
||||
case STOP:
|
||||
return MOVE_NONE;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
return MOVE_NONE;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
|
||||
#include "movegen.h"
|
||||
#include "position.h"
|
||||
#include "search.h"
|
||||
#include "types.h"
|
||||
|
||||
|
||||
|
@ -45,9 +44,7 @@ struct Stats {
|
|||
const T* operator[](Piece pc) const { return table[pc]; }
|
||||
T* operator[](Piece pc) { return table[pc]; }
|
||||
void clear() { std::memset(table, 0, sizeof(table)); }
|
||||
|
||||
void update(Piece pc, Square to, Move m) { table[pc][to] = m; }
|
||||
|
||||
void update(Piece pc, Square to, Value v) {
|
||||
|
||||
if (abs(int(v)) >= 324)
|
||||
|
@ -70,29 +67,30 @@ struct FromToStats {
|
|||
|
||||
Value get(Color c, Move m) const { return table[c][from_sq(m)][to_sq(m)]; }
|
||||
void clear() { std::memset(table, 0, sizeof(table)); }
|
||||
void update(Color c, Move m, Value v) {
|
||||
|
||||
void update(Color c, Move m, Value v)
|
||||
{
|
||||
if (abs(int(v)) >= 324)
|
||||
return;
|
||||
|
||||
Square f = from_sq(m);
|
||||
Square t = to_sq(m);
|
||||
Square from = from_sq(m);
|
||||
Square to = to_sq(m);
|
||||
|
||||
table[c][f][t] -= table[c][f][t] * abs(int(v)) / 324;
|
||||
table[c][f][t] += int(v) * 32;
|
||||
table[c][from][to] -= table[c][from][to] * abs(int(v)) / 324;
|
||||
table[c][from][to] += int(v) * 32;
|
||||
}
|
||||
|
||||
private:
|
||||
Value table[COLOR_NB][SQUARE_NB][SQUARE_NB];
|
||||
};
|
||||
|
||||
|
||||
/// 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.
|
||||
namespace Search { struct Stack; }
|
||||
|
||||
class MovePicker {
|
||||
public:
|
||||
|
@ -107,8 +105,7 @@ public:
|
|||
|
||||
private:
|
||||
template<GenType> void score();
|
||||
void generate_next_stage();
|
||||
ExtMove* begin() { return moves; }
|
||||
ExtMove* begin() { return cur; }
|
||||
ExtMove* end() { return endMoves; }
|
||||
|
||||
const Position& pos;
|
||||
|
@ -116,12 +113,11 @@ private:
|
|||
Move countermove;
|
||||
Depth depth;
|
||||
Move ttMove;
|
||||
ExtMove killers[3];
|
||||
Square recaptureSquare;
|
||||
Value threshold;
|
||||
int stage;
|
||||
ExtMove* endBadCaptures = moves + MAX_MOVES - 1;
|
||||
ExtMove moves[MAX_MOVES], *cur = moves, *endMoves = moves;
|
||||
ExtMove *cur, *endMoves, *endBadCaptures;
|
||||
ExtMove moves[MAX_MOVES];
|
||||
};
|
||||
|
||||
#endif // #ifndef MOVEPICK_H_INCLUDED
|
||||
|
|
|
@ -215,6 +215,7 @@ Entry* probe(const Position& pos) {
|
|||
e->key = key;
|
||||
e->score = evaluate<WHITE>(pos, e) - evaluate<BLACK>(pos, e);
|
||||
e->asymmetry = popcount(e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK]);
|
||||
e->openFiles = popcount(e->semiopenFiles[WHITE] & e->semiopenFiles[BLACK]);
|
||||
return e;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ struct Entry {
|
|||
Bitboard passed_pawns(Color c) const { return passedPawns[c]; }
|
||||
Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[c]; }
|
||||
int pawn_asymmetry() const { return asymmetry; }
|
||||
int open_files() const { return openFiles; }
|
||||
|
||||
int semiopen_file(Color c, File f) const {
|
||||
return semiopenFiles[c] & (1 << f);
|
||||
|
@ -74,6 +75,7 @@ struct Entry {
|
|||
int semiopenFiles[COLOR_NB];
|
||||
int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares]
|
||||
int asymmetry;
|
||||
int openFiles;
|
||||
};
|
||||
|
||||
typedef HashTable<Entry, 16384> Table;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef> // For offsetof()
|
||||
#include <cstring> // For std::memset, std::memcmp
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
@ -34,17 +35,18 @@
|
|||
|
||||
using std::string;
|
||||
|
||||
namespace PSQT {
|
||||
extern Score psq[PIECE_NB][SQUARE_NB];
|
||||
}
|
||||
|
||||
namespace Zobrist {
|
||||
|
||||
Key psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
|
||||
Key psq[PIECE_NB][SQUARE_NB];
|
||||
Key enpassant[FILE_NB];
|
||||
Key castling[CASTLING_RIGHT_NB];
|
||||
Key side;
|
||||
Key exclusion;
|
||||
}
|
||||
|
||||
Key Position::exclusion_key() const { return st->key ^ Zobrist::exclusion; }
|
||||
|
||||
namespace {
|
||||
|
||||
const string PieceToChar(" PNBRQK pnbrqk");
|
||||
|
@ -112,10 +114,9 @@ void Position::init() {
|
|||
|
||||
PRNG rng(1070372);
|
||||
|
||||
for (Color c = WHITE; c <= BLACK; ++c)
|
||||
for (PieceType pt = PAWN; pt <= KING; ++pt)
|
||||
for (Piece pc : Pieces)
|
||||
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
||||
Zobrist::psq[c][pt][s] = rng.rand<Key>();
|
||||
Zobrist::psq[pc][s] = rng.rand<Key>();
|
||||
|
||||
for (File f = FILE_A; f <= FILE_H; ++f)
|
||||
Zobrist::enpassant[f] = rng.rand<Key>();
|
||||
|
@ -132,7 +133,6 @@ void Position::init() {
|
|||
}
|
||||
|
||||
Zobrist::side = rng.rand<Key>();
|
||||
Zobrist::exclusion = rng.rand<Key>();
|
||||
}
|
||||
|
||||
|
||||
|
@ -182,7 +182,7 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
|
|||
|
||||
std::memset(this, 0, sizeof(Position));
|
||||
std::memset(si, 0, sizeof(StateInfo));
|
||||
std::fill_n(&pieceList[0][0][0], sizeof(pieceList) / sizeof(Square), SQ_NONE);
|
||||
std::fill_n(&pieceList[0][0], sizeof(pieceList) / sizeof(Square), SQ_NONE);
|
||||
st = si;
|
||||
|
||||
ss >> std::noskipws;
|
||||
|
@ -198,7 +198,7 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
|
|||
|
||||
else if ((idx = PieceToChar.find(token)) != string::npos)
|
||||
{
|
||||
put_piece(color_of(Piece(idx)), type_of(Piece(idx)), sq);
|
||||
put_piece(Piece(idx), sq);
|
||||
++sq;
|
||||
}
|
||||
}
|
||||
|
@ -296,8 +296,8 @@ void Position::set_castling_right(Color c, Square rfrom) {
|
|||
|
||||
void Position::set_check_info(StateInfo* si) const {
|
||||
|
||||
si->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square<KING>(WHITE));
|
||||
si->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square<KING>(BLACK));
|
||||
si->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square<KING>(WHITE), si->pinnersForKing[WHITE]);
|
||||
si->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square<KING>(BLACK), si->pinnersForKing[BLACK]);
|
||||
|
||||
Square ksq = square<KING>(~sideToMove);
|
||||
|
||||
|
@ -328,8 +328,8 @@ void Position::set_state(StateInfo* si) const {
|
|||
{
|
||||
Square s = pop_lsb(&b);
|
||||
Piece pc = piece_on(s);
|
||||
si->key ^= Zobrist::psq[color_of(pc)][type_of(pc)][s];
|
||||
si->psq += PSQT::psq[color_of(pc)][type_of(pc)][s];
|
||||
si->key ^= Zobrist::psq[pc][s];
|
||||
si->psq += PSQT::psq[pc][s];
|
||||
}
|
||||
|
||||
if (si->epSquare != SQ_NONE)
|
||||
|
@ -343,17 +343,17 @@ void Position::set_state(StateInfo* si) const {
|
|||
for (Bitboard b = pieces(PAWN); b; )
|
||||
{
|
||||
Square s = pop_lsb(&b);
|
||||
si->pawnKey ^= Zobrist::psq[color_of(piece_on(s))][PAWN][s];
|
||||
si->pawnKey ^= Zobrist::psq[piece_on(s)][s];
|
||||
}
|
||||
|
||||
for (Color c = WHITE; c <= BLACK; ++c)
|
||||
for (PieceType pt = PAWN; pt <= KING; ++pt)
|
||||
for (int cnt = 0; cnt < pieceCount[c][pt]; ++cnt)
|
||||
si->materialKey ^= Zobrist::psq[c][pt][cnt];
|
||||
for (Piece pc : Pieces)
|
||||
{
|
||||
if (type_of(pc) != PAWN && type_of(pc) != KING)
|
||||
si->nonPawnMaterial[color_of(pc)] += pieceCount[pc] * PieceValue[MG][pc];
|
||||
|
||||
for (Color c = WHITE; c <= BLACK; ++c)
|
||||
for (PieceType pt = KNIGHT; pt <= QUEEN; ++pt)
|
||||
si->nonPawnMaterial[c] += pieceCount[c][pt] * PieceValue[MG][pt];
|
||||
for (int cnt = 0; cnt < pieceCount[pc]; ++cnt)
|
||||
si->materialKey ^= Zobrist::psq[pc][cnt];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -420,24 +420,25 @@ Phase Position::game_phase() const {
|
|||
}
|
||||
|
||||
|
||||
/// Position::slider_blockers() returns a bitboard of all the pieces (both colors) that
|
||||
/// are blocking attacks on the square 's' from 'sliders'. A piece blocks a slider
|
||||
/// if removing that piece from the board would result in a position where square 's'
|
||||
/// is attacked. For example, a king-attack blocking piece can be either a pinned or
|
||||
/// a discovered check piece, according if its color is the opposite or the same of
|
||||
/// the color of the slider.
|
||||
/// Position::slider_blockers() returns a bitboard of all the pieces (both colors)
|
||||
/// that are blocking attacks on the square 's' from 'sliders'. A piece blocks a
|
||||
/// slider if removing that piece from the board would result in a position where
|
||||
/// square 's' is attacked. For example, a king-attack blocking piece can be either
|
||||
/// a pinned or a discovered check piece, according if its color is the opposite
|
||||
/// or the same of the color of the slider. The pinners bitboard get filled with
|
||||
/// real and potential pinners.
|
||||
|
||||
Bitboard Position::slider_blockers(Bitboard sliders, Square s) const {
|
||||
Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const {
|
||||
|
||||
Bitboard b, pinners, result = 0;
|
||||
Bitboard b, p, result = 0;
|
||||
|
||||
// Pinners are sliders that attack 's' when a pinned piece is removed
|
||||
pinners = ( (PseudoAttacks[ROOK ][s] & pieces(QUEEN, ROOK))
|
||||
pinners = p = ( (PseudoAttacks[ROOK ][s] & pieces(QUEEN, ROOK))
|
||||
| (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders;
|
||||
|
||||
while (pinners)
|
||||
while (p)
|
||||
{
|
||||
b = between_bb(s, pop_lsb(&pinners)) & pieces();
|
||||
b = between_bb(s, pop_lsb(&p)) & pieces();
|
||||
|
||||
if (!more_than_one(b))
|
||||
result |= b;
|
||||
|
@ -661,23 +662,24 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||
Color them = ~us;
|
||||
Square from = from_sq(m);
|
||||
Square to = to_sq(m);
|
||||
PieceType pt = type_of(piece_on(from));
|
||||
PieceType captured = type_of(m) == ENPASSANT ? PAWN : type_of(piece_on(to));
|
||||
Piece pc = piece_on(from);
|
||||
Piece captured = type_of(m) == ENPASSANT ? make_piece(them, PAWN) : piece_on(to);
|
||||
|
||||
assert(color_of(piece_on(from)) == us);
|
||||
assert(piece_on(to) == NO_PIECE || color_of(piece_on(to)) == (type_of(m) != CASTLING ? them : us));
|
||||
assert(captured != KING);
|
||||
assert(color_of(pc) == us);
|
||||
assert(captured == NO_PIECE || color_of(captured) == (type_of(m) != CASTLING ? them : us));
|
||||
assert(type_of(captured) != KING);
|
||||
|
||||
if (type_of(m) == CASTLING)
|
||||
{
|
||||
assert(pt == KING);
|
||||
assert(pc == make_piece(us, KING));
|
||||
assert(captured == make_piece(us, ROOK));
|
||||
|
||||
Square rfrom, rto;
|
||||
do_castling<true>(us, from, to, rfrom, rto);
|
||||
|
||||
captured = NO_PIECE_TYPE;
|
||||
st->psq += PSQT::psq[us][ROOK][rto] - PSQT::psq[us][ROOK][rfrom];
|
||||
k ^= Zobrist::psq[us][ROOK][rfrom] ^ Zobrist::psq[us][ROOK][rto];
|
||||
st->psq += PSQT::psq[captured][rto] - PSQT::psq[captured][rfrom];
|
||||
k ^= Zobrist::psq[captured][rfrom] ^ Zobrist::psq[captured][rto];
|
||||
captured = NO_PIECE;
|
||||
}
|
||||
|
||||
if (captured)
|
||||
|
@ -686,13 +688,13 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||
|
||||
// If the captured piece is a pawn, update pawn hash key, otherwise
|
||||
// update non-pawn material.
|
||||
if (captured == PAWN)
|
||||
if (type_of(captured) == PAWN)
|
||||
{
|
||||
if (type_of(m) == ENPASSANT)
|
||||
{
|
||||
capsq -= pawn_push(us);
|
||||
|
||||
assert(pt == PAWN);
|
||||
assert(pc == make_piece(us, PAWN));
|
||||
assert(to == st->epSquare);
|
||||
assert(relative_rank(us, to) == RANK_6);
|
||||
assert(piece_on(to) == NO_PIECE);
|
||||
|
@ -701,28 +703,28 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||
board[capsq] = NO_PIECE; // Not done by remove_piece()
|
||||
}
|
||||
|
||||
st->pawnKey ^= Zobrist::psq[them][PAWN][capsq];
|
||||
st->pawnKey ^= Zobrist::psq[captured][capsq];
|
||||
}
|
||||
else
|
||||
st->nonPawnMaterial[them] -= PieceValue[MG][captured];
|
||||
|
||||
// Update board and piece lists
|
||||
remove_piece(them, captured, capsq);
|
||||
remove_piece(captured, capsq);
|
||||
|
||||
// Update material hash key and prefetch access to materialTable
|
||||
k ^= Zobrist::psq[them][captured][capsq];
|
||||
st->materialKey ^= Zobrist::psq[them][captured][pieceCount[them][captured]];
|
||||
k ^= Zobrist::psq[captured][capsq];
|
||||
st->materialKey ^= Zobrist::psq[captured][pieceCount[captured]];
|
||||
prefetch(thisThread->materialTable[st->materialKey]);
|
||||
|
||||
// Update incremental scores
|
||||
st->psq -= PSQT::psq[them][captured][capsq];
|
||||
st->psq -= PSQT::psq[captured][capsq];
|
||||
|
||||
// Reset rule 50 counter
|
||||
st->rule50 = 0;
|
||||
}
|
||||
|
||||
// Update hash key
|
||||
k ^= Zobrist::psq[us][pt][from] ^ Zobrist::psq[us][pt][to];
|
||||
k ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
||||
|
||||
// Reset en passant square
|
||||
if (st->epSquare != SQ_NONE)
|
||||
|
@ -741,10 +743,10 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||
|
||||
// Move the piece. The tricky Chess960 castling is handled earlier
|
||||
if (type_of(m) != CASTLING)
|
||||
move_piece(us, pt, from, to);
|
||||
move_piece(pc, from, to);
|
||||
|
||||
// If the moving piece is a pawn do some special extra work
|
||||
if (pt == PAWN)
|
||||
if (type_of(pc) == PAWN)
|
||||
{
|
||||
// Set en-passant square if the moved pawn can be captured
|
||||
if ( (int(to) ^ int(from)) == 16
|
||||
|
@ -756,29 +758,29 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||
|
||||
else if (type_of(m) == PROMOTION)
|
||||
{
|
||||
PieceType promotion = promotion_type(m);
|
||||
Piece promotion = make_piece(us, promotion_type(m));
|
||||
|
||||
assert(relative_rank(us, to) == RANK_8);
|
||||
assert(promotion >= KNIGHT && promotion <= QUEEN);
|
||||
assert(type_of(promotion) >= KNIGHT && type_of(promotion) <= QUEEN);
|
||||
|
||||
remove_piece(us, PAWN, to);
|
||||
put_piece(us, promotion, to);
|
||||
remove_piece(pc, to);
|
||||
put_piece(promotion, to);
|
||||
|
||||
// Update hash keys
|
||||
k ^= Zobrist::psq[us][PAWN][to] ^ Zobrist::psq[us][promotion][to];
|
||||
st->pawnKey ^= Zobrist::psq[us][PAWN][to];
|
||||
st->materialKey ^= Zobrist::psq[us][promotion][pieceCount[us][promotion]-1]
|
||||
^ Zobrist::psq[us][PAWN][pieceCount[us][PAWN]];
|
||||
k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[promotion][to];
|
||||
st->pawnKey ^= Zobrist::psq[pc][to];
|
||||
st->materialKey ^= Zobrist::psq[promotion][pieceCount[promotion]-1]
|
||||
^ Zobrist::psq[pc][pieceCount[pc]];
|
||||
|
||||
// Update incremental score
|
||||
st->psq += PSQT::psq[us][promotion][to] - PSQT::psq[us][PAWN][to];
|
||||
st->psq += PSQT::psq[promotion][to] - PSQT::psq[pc][to];
|
||||
|
||||
// Update material
|
||||
st->nonPawnMaterial[us] += PieceValue[MG][promotion];
|
||||
}
|
||||
|
||||
// Update pawn hash key and prefetch access to pawnsTable
|
||||
st->pawnKey ^= Zobrist::psq[us][PAWN][from] ^ Zobrist::psq[us][PAWN][to];
|
||||
st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
|
||||
prefetch(thisThread->pawnsTable[st->pawnKey]);
|
||||
|
||||
// Reset rule 50 draw counter
|
||||
|
@ -786,10 +788,10 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
|||
}
|
||||
|
||||
// Update incremental scores
|
||||
st->psq += PSQT::psq[us][pt][to] - PSQT::psq[us][pt][from];
|
||||
st->psq += PSQT::psq[pc][to] - PSQT::psq[pc][from];
|
||||
|
||||
// Set capture piece
|
||||
st->capturedType = captured;
|
||||
st->capturedPiece = captured;
|
||||
|
||||
// Update the key with the final value
|
||||
st->key = k;
|
||||
|
@ -818,20 +820,20 @@ void Position::undo_move(Move m) {
|
|||
Color us = sideToMove;
|
||||
Square from = from_sq(m);
|
||||
Square to = to_sq(m);
|
||||
PieceType pt = type_of(piece_on(to));
|
||||
Piece pc = piece_on(to);
|
||||
|
||||
assert(empty(from) || type_of(m) == CASTLING);
|
||||
assert(st->capturedType != KING);
|
||||
assert(type_of(st->capturedPiece) != KING);
|
||||
|
||||
if (type_of(m) == PROMOTION)
|
||||
{
|
||||
assert(relative_rank(us, to) == RANK_8);
|
||||
assert(pt == promotion_type(m));
|
||||
assert(pt >= KNIGHT && pt <= QUEEN);
|
||||
assert(type_of(pc) == promotion_type(m));
|
||||
assert(type_of(pc) >= KNIGHT && type_of(pc) <= QUEEN);
|
||||
|
||||
remove_piece(us, pt, to);
|
||||
put_piece(us, PAWN, to);
|
||||
pt = PAWN;
|
||||
remove_piece(pc, to);
|
||||
pc = make_piece(us, PAWN);
|
||||
put_piece(pc, to);
|
||||
}
|
||||
|
||||
if (type_of(m) == CASTLING)
|
||||
|
@ -841,9 +843,9 @@ void Position::undo_move(Move m) {
|
|||
}
|
||||
else
|
||||
{
|
||||
move_piece(us, pt, to, from); // Put the piece back at the source square
|
||||
move_piece(pc, to, from); // Put the piece back at the source square
|
||||
|
||||
if (st->capturedType)
|
||||
if (st->capturedPiece)
|
||||
{
|
||||
Square capsq = to;
|
||||
|
||||
|
@ -851,14 +853,14 @@ void Position::undo_move(Move m) {
|
|||
{
|
||||
capsq -= pawn_push(us);
|
||||
|
||||
assert(pt == PAWN);
|
||||
assert(type_of(pc) == PAWN);
|
||||
assert(to == st->previous->epSquare);
|
||||
assert(relative_rank(us, to) == RANK_6);
|
||||
assert(piece_on(capsq) == NO_PIECE);
|
||||
assert(st->capturedType == PAWN);
|
||||
assert(st->capturedPiece == make_piece(~us, PAWN));
|
||||
}
|
||||
|
||||
put_piece(~us, st->capturedType, capsq); // Restore the captured piece
|
||||
put_piece(st->capturedPiece, capsq); // Restore the captured piece
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -871,7 +873,7 @@ void Position::undo_move(Move m) {
|
|||
|
||||
|
||||
/// Position::do_castling() is a helper used to do/undo a castling move. This
|
||||
/// is a bit tricky, especially in Chess960.
|
||||
/// is a bit tricky in Chess960 where from/to squares can overlap.
|
||||
template<bool Do>
|
||||
void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto) {
|
||||
|
||||
|
@ -881,11 +883,11 @@ void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Squ
|
|||
to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
|
||||
|
||||
// Remove both pieces first since squares could overlap in Chess960
|
||||
remove_piece(us, KING, Do ? from : to);
|
||||
remove_piece(us, ROOK, Do ? rfrom : rto);
|
||||
remove_piece(make_piece(us, KING), Do ? from : to);
|
||||
remove_piece(make_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(us, KING, Do ? to : from);
|
||||
put_piece(us, ROOK, Do ? rto : rfrom);
|
||||
put_piece(make_piece(us, KING), Do ? to : from);
|
||||
put_piece(make_piece(us, ROOK), Do ? rto : rfrom);
|
||||
}
|
||||
|
||||
|
||||
|
@ -935,17 +937,16 @@ void Position::undo_null_move() {
|
|||
|
||||
Key Position::key_after(Move m) const {
|
||||
|
||||
Color us = sideToMove;
|
||||
Square from = from_sq(m);
|
||||
Square to = to_sq(m);
|
||||
PieceType pt = type_of(piece_on(from));
|
||||
PieceType captured = type_of(piece_on(to));
|
||||
Piece pc = piece_on(from);
|
||||
Piece captured = piece_on(to);
|
||||
Key k = st->key ^ Zobrist::side;
|
||||
|
||||
if (captured)
|
||||
k ^= Zobrist::psq[~us][captured][to];
|
||||
k ^= Zobrist::psq[captured][to];
|
||||
|
||||
return k ^ Zobrist::psq[us][pt][to] ^ Zobrist::psq[us][pt][from];
|
||||
return k ^ Zobrist::psq[pc][to] ^ Zobrist::psq[pc][from];
|
||||
}
|
||||
|
||||
|
||||
|
@ -1001,6 +1002,15 @@ Value Position::see(Move m) const {
|
|||
// If the opponent has no attackers we are finished
|
||||
stm = ~stm;
|
||||
stmAttackers = attackers & pieces(stm);
|
||||
occupied ^= to; // For the case when captured piece is a pinner
|
||||
|
||||
// Don't allow pinned pieces to attack as long all pinners (this includes also
|
||||
// potential ones) are on their original square. When a pinner moves to the
|
||||
// exchange-square or get captured on it, we fall back to standard SEE behaviour.
|
||||
if ( (stmAttackers & pinned_pieces(stm))
|
||||
&& (st->pinnersForKing[stm] & occupied) == st->pinnersForKing[stm])
|
||||
stmAttackers &= ~pinned_pieces(stm);
|
||||
|
||||
if (!stmAttackers)
|
||||
return swapList[0];
|
||||
|
||||
|
@ -1022,6 +1032,10 @@ Value Position::see(Move m) const {
|
|||
captured = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers);
|
||||
stm = ~stm;
|
||||
stmAttackers = attackers & pieces(stm);
|
||||
if ( (stmAttackers & pinned_pieces(stm))
|
||||
&& (st->pinnersForKing[stm] & occupied) == st->pinnersForKing[stm])
|
||||
stmAttackers &= ~pinned_pieces(stm);
|
||||
|
||||
++slIndex;
|
||||
|
||||
} while (stmAttackers && (captured != KING || (--slIndex, false))); // Stop before a king capture
|
||||
|
@ -1140,15 +1154,13 @@ bool Position::pos_is_ok(int* failedStep) const {
|
|||
}
|
||||
|
||||
if (step == Lists)
|
||||
for (Color c = WHITE; c <= BLACK; ++c)
|
||||
for (PieceType pt = PAWN; pt <= KING; ++pt)
|
||||
for (Piece pc : Pieces)
|
||||
{
|
||||
if (pieceCount[c][pt] != popcount(pieces(c, pt)))
|
||||
if (pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc))))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < pieceCount[c][pt]; ++i)
|
||||
if ( board[pieceList[c][pt][i]] != make_piece(c, pt)
|
||||
|| index[pieceList[c][pt][i]] != i)
|
||||
for (int i = 0; i < pieceCount[pc]; ++i)
|
||||
if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,25 +22,13 @@
|
|||
#define POSITION_H_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef> // For offsetof()
|
||||
#include <deque>
|
||||
#include <memory> // For std::unique_ptr
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "bitboard.h"
|
||||
#include "types.h"
|
||||
|
||||
class Position;
|
||||
class Thread;
|
||||
|
||||
namespace PSQT {
|
||||
|
||||
extern Score psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
|
||||
|
||||
void init();
|
||||
}
|
||||
|
||||
|
||||
/// 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
|
||||
|
@ -58,12 +46,13 @@ struct StateInfo {
|
|||
Score psq;
|
||||
Square epSquare;
|
||||
|
||||
// Not copied when making a move
|
||||
// Not copied when making a move (will be recomputed anyhow)
|
||||
Key key;
|
||||
Bitboard checkersBB;
|
||||
PieceType capturedType;
|
||||
Piece capturedPiece;
|
||||
StateInfo* previous;
|
||||
Bitboard blockersForKing[COLOR_NB];
|
||||
Bitboard pinnersForKing[COLOR_NB];
|
||||
Bitboard checkSquares[PIECE_TYPE_NB];
|
||||
};
|
||||
|
||||
|
@ -75,9 +64,9 @@ typedef std::unique_ptr<std::deque<StateInfo>> StateListPtr;
|
|||
/// 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 Thread;
|
||||
|
||||
class Position {
|
||||
|
||||
public:
|
||||
static void init();
|
||||
|
||||
|
@ -121,7 +110,7 @@ public:
|
|||
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;
|
||||
Bitboard slider_blockers(Bitboard sliders, Square s) const;
|
||||
Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const;
|
||||
|
||||
// Properties of moves
|
||||
bool legal(Move m) const;
|
||||
|
@ -131,7 +120,7 @@ public:
|
|||
bool gives_check(Move m) const;
|
||||
bool advanced_pawn_push(Move m) const;
|
||||
Piece moved_piece(Move m) const;
|
||||
PieceType captured_piece_type() const;
|
||||
Piece captured_piece() const;
|
||||
|
||||
// Piece specific
|
||||
bool pawn_passed(Color c, Square s) const;
|
||||
|
@ -143,14 +132,13 @@ public:
|
|||
void do_null_move(StateInfo& st);
|
||||
void undo_null_move();
|
||||
|
||||
// Static exchange evaluation
|
||||
// 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;
|
||||
|
||||
|
@ -178,9 +166,9 @@ private:
|
|||
void set_check_info(StateInfo* si) const;
|
||||
|
||||
// Other helpers
|
||||
void put_piece(Color c, PieceType pt, Square s);
|
||||
void remove_piece(Color c, PieceType pt, Square s);
|
||||
void move_piece(Color c, PieceType pt, Square from, Square to);
|
||||
void put_piece(Piece pc, Square s);
|
||||
void remove_piece(Piece pc, Square s);
|
||||
void move_piece(Piece pc, Square from, Square to);
|
||||
template<bool Do>
|
||||
void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto);
|
||||
|
||||
|
@ -188,8 +176,8 @@ private:
|
|||
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 pieceCount[PIECE_NB];
|
||||
Square pieceList[PIECE_NB][16];
|
||||
int index[SQUARE_NB];
|
||||
int castlingRightsMask[SQUARE_NB];
|
||||
Square castlingRookSquare[CASTLING_RIGHT_NB];
|
||||
|
@ -245,16 +233,16 @@ inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const {
|
|||
}
|
||||
|
||||
template<PieceType Pt> inline int Position::count(Color c) const {
|
||||
return pieceCount[c][Pt];
|
||||
return pieceCount[make_piece(c, Pt)];
|
||||
}
|
||||
|
||||
template<PieceType Pt> inline const Square* Position::squares(Color c) const {
|
||||
return pieceList[c][Pt];
|
||||
return pieceList[make_piece(c, Pt)];
|
||||
}
|
||||
|
||||
template<PieceType Pt> inline Square Position::square(Color c) const {
|
||||
assert(pieceCount[c][Pt] == 1);
|
||||
return pieceList[c][Pt][0];
|
||||
assert(pieceCount[make_piece(c, Pt)] == 1);
|
||||
return pieceList[make_piece(c, Pt)][0];
|
||||
}
|
||||
|
||||
inline Square Position::ep_square() const {
|
||||
|
@ -359,8 +347,8 @@ inline void Position::set_nodes_searched(uint64_t n) {
|
|||
}
|
||||
|
||||
inline bool Position::opposite_bishops() const {
|
||||
return pieceCount[WHITE][BISHOP] == 1
|
||||
&& pieceCount[BLACK][BISHOP] == 1
|
||||
return pieceCount[W_BISHOP] == 1
|
||||
&& pieceCount[B_BISHOP] == 1
|
||||
&& opposite_colors(square<BISHOP>(WHITE), square<BISHOP>(BLACK));
|
||||
}
|
||||
|
||||
|
@ -369,66 +357,64 @@ inline bool Position::is_chess960() const {
|
|||
}
|
||||
|
||||
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));
|
||||
// Castling is encoded as "king captures rook"
|
||||
return (!empty(to_sq(m)) && type_of(m) != CASTLING) || type_of(m) == ENPASSANT;
|
||||
}
|
||||
|
||||
inline PieceType Position::captured_piece_type() const {
|
||||
return st->capturedType;
|
||||
inline Piece Position::captured_piece() const {
|
||||
return st->capturedPiece;
|
||||
}
|
||||
|
||||
inline Thread* Position::this_thread() const {
|
||||
return thisThread;
|
||||
}
|
||||
|
||||
inline void Position::put_piece(Color c, PieceType pt, Square s) {
|
||||
inline void Position::put_piece(Piece pc, Square s) {
|
||||
|
||||
board[s] = make_piece(c, pt);
|
||||
board[s] = pc;
|
||||
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]++;
|
||||
byTypeBB[type_of(pc)] |= s;
|
||||
byColorBB[color_of(pc)] |= s;
|
||||
index[s] = pieceCount[pc]++;
|
||||
pieceList[pc][index[s]] = s;
|
||||
pieceCount[make_piece(color_of(pc), ALL_PIECES)]++;
|
||||
}
|
||||
|
||||
inline void Position::remove_piece(Color c, PieceType pt, Square s) {
|
||||
inline void Position::remove_piece(Piece pc, Square s) {
|
||||
|
||||
// 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.
|
||||
// are not invariant to a do_move() + undo_move() sequence.
|
||||
byTypeBB[ALL_PIECES] ^= s;
|
||||
byTypeBB[pt] ^= s;
|
||||
byColorBB[c] ^= s;
|
||||
byTypeBB[type_of(pc)] ^= s;
|
||||
byColorBB[color_of(pc)] ^= s;
|
||||
/* board[s] = NO_PIECE; Not needed, overwritten by the capturing one */
|
||||
Square lastSquare = pieceList[c][pt][--pieceCount[c][pt]];
|
||||
Square lastSquare = pieceList[pc][--pieceCount[pc]];
|
||||
index[lastSquare] = index[s];
|
||||
pieceList[c][pt][index[lastSquare]] = lastSquare;
|
||||
pieceList[c][pt][pieceCount[c][pt]] = SQ_NONE;
|
||||
pieceCount[c][ALL_PIECES]--;
|
||||
pieceList[pc][index[lastSquare]] = lastSquare;
|
||||
pieceList[pc][pieceCount[pc]] = SQ_NONE;
|
||||
pieceCount[make_piece(color_of(pc), ALL_PIECES)]--;
|
||||
}
|
||||
|
||||
inline void Position::move_piece(Color c, PieceType pt, Square from, Square to) {
|
||||
inline void Position::move_piece(Piece pc, Square from, Square to) {
|
||||
|
||||
// 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;
|
||||
byTypeBB[type_of(pc)] ^= from_to_bb;
|
||||
byColorBB[color_of(pc)] ^= from_to_bb;
|
||||
board[from] = NO_PIECE;
|
||||
board[to] = make_piece(c, pt);
|
||||
board[to] = pc;
|
||||
index[to] = index[from];
|
||||
pieceList[c][pt][index[to]] = to;
|
||||
pieceList[pc][index[to]] = to;
|
||||
}
|
||||
|
||||
#endif // #ifndef POSITION_H_INCLUDED
|
||||
|
|
|
@ -99,25 +99,25 @@ const Score Bonus[][RANK_NB][int(FILE_NB) / 2] = {
|
|||
|
||||
#undef S
|
||||
|
||||
Score psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
|
||||
Score psq[PIECE_NB][SQUARE_NB];
|
||||
|
||||
// init() initializes piece-square tables: the white halves of the tables are
|
||||
// copied from Bonus[] adding the piece value, then the black halves of the
|
||||
// tables are initialized by flipping and changing the sign of the white scores.
|
||||
void init() {
|
||||
|
||||
for (PieceType pt = PAWN; pt <= KING; ++pt)
|
||||
for (Piece pc = W_PAWN; pc <= W_KING; ++pc)
|
||||
{
|
||||
PieceValue[MG][make_piece(BLACK, pt)] = PieceValue[MG][pt];
|
||||
PieceValue[EG][make_piece(BLACK, pt)] = PieceValue[EG][pt];
|
||||
PieceValue[MG][~pc] = PieceValue[MG][pc];
|
||||
PieceValue[EG][~pc] = PieceValue[EG][pc];
|
||||
|
||||
Score v = make_score(PieceValue[MG][pt], PieceValue[EG][pt]);
|
||||
Score v = make_score(PieceValue[MG][pc], PieceValue[EG][pc]);
|
||||
|
||||
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
||||
{
|
||||
File f = std::min(file_of(s), FILE_H - file_of(s));
|
||||
psq[WHITE][pt][ s] = v + Bonus[pt][rank_of(s)][f];
|
||||
psq[BLACK][pt][~s] = -psq[WHITE][pt][s];
|
||||
psq[ pc][ s] = v + Bonus[pc][rank_of(s)][f];
|
||||
psq[~pc][~s] = -psq[pc][s];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "misc.h"
|
||||
#include "movegen.h"
|
||||
#include "movepick.h"
|
||||
#include "position.h"
|
||||
#include "search.h"
|
||||
#include "timeman.h"
|
||||
#include "thread.h"
|
||||
|
@ -157,7 +158,6 @@ namespace {
|
|||
|
||||
EasyMoveManager EasyMove;
|
||||
Value DrawValue[COLOR_NB];
|
||||
CounterMoveHistoryStats CounterMoveHistory;
|
||||
|
||||
template <NodeType NT>
|
||||
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode);
|
||||
|
@ -208,13 +208,13 @@ void Search::init() {
|
|||
void Search::clear() {
|
||||
|
||||
TT.clear();
|
||||
CounterMoveHistory.clear();
|
||||
|
||||
for (Thread* th : Threads)
|
||||
{
|
||||
th->history.clear();
|
||||
th->counterMoves.clear();
|
||||
th->fromTo.clear();
|
||||
th->counterMoveHistory.clear();
|
||||
}
|
||||
|
||||
Threads.main()->previousScore = VALUE_INFINITE;
|
||||
|
@ -506,7 +506,7 @@ void Thread::search() {
|
|||
|
||||
if ( rootMoves.size() == 1
|
||||
|| Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 628
|
||||
|| (mainThread->easyMovePlayed = doEasyMove))
|
||||
|| (mainThread->easyMovePlayed = doEasyMove, doEasyMove))
|
||||
{
|
||||
// If we are allowed to ponder do not stop the search now but
|
||||
// keep pondering until the GUI sends "ponderhit" or "stop".
|
||||
|
@ -560,7 +560,7 @@ namespace {
|
|||
TTEntry* tte;
|
||||
Key posKey;
|
||||
Move ttMove, move, excludedMove, bestMove;
|
||||
Depth extension, newDepth, predictedDepth;
|
||||
Depth extension, newDepth;
|
||||
Value bestValue, value, ttValue, eval, nullValue;
|
||||
bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
|
||||
bool captureOrPromotion, doFullDepthSearch, moveCountPruning;
|
||||
|
@ -622,7 +622,7 @@ namespace {
|
|||
// search to overwrite a previous full search TT value, so we use a different
|
||||
// position key in case of an excluded move.
|
||||
excludedMove = ss->excludedMove;
|
||||
posKey = excludedMove ? pos.exclusion_key() : pos.key();
|
||||
posKey = pos.key() ^ Key(excludedMove);
|
||||
tte = TT.probe(posKey, ttHit);
|
||||
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
|
||||
ttMove = rootNode ? thisThread->rootMoves[thisThread->PVIdx].pv[0]
|
||||
|
@ -650,7 +650,7 @@ namespace {
|
|||
}
|
||||
|
||||
// Extra penalty for a quiet TT move in previous ply when it gets refuted
|
||||
if ((ss-1)->moveCount == 1 && !pos.captured_piece_type())
|
||||
if ((ss-1)->moveCount == 1 && !pos.captured_piece())
|
||||
{
|
||||
Value penalty = Value(d * d + 4 * d + 1);
|
||||
Square prevSq = to_sq((ss-1)->currentMove);
|
||||
|
@ -725,8 +725,8 @@ namespace {
|
|||
// Step 6. Razoring (skipped when in check)
|
||||
if ( !PvNode
|
||||
&& depth < 4 * ONE_PLY
|
||||
&& eval + razor_margin[depth / ONE_PLY] <= alpha
|
||||
&& ttMove == MOVE_NONE)
|
||||
&& ttMove == MOVE_NONE
|
||||
&& eval + razor_margin[depth / ONE_PLY] <= alpha)
|
||||
{
|
||||
if ( depth <= ONE_PLY
|
||||
&& eval + razor_margin[3 * ONE_PLY] <= alpha)
|
||||
|
@ -788,9 +788,8 @@ namespace {
|
|||
}
|
||||
|
||||
// Step 9. ProbCut (skipped when in check)
|
||||
// If we have a very good capture (i.e. SEE > seeValues[captured_piece_type])
|
||||
// and a reduced search returns a value much above beta, we can (almost)
|
||||
// safely prune the previous move.
|
||||
// If we have a good enough capture and a reduced search returns a value
|
||||
// much above beta, we can (almost) safely prune the previous move.
|
||||
if ( !PvNode
|
||||
&& depth >= 5 * ONE_PLY
|
||||
&& abs(beta) < VALUE_MATE_IN_MAX_PLY)
|
||||
|
@ -802,13 +801,13 @@ namespace {
|
|||
assert((ss-1)->currentMove != MOVE_NONE);
|
||||
assert((ss-1)->currentMove != MOVE_NULL);
|
||||
|
||||
MovePicker mp(pos, ttMove, PieceValue[MG][pos.captured_piece_type()]);
|
||||
MovePicker mp(pos, ttMove, rbeta - ss->staticEval);
|
||||
|
||||
while ((move = mp.next_move()) != MOVE_NONE)
|
||||
if (pos.legal(move))
|
||||
{
|
||||
ss->currentMove = move;
|
||||
ss->counterMoves = &CounterMoveHistory[pos.moved_piece(move)][to_sq(move)];
|
||||
ss->counterMoves = &thisThread->counterMoveHistory[pos.moved_piece(move)][to_sq(move)];
|
||||
pos.do_move(move, st, pos.gives_check(move));
|
||||
value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, rdepth, !cutNode);
|
||||
pos.undo_move(move);
|
||||
|
@ -922,41 +921,40 @@ moves_loop: // When in check search starts from here
|
|||
|
||||
// Step 13. Pruning at shallow depth
|
||||
if ( !rootNode
|
||||
&& !captureOrPromotion
|
||||
&& !inCheck
|
||||
&& !givesCheck
|
||||
&& !pos.advanced_pawn_push(move)
|
||||
&& bestValue > VALUE_MATED_IN_MAX_PLY)
|
||||
{
|
||||
if ( !captureOrPromotion
|
||||
&& !givesCheck
|
||||
&& !pos.advanced_pawn_push(move))
|
||||
{
|
||||
// Move count based pruning
|
||||
if (moveCountPruning)
|
||||
continue;
|
||||
|
||||
predictedDepth = std::max(newDepth - reduction<PvNode>(improving, depth, moveCount), DEPTH_ZERO);
|
||||
// Reduced depth of the next LMR search
|
||||
int lmrDepth = std::max(newDepth - reduction<PvNode>(improving, depth, moveCount), DEPTH_ZERO) / ONE_PLY;
|
||||
|
||||
// Countermoves based pruning
|
||||
if ( predictedDepth < 3 * ONE_PLY
|
||||
&& move != ss->killers[0]
|
||||
if ( lmrDepth < 3
|
||||
&& (!cmh || (*cmh )[moved_piece][to_sq(move)] < VALUE_ZERO)
|
||||
&& (!fmh || (*fmh )[moved_piece][to_sq(move)] < VALUE_ZERO)
|
||||
&& (!fmh2 || (*fmh2)[moved_piece][to_sq(move)] < VALUE_ZERO || (cmh && fmh)))
|
||||
continue;
|
||||
|
||||
// Futility pruning: parent node
|
||||
if ( predictedDepth < 7 * ONE_PLY
|
||||
&& ss->staticEval + 256 + 200 * predictedDepth / ONE_PLY <= alpha)
|
||||
if ( lmrDepth < 7
|
||||
&& ss->staticEval + 256 + 200 * lmrDepth <= alpha)
|
||||
continue;
|
||||
|
||||
// Prune moves with negative SEE at low depths and below a decreasing
|
||||
// threshold at higher depths.
|
||||
if (predictedDepth < 8 * ONE_PLY)
|
||||
{
|
||||
Value see_v = predictedDepth < 4 * ONE_PLY ? VALUE_ZERO
|
||||
: -PawnValueMg * 2 * int(predictedDepth - 3 * ONE_PLY) / ONE_PLY;
|
||||
|
||||
if (pos.see_sign(move) < see_v)
|
||||
// Prune moves with negative SEE
|
||||
if ( lmrDepth < 8
|
||||
&& pos.see_sign(move) < Value(-35 * lmrDepth * lmrDepth))
|
||||
continue;
|
||||
}
|
||||
else if ( depth < 7 * ONE_PLY
|
||||
&& pos.see_sign(move) < Value(-35 * depth / ONE_PLY * depth / ONE_PLY))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Speculative prefetch as early as possible
|
||||
|
@ -970,7 +968,7 @@ moves_loop: // When in check search starts from here
|
|||
}
|
||||
|
||||
ss->currentMove = move;
|
||||
ss->counterMoves = &CounterMoveHistory[moved_piece][to_sq(move)];
|
||||
ss->counterMoves = &thisThread->counterMoveHistory[moved_piece][to_sq(move)];
|
||||
|
||||
// Step 14. Make the move
|
||||
pos.do_move(move, st, givesCheck);
|
||||
|
@ -1140,7 +1138,7 @@ moves_loop: // When in check search starts from here
|
|||
}
|
||||
|
||||
// Extra penalty for a quiet TT move in previous ply when it gets refuted
|
||||
if ((ss-1)->moveCount == 1 && !pos.captured_piece_type())
|
||||
if ((ss-1)->moveCount == 1 && !pos.captured_piece())
|
||||
{
|
||||
Value penalty = Value(d * d + 4 * d + 1);
|
||||
Square prevSq = to_sq((ss-1)->currentMove);
|
||||
|
@ -1149,7 +1147,7 @@ moves_loop: // When in check search starts from here
|
|||
}
|
||||
// Bonus for prior countermove that caused the fail low
|
||||
else if ( depth >= 3 * ONE_PLY
|
||||
&& !pos.captured_piece_type()
|
||||
&& !pos.captured_piece()
|
||||
&& is_ok((ss-1)->currentMove))
|
||||
{
|
||||
int d = depth / ONE_PLY;
|
||||
|
@ -1643,7 +1641,7 @@ void Tablebases::filter_root_moves(Position& pos, Search::RootMoves& rootMoves)
|
|||
RootInTB = root_probe_wdl(pos, rootMoves, TB::Score);
|
||||
|
||||
// Only probe during search if winning
|
||||
if (TB::RootInTB && TB::Score <= VALUE_DRAW)
|
||||
if (RootInTB && TB::Score <= VALUE_DRAW)
|
||||
Cardinality = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,11 +25,10 @@
|
|||
#include <vector>
|
||||
|
||||
#include "misc.h"
|
||||
#include "position.h"
|
||||
#include "movepick.h"
|
||||
#include "types.h"
|
||||
|
||||
template<typename T, bool CM> struct Stats;
|
||||
typedef Stats<Value, true> CounterMoveStats;
|
||||
class Position;
|
||||
|
||||
namespace Search {
|
||||
|
||||
|
@ -49,6 +48,7 @@ struct Stack {
|
|||
CounterMoveStats* counterMoves;
|
||||
};
|
||||
|
||||
|
||||
/// RootMove struct is used for moves at the root of the tree. For each root move
|
||||
/// we store a score and a PV (really a refutation in the case of moves which
|
||||
/// fail low). Score is normally set at -VALUE_INFINITE for all non-pv moves.
|
||||
|
@ -68,6 +68,7 @@ struct RootMove {
|
|||
|
||||
typedef std::vector<RootMove> RootMoves;
|
||||
|
||||
|
||||
/// LimitsType struct stores information sent by GUI about available time to
|
||||
/// search the current move, maximum depth/time, if we are in analysis mode or
|
||||
/// if we have to ponder while it's our opponent's turn to move.
|
||||
|
@ -89,8 +90,9 @@ struct LimitsType {
|
|||
TimePoint startTime;
|
||||
};
|
||||
|
||||
/// The SignalsType struct stores atomic flags updated during the search
|
||||
/// typically in an async fashion e.g. to stop the search by the GUI.
|
||||
|
||||
/// SignalsType struct stores atomic flags updated during the search, typically
|
||||
/// in an async fashion e.g. to stop the search by the GUI.
|
||||
|
||||
struct SignalsType {
|
||||
std::atomic_bool stop, stopOnPonderhit;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "tbcore.cpp"
|
||||
|
||||
namespace Zobrist {
|
||||
extern Key psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
|
||||
extern Key psq[PIECE_NB][SQUARE_NB];
|
||||
}
|
||||
|
||||
int Tablebases::MaxCardinality = 0;
|
||||
|
@ -60,11 +60,11 @@ static uint64 calc_key(Position& pos, int mirror)
|
|||
color = !mirror ? WHITE : BLACK;
|
||||
for (pt = PAWN; pt <= KING; ++pt)
|
||||
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
|
||||
key ^= Zobrist::psq[WHITE][pt][i - 1];
|
||||
key ^= Zobrist::psq[make_piece(WHITE, pt)][i - 1];
|
||||
color = ~color;
|
||||
for (pt = PAWN; pt <= KING; ++pt)
|
||||
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
|
||||
key ^= Zobrist::psq[BLACK][pt][i - 1];
|
||||
key ^= Zobrist::psq[make_piece(BLACK, pt)][i - 1];
|
||||
|
||||
return key;
|
||||
}
|
||||
|
@ -83,11 +83,11 @@ static uint64 calc_key_from_pcs(int *pcs, int mirror)
|
|||
color = !mirror ? 0 : 8;
|
||||
for (pt = PAWN; pt <= KING; ++pt)
|
||||
for (i = 0; i < pcs[color + pt]; i++)
|
||||
key ^= Zobrist::psq[WHITE][pt][i];
|
||||
key ^= Zobrist::psq[make_piece(WHITE, pt)][i];
|
||||
color ^= 8;
|
||||
for (pt = PAWN; pt <= KING; ++pt)
|
||||
for (i = 0; i < pcs[color + pt]; i++)
|
||||
key ^= Zobrist::psq[BLACK][pt][i];
|
||||
key ^= Zobrist::psq[make_piece(BLACK, pt)][i];
|
||||
|
||||
return key;
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ static int probe_wdl_table(Position& pos, int *success)
|
|||
key = pos.material_key();
|
||||
|
||||
// Test for KvK.
|
||||
if (key == (Zobrist::psq[WHITE][KING][0] ^ Zobrist::psq[BLACK][KING][0]))
|
||||
if (key == (Zobrist::psq[W_KING][0] ^ Zobrist::psq[B_KING][0]))
|
||||
return 0;
|
||||
|
||||
ptr2 = TB_hash[key >> (64 - TBHASHBITS)];
|
||||
|
|
|
@ -66,11 +66,12 @@ public:
|
|||
Position rootPos;
|
||||
Search::RootMoves rootMoves;
|
||||
Depth rootDepth;
|
||||
Depth completedDepth;
|
||||
std::atomic_bool resetCalls;
|
||||
HistoryStats history;
|
||||
MoveStats counterMoves;
|
||||
FromToStats fromTo;
|
||||
Depth completedDepth;
|
||||
std::atomic_bool resetCalls;
|
||||
CounterMoveHistoryStats counterMoveHistory;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -183,13 +183,13 @@ enum Value : int {
|
|||
VALUE_MATE_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY,
|
||||
VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY,
|
||||
|
||||
PawnValueMg = 198, PawnValueEg = 258,
|
||||
KnightValueMg = 817, KnightValueEg = 896,
|
||||
BishopValueMg = 836, BishopValueEg = 907,
|
||||
RookValueMg = 1270, RookValueEg = 1356,
|
||||
QueenValueMg = 2521, QueenValueEg = 2658,
|
||||
PawnValueMg = 188, PawnValueEg = 248,
|
||||
KnightValueMg = 753, KnightValueEg = 832,
|
||||
BishopValueMg = 826, BishopValueEg = 897,
|
||||
RookValueMg = 1285, RookValueEg = 1371,
|
||||
QueenValueMg = 2513, QueenValueEg = 2650,
|
||||
|
||||
MidgameLimit = 15581, EndgameLimit = 3998
|
||||
MidgameLimit = 15258, EndgameLimit = 3915
|
||||
};
|
||||
|
||||
enum PieceType {
|
||||
|
@ -205,6 +205,10 @@ enum Piece {
|
|||
PIECE_NB = 16
|
||||
};
|
||||
|
||||
const Piece Pieces[] = { W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
|
||||
B_PAWN, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING };
|
||||
extern Value PieceValue[PHASE_NB][PIECE_NB];
|
||||
|
||||
enum Depth {
|
||||
|
||||
ONE_PLY = 1,
|
||||
|
@ -261,24 +265,24 @@ enum Rank {
|
|||
enum Score : int { SCORE_ZERO };
|
||||
|
||||
inline Score make_score(int mg, int eg) {
|
||||
return Score((mg << 16) + eg);
|
||||
return Score((eg << 16) + mg);
|
||||
}
|
||||
|
||||
/// Extracting the signed lower and upper 16 bits is not so trivial because
|
||||
/// according to the standard a simple cast to short is implementation defined
|
||||
/// and so is a right shift of a signed integer.
|
||||
inline Value mg_value(Score s) {
|
||||
|
||||
union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s + 0x8000) >> 16) };
|
||||
return Value(mg.s);
|
||||
}
|
||||
|
||||
inline Value eg_value(Score s) {
|
||||
|
||||
union { uint16_t u; int16_t s; } eg = { uint16_t(unsigned(s)) };
|
||||
union { uint16_t u; int16_t s; } eg = { uint16_t(unsigned(s + 0x8000) >> 16) };
|
||||
return Value(eg.s);
|
||||
}
|
||||
|
||||
inline Value mg_value(Score s) {
|
||||
|
||||
union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s)) };
|
||||
return Value(mg.s);
|
||||
}
|
||||
|
||||
#define ENABLE_BASE_OPERATORS_ON(T) \
|
||||
inline T operator+(T d1, T d2) { return T(int(d1) + int(d2)); } \
|
||||
inline T operator-(T d1, T d2) { return T(int(d1) - int(d2)); } \
|
||||
|
@ -326,16 +330,18 @@ inline Score operator/(Score s, int i) {
|
|||
return make_score(mg_value(s) / i, eg_value(s) / i);
|
||||
}
|
||||
|
||||
extern Value PieceValue[PHASE_NB][PIECE_NB];
|
||||
|
||||
inline Color operator~(Color c) {
|
||||
return Color(c ^ BLACK);
|
||||
return Color(c ^ BLACK); // Toggle color
|
||||
}
|
||||
|
||||
inline Square operator~(Square s) {
|
||||
return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8
|
||||
}
|
||||
|
||||
inline Piece operator~(Piece pc) {
|
||||
return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT
|
||||
}
|
||||
|
||||
inline CastlingRight operator|(Color c, CastlingSide s) {
|
||||
return CastlingRight(WHITE_OO << ((s == QUEEN_SIDE) + 2 * c));
|
||||
}
|
||||
|
@ -349,11 +355,11 @@ inline Value mated_in(int ply) {
|
|||
}
|
||||
|
||||
inline Square make_square(File f, Rank r) {
|
||||
return Square((r << 3) | f);
|
||||
return Square((r << 3) + f);
|
||||
}
|
||||
|
||||
inline Piece make_piece(Color c, PieceType pt) {
|
||||
return Piece((c << 3) | pt);
|
||||
return Piece((c << 3) + pt);
|
||||
}
|
||||
|
||||
inline PieceType type_of(Piece pc) {
|
||||
|
@ -415,12 +421,12 @@ inline PieceType promotion_type(Move m) {
|
|||
}
|
||||
|
||||
inline Move make_move(Square from, Square to) {
|
||||
return Move(to | (from << 6));
|
||||
return Move((from << 6) + to);
|
||||
}
|
||||
|
||||
template<MoveType T>
|
||||
inline Move make(Square from, Square to, PieceType pt = KNIGHT) {
|
||||
return Move(to | (from << 6) | T | ((pt - KNIGHT) << 12));
|
||||
return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to);
|
||||
}
|
||||
|
||||
inline bool is_ok(Move m) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user