Skip to content

Commit

Permalink
Counter Move History (#3)
Browse files Browse the repository at this point in the history
Added counter move history which resulted in a boost of +40 +-8 Elo in self play at very fast TC.

The regular History Heuristic as well as SFs Capture History were both tried without any real success.
Non of these features were tuned and they were done in a rush, so there should be plenty of room for improvement.
  • Loading branch information
rosenthj authored Feb 19, 2019
1 parent f2a9593 commit dd7a442
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 7 deletions.
6 changes: 4 additions & 2 deletions src/general/feature_indexes.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,10 @@ const int kPWIPawnRankDestination = kPWIForcingChanges + 4;
const int kPWIPassedRankDestination = kPWIPawnRankDestination + 6;
const int kPWIPawnAttack = kPWIPassedRankDestination + 6;
const int kPWIPieceUnderAttack = kPWIPawnAttack + 1;
const int kNumMoveProbabilityFeatures = kPWIPieceUnderAttack + 2;
const int kPWICMH = kPWIPieceUnderAttack + 2;
const int kNumMoveProbabilityFeatures = kPWICMH+ 1;

const std::array<FeatureInfo, 19> kFeatureInfos = {{
const std::array<FeatureInfo, 20> kFeatureInfos = {{
FeatureInfo("Hash Move", kPWIHashMove),
FeatureInfo("Killer Move", kPWIKiller),
FeatureInfo("Counter Move", kPWICounterMove),
Expand All @@ -182,6 +183,7 @@ const std::array<FeatureInfo, 19> kFeatureInfos = {{
FeatureInfo("Rank of passed pawn destination", kPWIPassedRankDestination),
FeatureInfo("Pawn move attacks a piece", kPWIPawnAttack),
FeatureInfo("Piece under attack", kPWIPieceUnderAttack),
FeatureInfo("CMH", kPWICMH),
FeatureInfo("Num Features Placeholder", kNumMoveProbabilityFeatures)
}};

Expand Down
10 changes: 6 additions & 4 deletions src/general/hardcoded_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ const std::array<int, (174*4)> eval_weights_gmm = {
// ------------------------------------------------------------------------------------------------

// Search parameters used for move ordering when not in check
const std::array<int, 114> search_params = {
const std::array<int, 115> search_params = {
2000, // Hash Move
142, // Killer Move
112, // Killer Move
Expand Down Expand Up @@ -680,11 +680,12 @@ const std::array<int, 114> search_params = {
0, // Rank of passed pawn destination
128, // Pawn move attacks a piece
131, // Piece under attack
206 // Piece under attack
206, // Piece under attack
1
};

// Search parameters used for move ordering when in check
const std::array<int, 114> search_params_in_check = {
const std::array<int, 115> search_params_in_check = {
2000, // Hash Move
123, // Killer Move
116, // Killer Move
Expand Down Expand Up @@ -798,7 +799,8 @@ const std::array<int, 114> search_params_in_check = {
0, // Rank of passed pawn destination
-15, // Pawn move attacks a piece
75, // Piece under attack
11 // Piece under attack
11, // Piece under attack
1
};

}
Expand Down
2 changes: 1 addition & 1 deletion src/general/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
namespace settings {

const std::string engine_name = "Winter";
const std::string engine_version = "0.4.2";
const std::string engine_version = "0.5";
const std::string engine_author = "Jonathan Rosenthal";

const int kNumClusters = 4;
Expand Down
55 changes: 55 additions & 0 deletions src/search.cc
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,19 @@ template<> inline void AddFeature<int, true>(int &s, const int index) {
s += search_weights_in_check[index];
}

template<typename T, bool in_check> inline
void AddFeature(T &s, const int index, int val) {
s[index] = val;
}

template<> inline void AddFeature<int, false>(int &s, const int index, int val) {
s += search_weights[index] * val;
}

template<> inline void AddFeature<int, true>(int &s, const int index, int val) {
s += search_weights_in_check[index] * val;
}

inline Move get_last_move(const Board &board) {
if (board.get_num_made_moves() > 0) {
return board.get_last_move();
Expand Down Expand Up @@ -340,6 +353,13 @@ T GetMoveWeight(const Move move, search::Thread &t, const MoveOrderInfo &info) {
if (move == t.counter_moves[t.board.get_turn()][last_moved_piece][last_destination]) {
AddFeature<T, in_check>(move_weight, kPWICounterMove);
}
if (GetMoveType(move) < kCapture) {
const PieceType moving_piece = GetPieceType(t.board.get_piece(GetMoveSource(move)));
const Square destination = GetMoveDestination(move);
const int score = t.get_cmh_score(last_moved_piece, last_destination,
moving_piece, destination);
AddFeature<T, in_check>(move_weight, kPWICMH, score / 100);
}
}
const PieceType moving_piece = GetPieceType(t.board.get_piece(GetMoveSource(move)));
PieceType target = GetPieceType(t.board.get_piece(GetMoveDestination(move)));
Expand Down Expand Up @@ -725,6 +745,27 @@ inline void bookkeeping_log(int NodeType, const Board &board, Move tt_entry,

bool move_is_singular(Thread &t, const Depth depth, const std::vector<Move> &moves, const table::Entry &entry);

void update_counter_move_history(Thread &t, const std::vector<Move> &quiets, const Depth depth) {
if (t.board.get_num_made_moves() == 0 || t.board.get_last_move() == kNullMove) {
return;
}
const Move move = t.board.get_last_move();
Square opp_des = GetMoveDestination(move);
PieceType opp_piecetype = GetPieceType(t.board.get_piece(opp_des));
// TODO deal with promotion situations
int32_t score = std::min(depth * depth, 200);

for (int i = 0; i < quiets.size() - 1; ++i) {
Square des = GetMoveDestination(quiets[i]);
PieceType piecetype = GetPieceType(t.board.get_piece(GetMoveSource(quiets[i])));
t.update_cmh_scores(opp_piecetype, opp_des, piecetype, des, -score);
}
int i = quiets.size() - 1;
Square des = GetMoveDestination(quiets[i]);
PieceType piecetype = GetPieceType(t.board.get_piece(GetMoveSource(quiets[i])));
t.update_cmh_scores(opp_piecetype, opp_des, piecetype, des, score);
}

template<int NodeType, int Mode>
Score AlphaBeta(Thread &t, Score alpha, Score beta, Depth depth, int expected_node = 1) {
assert(beta > alpha);
Expand Down Expand Up @@ -756,6 +797,9 @@ Score AlphaBeta(Thread &t, Score alpha, Score beta, Depth depth, int expected_no
bool valid_entry = table::ValidateHash(entry,t.board.get_hash());
if (NodeType != kPV && valid_entry
&& sufficient_bounds(t.board, entry, alpha, beta, depth) ) {
// if (entry.get_best_move() != kNullMove && GetMoveType(entry.get_best_move()) < kCapture) {
// update_counter_move_history(t, {{entry.get_best_move()}}, depth);
// }
return entry.get_score(t.board);
}

Expand Down Expand Up @@ -850,6 +894,7 @@ Score AlphaBeta(Thread &t, Score alpha, Score beta, Depth depth, int expected_no
//Ie no checks from special moves or discovered checks.
Vec<BitBoard, 6> checking_squares = t.board.GetDirectCheckingSquares();

std::vector<Move> quiets;
//Move loop
for (unsigned int i = 0; i < moves.size(); i++) {
if (i == 1 && !moves_sorted) {
Expand Down Expand Up @@ -899,6 +944,10 @@ Score AlphaBeta(Thread &t, Score alpha, Score beta, Depth depth, int expected_no
}
}

if (GetMoveType(move) < kCapture) {
quiets.emplace_back(move);
}

//Make moves, search and unmake
t.board.Make(move);
Score score;
Expand All @@ -925,6 +974,9 @@ Score AlphaBeta(Thread &t, Score alpha, Score beta, Depth depth, int expected_no

//Check if search failed high
if (score >= beta) {
if (GetMoveType(move) < kCapture) {
update_counter_move_history(t, quiets, depth);
}
//Save TT entry
table::SaveEntry(t.board, move, score, depth);

Expand All @@ -949,6 +1001,9 @@ Score AlphaBeta(Thread &t, Score alpha, Score beta, Depth depth, int expected_no

//In PV nodes we might be improving Alpha without breaking Beta
if (score > alpha) {
if (GetMoveType(move) < kCapture) {
update_counter_move_history(t, quiets, depth);
}
//Update score and expected best move
alpha = score;
best_local_move = move;
Expand Down
25 changes: 25 additions & 0 deletions src/search_thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ struct Thread {
}
}
}

for (PieceType pt = kPawn; pt <= kKing; pt++) {
for (Square sq = 0; sq < 64; sq++) {
for (PieceType pt_i = kPawn; pt_i <= kKing; pt_i++) {
for (Square sq_i = 0; sq_i < 64; sq_i++) {
counter_move_history[pt][sq][pt_i][sq_i] = 0;
}
}
}
}

}

void search();
Expand All @@ -77,6 +88,19 @@ struct Thread {
static_scores[height] = score;
}

int32_t get_cmh_score(const PieceType opp_piecetype, const Square opp_des,
const PieceType piecetype, const Square des) const {
return counter_move_history[opp_piecetype][opp_des][piecetype][des];
}

void update_cmh_scores(const PieceType opp_piecetype, const Square opp_des,
const PieceType piecetype, const Square des, const int32_t score) {

counter_move_history[opp_piecetype][opp_des][piecetype][des] += 32 * score
- counter_move_history[opp_piecetype][opp_des][piecetype][des]
* std::abs(score) / 512;
}

//Multithreading objects
int id;

Expand All @@ -86,6 +110,7 @@ struct Thread {
Depth current_depth;
Array2d<Move, 1024, 2> killers;
Array3d<Move, 2, 6, 64> counter_moves;
Array2d<Array2d<int32_t, 6, 64>, 6, 64> counter_move_history;
Depth root_height;
std::array<Score, settings::kMaxDepth> static_scores;
std::atomic<size_t> nodes;
Expand Down

0 comments on commit dd7a442

Please sign in to comment.