mirror of
https://github.com/sockspls/badfish
synced 2025-07-11 19:49:14 +00:00
Add a second level of follow-up moves
STC: LLR: 2.95 (-2.94,2.94) [0.00,5.00] Total: 6438 W: 1229 L: 1077 D: 4132 LTC: LLR: 2.96 (-2.94,2.94) [0.00,5.00] Total: 4000 W: 605 L: 473 D: 2922 bench: 7378965 Resolves #636
This commit is contained in:
parent
a037e20f28
commit
464fec0493
4 changed files with 72 additions and 51 deletions
|
@ -67,22 +67,21 @@ namespace {
|
||||||
/// search captures, promotions, and some checks) and how important good move
|
/// search captures, promotions, and some checks) and how important good move
|
||||||
/// ordering is at the current node.
|
/// ordering is at the current node.
|
||||||
|
|
||||||
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h,
|
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Search::Stack* s)
|
||||||
const CounterMoveStats& cmh, const CounterMoveStats& fmh,
|
: pos(p), ss(s), depth(d) {
|
||||||
Move cm, Search::Stack* s)
|
|
||||||
: pos(p), history(h), counterMoveHistory(&cmh),
|
|
||||||
followupMoveHistory(&fmh), ss(s), countermove(cm), depth(d) {
|
|
||||||
|
|
||||||
assert(d > DEPTH_ZERO);
|
assert(d > DEPTH_ZERO);
|
||||||
|
|
||||||
|
Square prevSq = to_sq((ss-1)->currentMove);
|
||||||
|
countermove = pos.this_thread()->counterMoves[pos.piece_on(prevSq)][prevSq];
|
||||||
|
|
||||||
stage = pos.checkers() ? EVASION : MAIN_SEARCH;
|
stage = pos.checkers() ? EVASION : MAIN_SEARCH;
|
||||||
ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
|
ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE;
|
||||||
endMoves += (ttMove != MOVE_NONE);
|
endMoves += (ttMove != MOVE_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
|
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, Square s)
|
||||||
const HistoryStats& h, Square s)
|
: pos(p) {
|
||||||
: pos(p), history(h) {
|
|
||||||
|
|
||||||
assert(d <= DEPTH_ZERO);
|
assert(d <= DEPTH_ZERO);
|
||||||
|
|
||||||
|
@ -106,8 +105,8 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
|
||||||
endMoves += (ttMove != MOVE_NONE);
|
endMoves += (ttMove != MOVE_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
MovePicker::MovePicker(const Position& p, Move ttm, const HistoryStats& h, Value th)
|
MovePicker::MovePicker(const Position& p, Move ttm, Value th)
|
||||||
: pos(p), history(h), threshold(th) {
|
: pos(p), threshold(th) {
|
||||||
|
|
||||||
assert(!pos.checkers());
|
assert(!pos.checkers());
|
||||||
|
|
||||||
|
@ -142,10 +141,17 @@ void MovePicker::score<CAPTURES>() {
|
||||||
template<>
|
template<>
|
||||||
void MovePicker::score<QUIETS>() {
|
void MovePicker::score<QUIETS>() {
|
||||||
|
|
||||||
|
const HistoryStats& history = pos.this_thread()->history;
|
||||||
|
|
||||||
|
const CounterMoveStats* cm = (ss-1)->counterMoves;
|
||||||
|
const CounterMoveStats* fm = (ss-2)->counterMoves;
|
||||||
|
const CounterMoveStats* f2 = (ss-4)->counterMoves;
|
||||||
|
|
||||||
for (auto& m : *this)
|
for (auto& m : *this)
|
||||||
m.value = history[pos.moved_piece(m)][to_sq(m)]
|
m.value = history[pos.moved_piece(m)][to_sq(m)]
|
||||||
+ (*counterMoveHistory )[pos.moved_piece(m)][to_sq(m)]
|
+ (cm ? (*cm)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO)
|
||||||
+ (*followupMoveHistory)[pos.moved_piece(m)][to_sq(m)];
|
+ (fm ? (*fm)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO)
|
||||||
|
+ (f2 ? (*f2)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
@ -153,6 +159,7 @@ void MovePicker::score<EVASIONS>() {
|
||||||
// Try winning and equal captures ordered by MVV/LVA, then non-captures ordered
|
// Try winning and equal captures ordered by MVV/LVA, then non-captures ordered
|
||||||
// by history value, then bad captures and quiet moves with a negative SEE ordered
|
// by history value, then bad captures and quiet moves with a negative SEE ordered
|
||||||
// by SEE value.
|
// by SEE value.
|
||||||
|
const HistoryStats& history = pos.this_thread()->history;
|
||||||
Value see;
|
Value see;
|
||||||
|
|
||||||
for (auto& m : *this)
|
for (auto& m : *this)
|
||||||
|
|
|
@ -79,10 +79,9 @@ public:
|
||||||
MovePicker(const MovePicker&) = delete;
|
MovePicker(const MovePicker&) = delete;
|
||||||
MovePicker& operator=(const MovePicker&) = delete;
|
MovePicker& operator=(const MovePicker&) = delete;
|
||||||
|
|
||||||
MovePicker(const Position&, Move, const HistoryStats&, Value);
|
MovePicker(const Position&, Move, Value);
|
||||||
MovePicker(const Position&, Move, Depth, const HistoryStats&, Square);
|
MovePicker(const Position&, Move, Depth, Square);
|
||||||
MovePicker(const Position&, Move, Depth, const HistoryStats&,
|
MovePicker(const Position&, Move, Depth, Search::Stack*);
|
||||||
const CounterMoveStats&, const CounterMoveStats&, Move, Search::Stack*);
|
|
||||||
|
|
||||||
Move next_move();
|
Move next_move();
|
||||||
|
|
||||||
|
@ -93,10 +92,7 @@ private:
|
||||||
ExtMove* end() { return endMoves; }
|
ExtMove* end() { return endMoves; }
|
||||||
|
|
||||||
const Position& pos;
|
const Position& pos;
|
||||||
const HistoryStats& history;
|
const Search::Stack* ss;
|
||||||
const CounterMoveStats* counterMoveHistory;
|
|
||||||
const CounterMoveStats* followupMoveHistory;
|
|
||||||
Search::Stack* ss;
|
|
||||||
Move countermove;
|
Move countermove;
|
||||||
Depth depth;
|
Depth depth;
|
||||||
Move ttMove;
|
Move ttMove;
|
||||||
|
|
|
@ -380,12 +380,12 @@ void MainThread::search() {
|
||||||
|
|
||||||
void Thread::search() {
|
void Thread::search() {
|
||||||
|
|
||||||
Stack stack[MAX_PLY+4], *ss = stack+2; // To allow referencing (ss-2) and (ss+2)
|
Stack stack[MAX_PLY+7], *ss = stack+5; // To allow referencing (ss-5) and (ss+2)
|
||||||
Value bestValue, alpha, beta, delta;
|
Value bestValue, alpha, beta, delta;
|
||||||
Move easyMove = MOVE_NONE;
|
Move easyMove = MOVE_NONE;
|
||||||
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
|
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
|
||||||
|
|
||||||
std::memset(ss-2, 0, 5 * sizeof(Stack));
|
std::memset(ss-5, 0, 8 * sizeof(Stack));
|
||||||
|
|
||||||
bestValue = delta = alpha = -VALUE_INFINITE;
|
bestValue = delta = alpha = -VALUE_INFINITE;
|
||||||
beta = VALUE_INFINITE;
|
beta = VALUE_INFINITE;
|
||||||
|
@ -657,6 +657,7 @@ namespace {
|
||||||
assert(0 <= ss->ply && ss->ply < MAX_PLY);
|
assert(0 <= ss->ply && ss->ply < MAX_PLY);
|
||||||
|
|
||||||
ss->currentMove = (ss+1)->excludedMove = bestMove = MOVE_NONE;
|
ss->currentMove = (ss+1)->excludedMove = bestMove = MOVE_NONE;
|
||||||
|
ss->counterMoves = nullptr;
|
||||||
(ss+1)->skipEarlyPruning = false;
|
(ss+1)->skipEarlyPruning = false;
|
||||||
(ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
|
(ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
|
||||||
|
|
||||||
|
@ -780,6 +781,7 @@ namespace {
|
||||||
&& pos.non_pawn_material(pos.side_to_move()))
|
&& pos.non_pawn_material(pos.side_to_move()))
|
||||||
{
|
{
|
||||||
ss->currentMove = MOVE_NULL;
|
ss->currentMove = MOVE_NULL;
|
||||||
|
ss->counterMoves = nullptr;
|
||||||
|
|
||||||
assert(eval - beta >= 0);
|
assert(eval - beta >= 0);
|
||||||
|
|
||||||
|
@ -828,13 +830,14 @@ namespace {
|
||||||
assert((ss-1)->currentMove != MOVE_NONE);
|
assert((ss-1)->currentMove != MOVE_NONE);
|
||||||
assert((ss-1)->currentMove != MOVE_NULL);
|
assert((ss-1)->currentMove != MOVE_NULL);
|
||||||
|
|
||||||
MovePicker mp(pos, ttMove, thisThread->history, PieceValue[MG][pos.captured_piece_type()]);
|
MovePicker mp(pos, ttMove, PieceValue[MG][pos.captured_piece_type()]);
|
||||||
CheckInfo ci(pos);
|
CheckInfo ci(pos);
|
||||||
|
|
||||||
while ((move = mp.next_move()) != MOVE_NONE)
|
while ((move = mp.next_move()) != MOVE_NONE)
|
||||||
if (pos.legal(move, ci.pinned))
|
if (pos.legal(move, ci.pinned))
|
||||||
{
|
{
|
||||||
ss->currentMove = move;
|
ss->currentMove = move;
|
||||||
|
ss->counterMoves = &CounterMoveHistory[pos.moved_piece(move)][to_sq(move)];
|
||||||
pos.do_move(move, st, pos.gives_check(move, ci));
|
pos.do_move(move, st, pos.gives_check(move, ci));
|
||||||
value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, rdepth, !cutNode);
|
value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, rdepth, !cutNode);
|
||||||
pos.undo_move(move);
|
pos.undo_move(move);
|
||||||
|
@ -860,12 +863,9 @@ namespace {
|
||||||
moves_loop: // When in check search starts from here
|
moves_loop: // When in check search starts from here
|
||||||
|
|
||||||
Square prevSq = to_sq((ss-1)->currentMove);
|
Square prevSq = to_sq((ss-1)->currentMove);
|
||||||
Square ownPrevSq = to_sq((ss-2)->currentMove);
|
|
||||||
Move cm = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq];
|
|
||||||
const CounterMoveStats& cmh = CounterMoveHistory[pos.piece_on(prevSq)][prevSq];
|
const CounterMoveStats& cmh = CounterMoveHistory[pos.piece_on(prevSq)][prevSq];
|
||||||
const CounterMoveStats& fmh = CounterMoveHistory[pos.piece_on(ownPrevSq)][ownPrevSq];
|
|
||||||
|
|
||||||
MovePicker mp(pos, ttMove, depth, thisThread->history, cmh, fmh, cm, ss);
|
MovePicker mp(pos, ttMove, depth, ss);
|
||||||
CheckInfo ci(pos);
|
CheckInfo ci(pos);
|
||||||
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
|
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
|
||||||
improving = ss->staticEval >= (ss-2)->staticEval
|
improving = ss->staticEval >= (ss-2)->staticEval
|
||||||
|
@ -992,6 +992,7 @@ moves_loop: // When in check search starts from here
|
||||||
}
|
}
|
||||||
|
|
||||||
ss->currentMove = move;
|
ss->currentMove = move;
|
||||||
|
ss->counterMoves = &CounterMoveHistory[pos.moved_piece(move)][to_sq(move)];
|
||||||
|
|
||||||
// Step 14. Make the move
|
// Step 14. Make the move
|
||||||
pos.do_move(move, st, givesCheck);
|
pos.do_move(move, st, givesCheck);
|
||||||
|
@ -1153,13 +1154,17 @@ moves_loop: // When in check search starts from here
|
||||||
&& !bestMove
|
&& !bestMove
|
||||||
&& !inCheck
|
&& !inCheck
|
||||||
&& !pos.captured_piece_type()
|
&& !pos.captured_piece_type()
|
||||||
&& is_ok((ss - 1)->currentMove)
|
&& is_ok((ss-1)->currentMove))
|
||||||
&& is_ok((ss - 2)->currentMove))
|
|
||||||
{
|
{
|
||||||
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY - 1);
|
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY - 1);
|
||||||
Square prevPrevSq = to_sq((ss - 2)->currentMove);
|
if ((ss-2)->counterMoves)
|
||||||
CounterMoveStats& prevCmh = CounterMoveHistory[pos.piece_on(prevPrevSq)][prevPrevSq];
|
(ss-2)->counterMoves->update(pos.piece_on(prevSq), prevSq, bonus);
|
||||||
prevCmh.update(pos.piece_on(prevSq), prevSq, bonus);
|
|
||||||
|
if ((ss-3)->counterMoves)
|
||||||
|
(ss-3)->counterMoves->update(pos.piece_on(prevSq), prevSq, bonus);
|
||||||
|
|
||||||
|
if ((ss-5)->counterMoves)
|
||||||
|
(ss-5)->counterMoves->update(pos.piece_on(prevSq), prevSq, bonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
tte->save(posKey, value_to_tt(bestValue, ss->ply),
|
tte->save(posKey, value_to_tt(bestValue, ss->ply),
|
||||||
|
@ -1280,7 +1285,7 @@ moves_loop: // When in check search starts from here
|
||||||
// to search the moves. Because the depth is <= 0 here, only captures,
|
// to search the moves. Because the depth is <= 0 here, only captures,
|
||||||
// queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will
|
// queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will
|
||||||
// be generated.
|
// be generated.
|
||||||
MovePicker mp(pos, ttMove, depth, pos.this_thread()->history, to_sq((ss-1)->currentMove));
|
MovePicker mp(pos, ttMove, depth, to_sq((ss-1)->currentMove));
|
||||||
CheckInfo ci(pos);
|
CheckInfo ci(pos);
|
||||||
|
|
||||||
// Loop through the moves until no moves remain or a beta cutoff occurs
|
// Loop through the moves until no moves remain or a beta cutoff occurs
|
||||||
|
@ -1434,42 +1439,51 @@ moves_loop: // When in check search starts from here
|
||||||
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY - 1);
|
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY - 1);
|
||||||
|
|
||||||
Square prevSq = to_sq((ss-1)->currentMove);
|
Square prevSq = to_sq((ss-1)->currentMove);
|
||||||
Square ownPrevSq = to_sq((ss-2)->currentMove);
|
CounterMoveStats* cmh = (ss-1)->counterMoves;
|
||||||
CounterMoveStats& cmh = CounterMoveHistory[pos.piece_on(prevSq)][prevSq];
|
CounterMoveStats* fmh = (ss-2)->counterMoves;
|
||||||
CounterMoveStats& fmh = CounterMoveHistory[pos.piece_on(ownPrevSq)][ownPrevSq];
|
CounterMoveStats* fmh2 = (ss-4)->counterMoves;
|
||||||
Thread* thisThread = pos.this_thread();
|
Thread* thisThread = pos.this_thread();
|
||||||
|
|
||||||
thisThread->history.update(pos.moved_piece(move), to_sq(move), bonus);
|
thisThread->history.update(pos.moved_piece(move), to_sq(move), bonus);
|
||||||
|
|
||||||
if (is_ok((ss-1)->currentMove))
|
if (cmh)
|
||||||
{
|
{
|
||||||
thisThread->counterMoves.update(pos.piece_on(prevSq), prevSq, move);
|
thisThread->counterMoves.update(pos.piece_on(prevSq), prevSq, move);
|
||||||
cmh.update(pos.moved_piece(move), to_sq(move), bonus);
|
cmh->update(pos.moved_piece(move), to_sq(move), bonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_ok((ss-2)->currentMove))
|
if (fmh)
|
||||||
fmh.update(pos.moved_piece(move), to_sq(move), bonus);
|
fmh->update(pos.moved_piece(move), to_sq(move), bonus);
|
||||||
|
|
||||||
|
if (fmh2)
|
||||||
|
fmh2->update(pos.moved_piece(move), to_sq(move), bonus);
|
||||||
|
|
||||||
// Decrease all the other played quiet moves
|
// Decrease all the other played quiet moves
|
||||||
for (int i = 0; i < quietsCnt; ++i)
|
for (int i = 0; i < quietsCnt; ++i)
|
||||||
{
|
{
|
||||||
thisThread->history.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
|
thisThread->history.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
|
||||||
|
|
||||||
if (is_ok((ss-1)->currentMove))
|
if (cmh)
|
||||||
cmh.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
|
cmh->update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
|
||||||
|
|
||||||
if (is_ok((ss-2)->currentMove))
|
if (fmh)
|
||||||
fmh.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
|
fmh->update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
|
||||||
|
|
||||||
|
if (fmh2)
|
||||||
|
fmh2->update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra penalty for a quiet TT move in previous ply when it gets refuted
|
// Extra penalty for a quiet TT move in previous ply when it gets refuted
|
||||||
if ( (ss-1)->moveCount == 1
|
if ((ss-1)->moveCount == 1 && !pos.captured_piece_type())
|
||||||
&& !pos.captured_piece_type()
|
|
||||||
&& is_ok((ss-2)->currentMove))
|
|
||||||
{
|
{
|
||||||
Square prevPrevSq = to_sq((ss-2)->currentMove);
|
if ((ss-2)->counterMoves)
|
||||||
CounterMoveStats& prevCmh = CounterMoveHistory[pos.piece_on(prevPrevSq)][prevPrevSq];
|
(ss-2)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY);
|
||||||
prevCmh.update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY);
|
|
||||||
|
if ((ss-3)->counterMoves)
|
||||||
|
(ss-3)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY);
|
||||||
|
|
||||||
|
if ((ss-5)->counterMoves)
|
||||||
|
(ss-5)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,9 @@
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
template<typename T, bool CM> struct Stats;
|
||||||
|
typedef Stats<Value, true> CounterMoveStats;
|
||||||
|
|
||||||
namespace Search {
|
namespace Search {
|
||||||
|
|
||||||
/// Stack struct keeps track of the information we need to remember from nodes
|
/// Stack struct keeps track of the information we need to remember from nodes
|
||||||
|
@ -43,6 +46,7 @@ struct Stack {
|
||||||
Value staticEval;
|
Value staticEval;
|
||||||
bool skipEarlyPruning;
|
bool skipEarlyPruning;
|
||||||
int moveCount;
|
int moveCount;
|
||||||
|
CounterMoveStats* counterMoves;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// RootMove struct is used for moves at the root of the tree. For each root move
|
/// RootMove struct is used for moves at the root of the tree. For each root move
|
||||||
|
|
Loading…
Add table
Reference in a new issue