1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-04-29 16:23:09 +00:00

Restore original movepick modulo space inflation

We have a regression somewhere here so restart from zero
and proceed one change at a time.

With this modification we have the same strenght of
"Introduce Stockfish" patch that is our strongest to date.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
Marco Costalba 2008-10-25 15:28:24 +01:00
parent 5dd9159106
commit f8bc38a006
2 changed files with 146 additions and 122 deletions

View file

@ -7,12 +7,12 @@
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Stockfish is distributed in the hope that it will be useful, Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
@ -61,8 +61,9 @@ namespace {
/// search captures, promotions and some checks) and about how important good /// search captures, promotions and some checks) and about how important good
/// move ordering is at the current node. /// move ordering is at the current node.
MovePicker::MovePicker(const Position& p, bool pvnode, Move ttm, Move mk, MovePicker::MovePicker(Position& p, bool pvnode, Move ttm, Move mk,
Move k1, Move k2, Depth d) : pos(p) { Move k1, Move k2, Depth d) {
pos = &p;
pvNode = pvnode; pvNode = pvnode;
ttMove = ttm; ttMove = ttm;
mateKiller = (mk == ttm)? MOVE_NONE : mk; mateKiller = (mk == ttm)? MOVE_NONE : mk;
@ -111,13 +112,16 @@ Move MovePicker::get_next_move() {
// Next phase // Next phase
phaseIndex++; phaseIndex++;
switch (PhaseTable[phaseIndex]) { switch (PhaseTable[phaseIndex]) {
case PH_TT_MOVE: case PH_TT_MOVE:
if (ttMove != MOVE_NONE) if (ttMove != MOVE_NONE)
{ {
assert(move_is_ok(ttMove)); assert(move_is_ok(ttMove));
if (generate_move_if_legal(pos, ttMove, pinned) != MOVE_NONE) Move m = generate_move_if_legal(*pos, ttMove, pinned);
return ttMove; if (m != MOVE_NONE)
{
assert(m == ttMove);
return m;
}
} }
break; break;
@ -125,13 +129,17 @@ Move MovePicker::get_next_move() {
if (mateKiller != MOVE_NONE) if (mateKiller != MOVE_NONE)
{ {
assert(move_is_ok(mateKiller)); assert(move_is_ok(mateKiller));
if (generate_move_if_legal(pos, mateKiller, pinned) != MOVE_NONE) Move m = generate_move_if_legal(*pos, mateKiller, pinned);
return mateKiller; if (m != MOVE_NONE)
} {
break; assert(m == mateKiller);
return m;
}
}
break;
case PH_GOOD_CAPTURES: case PH_GOOD_CAPTURES:
numOfMoves = generate_captures(pos, moves); numOfMoves = generate_captures(*pos, moves);
score_captures(); score_captures();
movesPicked = 0; movesPicked = 0;
break; break;
@ -141,26 +149,26 @@ Move MovePicker::get_next_move() {
break; break;
case PH_NONCAPTURES: case PH_NONCAPTURES:
numOfMoves = generate_noncaptures(pos, moves); numOfMoves = generate_noncaptures(*pos, moves);
score_noncaptures(); score_noncaptures();
movesPicked = 0; movesPicked = 0;
break; break;
case PH_EVASIONS: case PH_EVASIONS:
assert(pos.is_check()); assert(pos->is_check());
numOfMoves = generate_evasions(pos, moves); numOfMoves = generate_evasions(*pos, moves);
score_evasions(); score_evasions();
movesPicked = 0; movesPicked = 0;
break; break;
case PH_QCAPTURES: case PH_QCAPTURES:
numOfMoves = generate_captures(pos, moves); numOfMoves = generate_captures(*pos, moves);
score_qcaptures(); score_qcaptures();
movesPicked = 0; movesPicked = 0;
break; break;
case PH_QCHECKS: case PH_QCHECKS:
numOfMoves = generate_checks(pos, moves, dc); numOfMoves = generate_checks(*pos, moves, dc);
movesPicked = 0; movesPicked = 0;
break; break;
@ -173,7 +181,6 @@ Move MovePicker::get_next_move() {
} }
} }
assert(false); assert(false);
return MOVE_NONE; return MOVE_NONE;
} }
@ -183,27 +190,30 @@ Move MovePicker::get_next_move() {
Move MovePicker::get_next_move(Lock &lock) { Move MovePicker::get_next_move(Lock &lock) {
lock_grab(&lock); Move m;
if (finished)
{
lock_release(&lock);
return MOVE_NONE;
}
Move m = get_next_move();
if (m == MOVE_NONE)
finished = true;
lock_release(&lock); lock_grab(&lock);
return m; if (finished)
{
lock_release(&lock);
return MOVE_NONE;
}
m = get_next_move();
if (m == MOVE_NONE)
finished = true;
lock_release(&lock);
return m;
} }
/// MovePicker::score_captures(), MovePicker::score_noncaptures(), /// MovePicker::score_captures(), MovePicker::score_noncaptures(),
/// MovePicker::score_evasions() and MovePicker::score_qcaptures() assign a /// MovePicker::score_evasions() and MovePicker::score_qcaptures() assign a
/// numerical move ordering score to each move in a move list. The moves /// numerical move ordering score to each move in a move list. The moves
/// with highest scores will be picked first by pick_move_from_list(). /// with highest scores will be picked first by pick_move_from_list().
void MovePicker::score_captures() { void MovePicker::score_captures() {
// Winning and equal captures in the main search are ordered by MVV. // Winning and equal captures in the main search are ordered by MVV/LVA.
// Suprisingly, this appears to perform slightly better than SEE based // Suprisingly, this appears to perform slightly better than SEE based
// move ordering. The reason is probably that in a position with a winning // move ordering. The reason is probably that in a position with a winning
// capture, capturing a more valuable (but sufficiently defended) piece // capture, capturing a more valuable (but sufficiently defended) piece
@ -214,11 +224,16 @@ void MovePicker::score_captures() {
// the subtree size. // the subtree size.
for (int i = 0; i < numOfMoves; i++) for (int i = 0; i < numOfMoves; i++)
{ {
Move m = moves[i].move; int seeValue = pos->see(moves[i].move);
moves[i].score = pos.see(m); if (seeValue >= 0)
if (moves[i].score >= 0) {
moves[i].score = move_promotion(m) ? QueenValueMidgame if (move_promotion(moves[i].move))
: pos.midgame_value_of_piece_on(move_to(m)); moves[i].score = QueenValueMidgame;
else
moves[i].score = int(pos->midgame_value_of_piece_on(move_to(moves[i].move)))
-int(pos->type_of_piece_on(move_from(moves[i].move)));
} else
moves[i].score = seeValue;
} }
} }
@ -232,13 +247,7 @@ void MovePicker::score_noncaptures() {
else if (m == killer2) else if (m == killer2)
moves[i].score = HistoryMax + 1; moves[i].score = HistoryMax + 1;
else else
moves[i].score = H.move_ordering_score(pos.piece_on(move_from(m)), m); moves[i].score = H.move_ordering_score(pos->piece_on(move_from(m)), m);
// Ensure moves in history are always sorted as first
if (moves[i].score > 0)
moves[i].score += 1000;
moves[i].score += pos.mg_pst_delta(moves[i].move);
} }
} }
@ -249,47 +258,31 @@ void MovePicker::score_evasions() {
Move m = moves[i].move; Move m = moves[i].move;
if (m == ttMove) if (m == ttMove)
moves[i].score = 2*HistoryMax; moves[i].score = 2*HistoryMax;
else if (!pos.square_is_empty(move_to(m))) else if(!pos->square_is_empty(move_to(m)))
{ {
moves[i].score = pos.see(m); int seeScore = pos->see(m);
if (moves[i].score >= 0) moves[i].score = (seeScore >= 0)? seeScore + HistoryMax : seeScore;
moves[i].score += HistoryMax; } else
} moves[i].score = H.move_ordering_score(pos->piece_on(move_from(m)), m);
else
moves[i].score = H.move_ordering_score(pos.piece_on(move_from(m)), m);
} }
// FIXME try psqt also here // FIXME try psqt also here
} }
void MovePicker::score_qcaptures() { void MovePicker::score_qcaptures() {
// Use MVV ordering // Use MVV/LVA ordering
for (int i = 0; i < numOfMoves; i++) for (int i = 0; i < numOfMoves; i++)
{ {
Move m = moves[i].move; Move m = moves[i].move;
moves[i].score = move_promotion(m) ? QueenValueMidgame if (move_promotion(m))
: pos.midgame_value_of_piece_on(move_to(m)); moves[i].score = QueenValueMidgame;
else
moves[i].score = int(pos->midgame_value_of_piece_on(move_to(m)))
-int(pos->midgame_value_of_piece_on(move_to(m))) / 64;
} }
} }
/// find_best_index() loops across the moves and returns index of
/// the highest scored one.
int MovePicker::find_best_index() {
int bestScore = -10000000, bestIndex = -1;
for (int i = movesPicked; i < numOfMoves; i++)
if (moves[i].score > bestScore)
{
bestIndex = i;
bestScore = moves[i].score;
}
return bestIndex;
}
/// 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
/// the current move generation phase). It takes care not to return the /// the current move generation phase). It takes care not to return the
@ -300,17 +293,18 @@ int MovePicker::find_best_index() {
Move MovePicker::pick_move_from_list() { Move MovePicker::pick_move_from_list() {
int bestScore = -10000000;
int bestIndex; int bestIndex;
Move move; Move move;
switch (PhaseTable[phaseIndex]) { switch (PhaseTable[phaseIndex]) {
case PH_GOOD_CAPTURES: case PH_GOOD_CAPTURES:
assert(!pos.is_check()); assert(!pos->is_check());
assert(movesPicked >= 0); assert(movesPicked >= 0);
while (movesPicked < numOfMoves) while (movesPicked < numOfMoves)
{ {
int bestScore = -10000000; bestScore = -10000000;
bestIndex = -1; bestIndex = -1;
for (int i = movesPicked; i < numOfMoves; i++) for (int i = movesPicked; i < numOfMoves; i++)
{ {
@ -320,66 +314,87 @@ Move MovePicker::pick_move_from_list() {
assert(numOfBadCaptures < 63); assert(numOfBadCaptures < 63);
badCaptures[numOfBadCaptures++] = moves[i]; badCaptures[numOfBadCaptures++] = moves[i];
moves[i--] = moves[--numOfMoves]; moves[i--] = moves[--numOfMoves];
} }
else if (moves[i].score > bestScore) else if (moves[i].score > bestScore)
{ {
bestIndex = i; bestIndex = i;
bestScore = moves[i].score; bestScore = moves[i].score;
} }
} }
if (bestIndex != -1) // Found a good capture if (bestIndex != -1) // Found a good capture
{ {
move = moves[bestIndex].move; move = moves[bestIndex].move;
moves[bestIndex] = moves[movesPicked++]; moves[bestIndex] = moves[movesPicked++];
if ( move != ttMove if ( move != ttMove
&& move != mateKiller && move != mateKiller
&& pos.move_is_legal(move, pinned)) && pos->move_is_legal(move, pinned))
return move; return move;
} }
} }
break; break;
case PH_NONCAPTURES: case PH_NONCAPTURES:
assert(!pos.is_check()); assert(!pos->is_check());
assert(movesPicked >= 0); assert(movesPicked >= 0);
while (movesPicked < numOfMoves) while (movesPicked < numOfMoves)
{ {
bestScore = -10000000;
// If this is a PV node or we have only picked a few moves, scan // If this is a PV node or we have only picked a few moves, scan
// the entire move list for the best move. If many moves have already // the entire move list for the best move. If many moves have already
// been searched and it is not a PV node, we are probably failing low // been searched and it is not a PV node, we are probably failing low
// anyway, so we just pick the first move from the list. // anyway, so we just pick the first move from the list.
bestIndex = (movesPicked < 12 || pvNode ? find_best_index() : movesPicked); if (pvNode || movesPicked < 12)
{
bestIndex = -1;
for (int i = movesPicked; i < numOfMoves; i++)
if (moves[i].score > bestScore)
{
bestIndex = i;
bestScore = moves[i].score;
}
} else
bestIndex = movesPicked;
if (bestIndex != -1) if (bestIndex != -1)
{ {
move = moves[bestIndex].move; move = moves[bestIndex].move;
moves[bestIndex] = moves[movesPicked++]; moves[bestIndex] = moves[movesPicked++];
if ( move != ttMove if ( move != ttMove
&& move != mateKiller && move != mateKiller
&& pos.move_is_legal(move, pinned)) && pos->move_is_legal(move, pinned))
return move; return move;
}
}
break;
case PH_EVASIONS:
assert(pos.is_check());
assert(movesPicked >= 0);
while (movesPicked < numOfMoves)
{
bestIndex = find_best_index();
if (bestIndex != -1)
{
move = moves[bestIndex].move;
moves[bestIndex] = moves[movesPicked++];
return move;
} }
} }
break; break;
case PH_EVASIONS:
assert(pos->is_check());
assert(movesPicked >= 0);
while (movesPicked < numOfMoves)
{
bestScore = -10000000;
bestIndex = -1;
for (int i = movesPicked; i < numOfMoves; i++)
if(moves[i].score > bestScore)
{
bestIndex = i;
bestScore = moves[i].score;
}
if (bestIndex != -1)
{
move = moves[bestIndex].move;
moves[bestIndex] = moves[movesPicked++];
return move;
}
}
break;
case PH_BAD_CAPTURES: case PH_BAD_CAPTURES:
assert(!pos.is_check()); assert(!pos->is_check());
assert(badCapturesPicked >= 0); assert(badCapturesPicked >= 0);
// It's probably a good idea to use SEE move ordering here, instead // It's probably a good idea to use SEE move ordering here, instead
// of just picking the first move. FIXME // of just picking the first move. FIXME
@ -388,38 +403,51 @@ Move MovePicker::pick_move_from_list() {
move = badCaptures[badCapturesPicked++].move; move = badCaptures[badCapturesPicked++].move;
if ( move != ttMove if ( move != ttMove
&& move != mateKiller && move != mateKiller
&& pos.move_is_legal(move, pinned)) && pos->move_is_legal(move, pinned))
return move; return move;
} }
break; break;
case PH_QCAPTURES: case PH_QCAPTURES:
assert(!pos.is_check()); assert(!pos->is_check());
assert(movesPicked >= 0); assert(movesPicked >= 0);
while (movesPicked < numOfMoves) while (movesPicked < numOfMoves)
{ {
// FIXME makes sens to score qcaps? bestScore = -10000000;
bestIndex = (movesPicked < 4 ? find_best_index() : movesPicked); if (movesPicked < 4)
{
bestIndex = -1;
for (int i = movesPicked; i < numOfMoves; i++)
if(moves[i].score > bestScore)
{
bestIndex = i;
bestScore = moves[i].score;
}
} else
bestIndex = movesPicked;
if (bestIndex != -1) if (bestIndex != -1)
{ {
move = moves[bestIndex].move; move = moves[bestIndex].move;
moves[bestIndex] = moves[movesPicked++]; moves[bestIndex] = moves[movesPicked++];
if (move != ttMove && pos.move_is_legal(move, pinned)) // Remember to change the line below if we decide to hash the qsearch!
// Maybe also postpone the legality check until after futility pruning?
if (/* move != ttMove && */ pos->move_is_legal(move, pinned))
return move; return move;
} }
} }
break; break;
case PH_QCHECKS: case PH_QCHECKS:
assert(!pos.is_check()); assert(!pos->is_check());
assert(movesPicked >= 0); assert(movesPicked >= 0);
// Perhaps we should do something better than just picking the first // Perhaps we should do something better than just picking the first
// move here? FIXME // move here? FIXME
while (movesPicked < numOfMoves) while (movesPicked < numOfMoves)
{ {
move = moves[movesPicked++].move; move = moves[movesPicked++].move;
if (move != ttMove && pos.move_is_legal(move, pinned)) // Remember to change the line below if we decide to hash the qsearch!
if (/* move != ttMove && */ pos->move_is_legal(move, pinned))
return move; return move;
} }
break; break;
@ -430,19 +458,14 @@ Move MovePicker::pick_move_from_list() {
return MOVE_NONE; return MOVE_NONE;
} }
/// MovePicker::current_move_type() returns the type of the just
/// picked next move. It can be used in search to further differentiate
/// according to the current move type: capture, non capture, escape, etc.
MovePicker::MovegenPhase MovePicker::current_move_type() const { MovePicker::MovegenPhase MovePicker::current_move_type() const {
return PhaseTable[phaseIndex]; return PhaseTable[phaseIndex];
} }
/// MovePicker::init_phase_table() initializes the PhaseTable[], /// MovePicker::init_phase_table() initializes the PhaseTable[],
/// MainSearchPhaseIndex, EvasionPhaseIndex, QsearchWithChecksPhaseIndex /// MainSearchPhaseIndex, EvasionPhaseIndex, QsearchWithChecksPhaseIndex
/// and QsearchWithoutChecksPhaseIndex variables. It is only called once /// and QsearchWithoutChecksPhaseIndex variables. It is only called once
/// during program startup, and never again while the program is running. /// during program startup, and never again while the program is running.
void MovePicker::init_phase_table() { void MovePicker::init_phase_table() {

View file

@ -2,12 +2,12 @@
Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008 Marco Costalba Copyright (C) 2008 Marco Costalba
Stockfish is free software: you can redistribute it and/or modify Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Stockfish is distributed in the hope that it will be useful, Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@ -60,7 +60,8 @@ public:
PH_STOP PH_STOP
}; };
MovePicker(const Position& p, bool pvnode, Move ttm, Move mk, Move k1, Move k2, Depth d); MovePicker(Position &p, bool pvnode, Move ttm, Move mk, Move k1, Move k2,
Depth dpth);
Move get_next_move(); Move get_next_move();
Move get_next_move(Lock &lock); Move get_next_move(Lock &lock);
int number_of_moves() const; int number_of_moves() const;
@ -76,9 +77,8 @@ private:
void score_evasions(); void score_evasions();
void score_qcaptures(); void score_qcaptures();
Move pick_move_from_list(); Move pick_move_from_list();
int find_best_index();
const Position& pos; Position *pos;
Move ttMove, mateKiller, killer1, killer2; Move ttMove, mateKiller, killer1, killer2;
Bitboard pinned, dc; Bitboard pinned, dc;
MoveStack moves[256], badCaptures[64]; MoveStack moves[256], badCaptures[64];
@ -101,6 +101,7 @@ private:
/// a single reply to check. /// a single reply to check.
inline int MovePicker::number_of_moves() const { inline int MovePicker::number_of_moves() const {
return numOfMoves; return numOfMoves;
} }