1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-07-11 19:49:14 +00:00

Delay costly SEE call during captures ordering in MovePicker

When ordering moves we push all captures with negative SEE values
to badCaptures[] array during the scoring phase.

This patch delays the costly SEE call up to when the move has been
picked up in pick_move_from_list(), this way we save some SEE calls
in case we get a cutoff.

It seems we have a speed gain of about 1-1.5 % in terms of nodes/sec
and profiling seems to confirm the small but real speed increase.

Idea from Pablo Vazquez on talkchess.com
http://www.talkchess.com/forum/viewtopic.php?t=29018&start=20

It would be a no functional change but actually it is not because
now sorting set is different and so std::sort(), that is not a
stable sort, does not guarantees the order of same scored moves to
remain the same as before.

After 952 games at 1+0 we are below error bar, almost equal just
6 games of difference (+2 ELO)

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
Marco Costalba 2009-07-23 07:13:06 +01:00
parent 8654fee18c
commit 20224a5bbf
2 changed files with 37 additions and 51 deletions

View file

@ -141,12 +141,10 @@ Move MovePicker::get_next_move() {
score_captures(); score_captures();
std::sort(moves, moves + numOfMoves); std::sort(moves, moves + numOfMoves);
movesPicked = 0; movesPicked = 0;
checkLegal = true;
break; break;
case PH_KILLERS: case PH_KILLERS:
movesPicked = numOfMoves = 0; movesPicked = numOfMoves = 0;
checkLegal = false;
if (killer1 != MOVE_NONE && move_is_legal(pos, killer1, pinned) && !pos.move_is_capture(killer1)) if (killer1 != MOVE_NONE && move_is_legal(pos, killer1, pinned) && !pos.move_is_capture(killer1))
moves[numOfMoves++].move = killer1; moves[numOfMoves++].move = killer1;
if (killer2 != MOVE_NONE && move_is_legal(pos, killer2, pinned) && !pos.move_is_capture(killer2) ) if (killer2 != MOVE_NONE && move_is_legal(pos, killer2, pinned) && !pos.move_is_capture(killer2) )
@ -155,16 +153,16 @@ Move MovePicker::get_next_move() {
case PH_NONCAPTURES: case PH_NONCAPTURES:
checkKillers = (numOfMoves != 0); // previous phase is PH_KILLERS checkKillers = (numOfMoves != 0); // previous phase is PH_KILLERS
checkLegal = true;
numOfMoves = generate_noncaptures(pos, moves); numOfMoves = generate_noncaptures(pos, moves);
score_noncaptures(); score_noncaptures();
std::sort(moves, moves + numOfMoves); std::sort(moves, moves + numOfMoves);
movesPicked = 0; movesPicked = 0;
checkLegal = true;
break; break;
case PH_BAD_CAPTURES: case PH_BAD_CAPTURES:
// Bad captures SEE value is already calculated by score_captures() // Bad captures SEE value is already calculated so just sort them
// so just sort them to get SEE move ordering. // to get SEE move ordering.
std::sort(badCaptures, badCaptures + numOfBadCaptures); std::sort(badCaptures, badCaptures + numOfBadCaptures);
movesPicked = 0; movesPicked = 0;
break; break;
@ -179,7 +177,7 @@ Move MovePicker::get_next_move() {
case PH_QCAPTURES: case PH_QCAPTURES:
numOfMoves = generate_captures(pos, moves); numOfMoves = generate_captures(pos, moves);
score_qcaptures(); score_captures();
std::sort(moves, moves + numOfMoves); std::sort(moves, moves + numOfMoves);
movesPicked = 0; movesPicked = 0;
break; break;
@ -236,32 +234,22 @@ void MovePicker::score_captures() {
// where it is possible to recapture with the hanging piece). Exchanging // where it is possible to recapture with the hanging piece). Exchanging
// big pieces before capturing a hanging piece probably helps to reduce // big pieces before capturing a hanging piece probably helps to reduce
// the subtree size. // the subtree size.
// While scoring captures it moves all captures with negative SEE values // In main search we want to push captures with negative SEE values to
// to the badCaptures[] array. // badCaptures[] array, but instead of doing it now we delay till when
// the move has been picked up in pick_move_from_list(), this way we save
// some SEE calls in case we get a cutoff (idea from Pablo Vazquez).
Move m; Move m;
int seeValue;
// Use MVV/LVA ordering
for (int i = 0; i < numOfMoves; i++) for (int i = 0; i < numOfMoves; i++)
{ {
m = moves[i].move; m = moves[i].move;
seeValue = pos.see_sign(m);
if (seeValue >= 0)
{
if (move_is_promotion(m)) if (move_is_promotion(m))
moves[i].score = QueenValueMidgame; moves[i].score = QueenValueMidgame;
else else
moves[i].score = int(pos.midgame_value_of_piece_on(move_to(m))) moves[i].score = int(pos.midgame_value_of_piece_on(move_to(m)))
-int(pos.type_of_piece_on(move_from(m))); -int(pos.type_of_piece_on(move_from(m)));
} }
else
{
// Losing capture, move it to the badCaptures[] array
assert(numOfBadCaptures < 63);
moves[i].score = seeValue;
badCaptures[numOfBadCaptures++] = moves[i];
moves[i--] = moves[--numOfMoves];
}
}
} }
void MovePicker::score_noncaptures() { void MovePicker::score_noncaptures() {
@ -304,20 +292,6 @@ void MovePicker::score_evasions() {
} }
} }
void MovePicker::score_qcaptures() {
// Use MVV/LVA ordering
for (int i = 0; i < numOfMoves; i++)
{
Move m = moves[i].move;
if (move_is_promotion(m))
moves[i].score = QueenValueMidgame;
else
moves[i].score = int(pos.midgame_value_of_piece_on(move_to(m)))
-int(pos.type_of_piece_on(move_from(m)));
}
}
/// MovePicker::pick_move_from_list() picks the move with the biggest score /// MovePicker::pick_move_from_list() picks the move with the biggest score
/// from a list of generated moves (moves[] or badCaptures[], depending on /// from a list of generated moves (moves[] or badCaptures[], depending on
@ -333,6 +307,26 @@ Move MovePicker::pick_move_from_list() {
switch (PhaseTable[phaseIndex]) { switch (PhaseTable[phaseIndex]) {
case PH_GOOD_CAPTURES: case PH_GOOD_CAPTURES:
while (movesPicked < numOfMoves)
{
Move move = moves[movesPicked++].move;
if ( move != ttMove
&& move != mateKiller
&& pos.pl_move_is_legal(move, pinned))
{
// Check for a non negative SEE now
int seeValue = pos.see_sign(move);
if (seeValue >= 0)
return move;
// Losing capture, move it to the badCaptures[] array, note
// that move has now been already checked for legality.
assert(numOfBadCaptures < 63);
badCaptures[numOfBadCaptures].move = move;
badCaptures[numOfBadCaptures++].score = seeValue;
}
}
break;
case PH_KILLERS: case PH_KILLERS:
case PH_NONCAPTURES: case PH_NONCAPTURES:
while (movesPicked < numOfMoves) while (movesPicked < numOfMoves)
@ -349,18 +343,11 @@ Move MovePicker::pick_move_from_list() {
case PH_EVASIONS: case PH_EVASIONS:
if (movesPicked < numOfMoves) if (movesPicked < numOfMoves)
return moves[movesPicked++].move; return moves[movesPicked++].move;
break; break;
case PH_BAD_CAPTURES: case PH_BAD_CAPTURES:
while (movesPicked < numOfBadCaptures) if (movesPicked < numOfBadCaptures)
{ return badCaptures[movesPicked++].move;
Move move = badCaptures[movesPicked++].move;
if ( move != ttMove
&& move != mateKiller
&& pos.pl_move_is_legal(move, pinned))
return move;
}
break; break;
case PH_QCAPTURES: case PH_QCAPTURES:

View file

@ -77,7 +77,6 @@ private:
void score_captures(); void score_captures();
void score_noncaptures(); void score_noncaptures();
void score_evasions(); void score_evasions();
void score_qcaptures();
Move pick_move_from_list(); Move pick_move_from_list();
const Position& pos; const Position& pos;