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:
parent
0cfb30e5be
commit
fbdabe2975
5 changed files with 36 additions and 82 deletions
|
@ -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]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
57
src/move.h
57
src/move.h
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue