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

Use std library to sort moves

Functional change due to the fact that now pick_best() is
stable, but should be no change in strenght.

Example code and ideas by Rein Halbersma.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
Marco Costalba 2011-07-14 12:12:49 +01:00
parent 0cfb30e5be
commit fbdabe2975
5 changed files with 36 additions and 82 deletions

View file

@ -245,7 +245,7 @@ inline Bitboard attack_span_mask(Color c, Square s) {
inline bool squares_aligned(Square s1, Square s2, Square s3) { inline bool squares_aligned(Square s1, Square s2, Square s3) {
return (BetweenBB[s1][s2] | BetweenBB[s1][s3] | BetweenBB[s2][s3]) return (BetweenBB[s1][s2] | BetweenBB[s1][s3] | BetweenBB[s2][s3])
& ((1ULL << s1) | (1ULL << s2) | (1ULL << s3)); & ( SetMaskBB[s1] | SetMaskBB[s2] | SetMaskBB[s3]);
} }

View file

@ -55,7 +55,7 @@ inline bool operator<(const MoveStack& f, const MoveStack& s) { return f.score <
// An helper insertion sort implementation, works with pointers and iterators // An helper insertion sort implementation, works with pointers and iterators
template<typename T, typename K> template<typename T, typename K>
inline void insertion_sort(K firstMove, K lastMove) inline void sort(K firstMove, K lastMove)
{ {
T value; T value;
K cur, p, d; K cur, p, d;
@ -74,61 +74,6 @@ inline void insertion_sort(K firstMove, K lastMove)
} }
} }
// Our dedicated sort in range [firstMove, lastMove), first splits
// positive scores from ramining then order seaprately the two sets.
template<typename T>
inline void sort_moves(T* firstMove, T* lastMove, T** lastPositive)
{
T tmp;
T *p, *d;
d = lastMove;
p = firstMove - 1;
d->score = -1; // right guard
// Split positives vs non-positives
do {
while ((++p)->score > 0) {}
if (p != d)
{
while (--d != p && d->score <= 0) {}
tmp = *p;
*p = *d;
*d = tmp;
}
} while (p != d);
// Sort just positive scored moves, remaining only when we get there
insertion_sort<T, T*>(firstMove, p);
*lastPositive = p;
}
// Picks up the best move in range [curMove, lastMove), one per cycle.
// It is faster then sorting all the moves in advance when moves are few,
// as normally are the possible captures. Note that is not a stable alghoritm.
template<typename T>
inline T pick_best(T* curMove, T* lastMove)
{
T bestMove, tmp;
bestMove = *curMove;
while (++curMove != lastMove)
{
if (bestMove < *curMove)
{
tmp = *curMove;
*curMove = bestMove;
bestMove = tmp;
}
}
return bestMove;
}
inline Square move_from(Move m) { inline Square move_from(Move m) {
return Square((m >> 6) & 0x3F); return Square((m >> 6) & 0x3F);
} }

View file

@ -18,6 +18,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <algorithm>
#include <cassert> #include <cassert>
#include "movegen.h" #include "movegen.h"
@ -49,6 +50,19 @@ namespace {
const uint8_t QsearchWithoutChecksTable[] = { PH_TT_MOVE, PH_QCAPTURES, PH_STOP }; const uint8_t QsearchWithoutChecksTable[] = { PH_TT_MOVE, PH_QCAPTURES, PH_STOP };
const uint8_t QsearchRecapturesTable[] = { PH_TT_MOVE, PH_QRECAPTURES, PH_STOP }; const uint8_t QsearchRecapturesTable[] = { PH_TT_MOVE, PH_QRECAPTURES, PH_STOP };
const uint8_t ProbCutTable[] = { PH_TT_MOVE, PH_GOOD_PROBCUT, PH_STOP }; const uint8_t ProbCutTable[] = { PH_TT_MOVE, PH_GOOD_PROBCUT, PH_STOP };
// Unary predicate used by std::partition to split positive scores from ramining
// ones so to sort separately the two sets, and with the second sort delayed.
inline bool has_positive_score(const MoveStack& move) { return move.score > 0; }
// Picks and pushes to the front the best move in range [firstMove, lastMove),
// it is faster then sorting all the moves in advance when moves are few, as
// normally are the possible captures.
inline MoveStack* pick_best(MoveStack* firstMove, MoveStack* lastMove)
{
std::swap(*firstMove, *std::max_element(firstMove, lastMove));
return firstMove;
}
} }
/// Constructors for the MovePicker class. As arguments we pass information /// Constructors for the MovePicker class. As arguments we pass information
@ -164,14 +178,15 @@ void MovePicker::go_next_phase() {
case PH_NONCAPTURES_1: case PH_NONCAPTURES_1:
lastNonCapture = lastMove = generate<MV_NON_CAPTURE>(pos, moves); lastNonCapture = lastMove = generate<MV_NON_CAPTURE>(pos, moves);
score_noncaptures(); score_noncaptures();
sort_moves(moves, lastNonCapture, &lastMove); lastMove = std::partition(curMove, lastMove, has_positive_score);
sort<MoveStack>(curMove, lastMove);
return; return;
case PH_NONCAPTURES_2: case PH_NONCAPTURES_2:
curMove = lastMove; curMove = lastMove;
lastMove = lastNonCapture; lastMove = lastNonCapture;
if (depth >= 3 * ONE_PLY) if (depth >= 3 * ONE_PLY)
insertion_sort<MoveStack>(curMove, lastMove); sort<MoveStack>(curMove, lastMove);
return; return;
case PH_BAD_CAPTURES: case PH_BAD_CAPTURES:
@ -306,7 +321,7 @@ Move MovePicker::get_next_move() {
break; break;
case PH_GOOD_CAPTURES: case PH_GOOD_CAPTURES:
move = pick_best(curMove++, lastMove).move; move = pick_best(curMove++, lastMove)->move;
if (move != ttMove) if (move != ttMove)
{ {
assert(captureThreshold <= 0); // Otherwise we must use see instead of see_sign assert(captureThreshold <= 0); // Otherwise we must use see instead of see_sign
@ -324,7 +339,7 @@ Move MovePicker::get_next_move() {
break; break;
case PH_GOOD_PROBCUT: case PH_GOOD_PROBCUT:
move = pick_best(curMove++, lastMove).move; move = pick_best(curMove++, lastMove)->move;
if ( move != ttMove if ( move != ttMove
&& pos.see(move) > captureThreshold) && pos.see(move) > captureThreshold)
return move; return move;
@ -349,12 +364,12 @@ Move MovePicker::get_next_move() {
break; break;
case PH_BAD_CAPTURES: case PH_BAD_CAPTURES:
move = pick_best(curMove++, lastMove).move; move = pick_best(curMove++, lastMove)->move;
return move; return move;
case PH_EVASIONS: case PH_EVASIONS:
case PH_QCAPTURES: case PH_QCAPTURES:
move = pick_best(curMove++, lastMove).move; move = pick_best(curMove++, lastMove)->move;
if (move != ttMove) if (move != ttMove)
return move; return move;
break; break;

View file

@ -513,14 +513,14 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
assert(piece_color(piece_on(from)) == us); assert(piece_color(piece_on(from)) == us);
assert(piece_on(king_square(us)) == make_piece(us, KING)); assert(piece_on(king_square(us)) == make_piece(us, KING));
// En passant captures are a tricky special case. Because they are // En passant captures are a tricky special case. Because they are rather
// rather uncommon, we do it simply by testing whether the king is attacked // uncommon, we do it simply by testing whether the king is attacked after
// after the move is made // the move is made.
if (move_is_ep(m)) if (move_is_ep(m))
{ {
Color them = opposite_color(us); Color them = opposite_color(us);
Square to = move_to(m); Square to = move_to(m);
Square capsq = make_square(square_file(to), square_rank(from)); Square capsq = to + Square(us == WHITE ? -8 : 8);
Square ksq = king_square(us); Square ksq = king_square(us);
Bitboard b = occupied_squares(); Bitboard b = occupied_squares();

View file

@ -79,16 +79,9 @@ namespace {
Move pv[PLY_MAX_PLUS_2]; Move pv[PLY_MAX_PLUS_2];
}; };
// RootMoveList struct is just a vector of RootMove objects, // RootMoveList struct is mainly a std::vector of RootMove objects
// with an handful of methods above the standard ones.
struct RootMoveList : public std::vector<RootMove> { struct RootMoveList : public std::vector<RootMove> {
typedef std::vector<RootMove> Base;
void init(Position& pos, Move searchMoves[]); void init(Position& pos, Move searchMoves[]);
void sort() { insertion_sort<RootMove, Base::iterator>(begin(), end()); }
void sort_first(int n) { insertion_sort<RootMove, Base::iterator>(begin(), begin() + n); }
int bestMoveChanges; int bestMoveChanges;
}; };
@ -1219,7 +1212,7 @@ split_point_start: // At split points actual search starts from here
// because all the values but the first are usually set to // because all the values but the first are usually set to
// -VALUE_INFINITE and we want to keep the same order for all // -VALUE_INFINITE and we want to keep the same order for all
// the moves but the new PV that goes to head. // the moves but the new PV that goes to head.
Rml.sort_first(moveCount); sort<RootMove>(Rml.begin(), Rml.begin() + moveCount);
// Update alpha. In multi-pv we don't use aspiration window, so set // Update alpha. In multi-pv we don't use aspiration window, so set
// alpha equal to minimum score among the PV lines searched so far. // alpha equal to minimum score among the PV lines searched so far.
@ -1555,7 +1548,7 @@ split_point_start: // At split points actual search starts from here
bool connected_moves(const Position& pos, Move m1, Move m2) { bool connected_moves(const Position& pos, Move m1, Move m2) {
Square f1, t1, f2, t2; Square f1, t1, f2, t2;
Piece p; Piece p1, p2;
assert(m1 && move_is_ok(m1)); assert(m1 && move_is_ok(m1));
assert(m2 && move_is_ok(m2)); assert(m2 && move_is_ok(m2));
@ -1573,17 +1566,18 @@ split_point_start: // At split points actual search starts from here
return true; return true;
// Case 3: Moving through the vacated square // Case 3: Moving through the vacated square
if ( piece_is_slider(pos.piece_on(f2)) p2 = pos.piece_on(f2);
if ( piece_is_slider(p2)
&& bit_is_set(squares_between(f2, t2), f1)) && bit_is_set(squares_between(f2, t2), f1))
return true; return true;
// Case 4: The destination square for m2 is defended by the moving piece in m1 // Case 4: The destination square for m2 is defended by the moving piece in m1
p = pos.piece_on(t1); p1 = pos.piece_on(t1);
if (bit_is_set(pos.attacks_from(p, t1), t2)) if (bit_is_set(pos.attacks_from(p1, t1), t2))
return true; return true;
// Case 5: Discovered check, checking piece is the piece moved in m1 // Case 5: Discovered check, checking piece is the piece moved in m1
if ( piece_is_slider(p) if ( piece_is_slider(p1)
&& bit_is_set(squares_between(t1, pos.king_square(pos.side_to_move())), f2) && bit_is_set(squares_between(t1, pos.king_square(pos.side_to_move())), f2)
&& !bit_is_set(squares_between(t1, pos.king_square(pos.side_to_move())), t2)) && !bit_is_set(squares_between(t1, pos.king_square(pos.side_to_move())), t2))
{ {
@ -2093,7 +2087,7 @@ split_point_start: // At split points actual search starts from here
break; break;
} }
Rml.sort(); sort<RootMove>(Rml.begin(), Rml.end());
} }
} // namespace } // namespace