mirror of
https://github.com/sockspls/badfish
synced 2025-05-02 17:49:35 +00:00
Implemented the logic to update Eval List and Dirty Pieces.
This commit is contained in:
parent
b330602cdc
commit
48bfe86d27
9 changed files with 313 additions and 30 deletions
|
@ -233,12 +233,14 @@ void prefetch_evalhash(const Key key) {
|
||||||
void load_eval() {
|
void load_eval() {
|
||||||
NNUE::Initialize();
|
NNUE::Initialize();
|
||||||
|
|
||||||
#if defined(EVAL_LEARN)
|
|
||||||
if (!Options["SkipLoadingEval"])
|
if (!Options["SkipLoadingEval"])
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
const std::string dir_name = Options["EvalDir"];
|
const std::string dir_name = Options["EvalDir"];
|
||||||
const std::string file_name = Path::Combine(dir_name, NNUE::kFileName);
|
const std::string file_name = Path::Combine(dir_name, NNUE::kFileName);
|
||||||
|
//{
|
||||||
|
// std::ofstream stream(file_name, std::ios::binary);
|
||||||
|
// NNUE::WriteParameters(stream);
|
||||||
|
//}
|
||||||
std::ifstream stream(file_name, std::ios::binary);
|
std::ifstream stream(file_name, std::ios::binary);
|
||||||
const bool result = NNUE::ReadParameters(stream);
|
const bool result = NNUE::ReadParameters(stream);
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "material.h"
|
#include "material.h"
|
||||||
#include "pawns.h"
|
#include "pawns.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "eval/nnue/evaluate_nnue.h"
|
||||||
|
|
||||||
namespace Trace {
|
namespace Trace {
|
||||||
|
|
||||||
|
@ -864,7 +865,8 @@ namespace {
|
||||||
/// evaluation of the position from the point of view of the side to move.
|
/// evaluation of the position from the point of view of the side to move.
|
||||||
|
|
||||||
Value Eval::evaluate(const Position& pos) {
|
Value Eval::evaluate(const Position& pos) {
|
||||||
return Evaluation<NO_TRACE>(pos).value();
|
//return Evaluation<NO_TRACE>(pos).value();
|
||||||
|
return Eval::NNUE::evaluate(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -907,3 +909,72 @@ std::string Eval::trace(const Position& pos) {
|
||||||
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Eval {
|
||||||
|
ExtBonaPiece kpp_board_index[PIECE_NB] = {
|
||||||
|
{ BONA_PIECE_ZERO, BONA_PIECE_ZERO },
|
||||||
|
{ f_pawn, e_pawn },
|
||||||
|
{ f_knight, e_knight },
|
||||||
|
{ f_bishop, e_bishop },
|
||||||
|
{ f_rook, e_rook },
|
||||||
|
{ f_queen, e_queen },
|
||||||
|
{ f_king, e_king },
|
||||||
|
{ BONA_PIECE_ZERO, BONA_PIECE_ZERO },
|
||||||
|
|
||||||
|
// 後手から見た場合。fとeが入れ替わる。
|
||||||
|
{ BONA_PIECE_ZERO, BONA_PIECE_ZERO },
|
||||||
|
{ e_pawn, f_pawn },
|
||||||
|
{ e_knight, f_knight },
|
||||||
|
{ e_bishop, f_bishop },
|
||||||
|
{ e_rook, f_rook },
|
||||||
|
{ e_queen, f_queen },
|
||||||
|
{ e_king, f_king },
|
||||||
|
{ BONA_PIECE_ZERO, BONA_PIECE_ZERO }, // 金の成りはない
|
||||||
|
};
|
||||||
|
|
||||||
|
// 内部で保持しているpieceListFw[]が正しいBonaPieceであるかを検査する。
|
||||||
|
// 注 : デバッグ用。遅い。
|
||||||
|
bool EvalList::is_valid(const Position& pos)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < length(); ++i)
|
||||||
|
{
|
||||||
|
BonaPiece fw = pieceListFw[i];
|
||||||
|
// このfwが本当に存在するかをPositionクラスのほうに調べに行く。
|
||||||
|
|
||||||
|
if (fw == Eval::BONA_PIECE_ZERO) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 範囲外
|
||||||
|
if (!(0 <= fw && fw < fe_end))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 盤上の駒なのでこの駒が本当に存在するか調べにいく。
|
||||||
|
for (Piece pc = NO_PIECE; pc < PIECE_NB; ++pc)
|
||||||
|
{
|
||||||
|
auto pt = type_of(pc);
|
||||||
|
if (pt == NO_PIECE || pt == 7) // 存在しない駒
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// 駒pcのBonaPieceの開始番号
|
||||||
|
auto s = BonaPiece(kpp_board_index[pc].fw);
|
||||||
|
if (s <= fw && fw < s + SQUARE_NB)
|
||||||
|
{
|
||||||
|
// 見つかったのでこの駒がsqの地点にあるかを調べる。
|
||||||
|
Square sq = (Square)(fw - s);
|
||||||
|
Piece pc2 = pos.piece_on(sq);
|
||||||
|
|
||||||
|
if (pc2 != pc)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
goto Found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 何故か存在しない駒であった..
|
||||||
|
return false;
|
||||||
|
Found:;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,15 @@ std::string trace(const Position& pos);
|
||||||
|
|
||||||
Value evaluate(const Position& pos);
|
Value evaluate(const Position& pos);
|
||||||
|
|
||||||
|
// 評価関数ファイルを読み込む。
|
||||||
|
// これは、"is_ready"コマンドの応答時に1度だけ呼び出される。2度呼び出すことは想定していない。
|
||||||
|
// (ただし、EvalDir(評価関数フォルダ)が変更になったあと、isreadyが再度送られてきたら読みなおす。)
|
||||||
|
void load_eval();
|
||||||
|
|
||||||
|
static uint64_t calc_check_sum() { return 0; }
|
||||||
|
|
||||||
|
static void print_softname(uint64_t check_sum) {}
|
||||||
|
|
||||||
// --- 評価関数で使う定数 KPP(玉と任意2駒)のPに相当するenum
|
// --- 評価関数で使う定数 KPP(玉と任意2駒)のPに相当するenum
|
||||||
|
|
||||||
// (評価関数の実験のときには、BonaPieceは自由に定義したいのでここでは定義しない。)
|
// (評価関数の実験のときには、BonaPieceは自由に定義したいのでここでは定義しない。)
|
||||||
|
@ -145,22 +154,10 @@ struct EvalList
|
||||||
v = PIECE_NUMBER_NB;
|
v = PIECE_NUMBER_NB;
|
||||||
}
|
}
|
||||||
|
|
||||||
// list長が可変のときは、add()/remove()をサポートする。
|
// 内部で保持しているpieceListFw[]が正しいBonaPieceであるかを検査する。
|
||||||
// DirtyPieceのほうから呼び出される。
|
|
||||||
|
|
||||||
// listにadd()する。
|
|
||||||
void add(BonaPiece fb);
|
|
||||||
|
|
||||||
// listからremoveする。
|
|
||||||
void remove(BonaPiece fb);
|
|
||||||
|
|
||||||
// 内部で保持しているpieceListFb[]が正しいBonaPieceであるかを検査する。
|
|
||||||
// 注 : デバッグ用。遅い。
|
// 注 : デバッグ用。遅い。
|
||||||
bool is_valid(const Position& pos);
|
bool is_valid(const Position& pos);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// 盤上sqにあるpiece_noの駒のBonaPieceがfb,fwであることを設定する。
|
// 盤上sqにあるpiece_noの駒のBonaPieceがfb,fwであることを設定する。
|
||||||
inline void set_piece_on_board(PieceNumber piece_no, BonaPiece fw, BonaPiece fb, Square sq)
|
inline void set_piece_on_board(PieceNumber piece_no, BonaPiece fw, BonaPiece fb, Square sq)
|
||||||
{
|
{
|
||||||
|
@ -173,7 +170,7 @@ protected:
|
||||||
// 駒リスト。駒番号(PieceNumber)いくつの駒がどこにあるのか(BonaPiece)を示す。FV38などで用いる。
|
// 駒リスト。駒番号(PieceNumber)いくつの駒がどこにあるのか(BonaPiece)を示す。FV38などで用いる。
|
||||||
|
|
||||||
// 駒リストの長さ
|
// 駒リストの長さ
|
||||||
// 38固定
|
// 38固定
|
||||||
public:
|
public:
|
||||||
int length() const { return PIECE_NUMBER_KING; }
|
int length() const { return PIECE_NUMBER_KING; }
|
||||||
|
|
||||||
|
@ -181,15 +178,15 @@ public:
|
||||||
// また、KPPT型評価関数などは、39,40番目の要素がゼロであることを前提とした
|
// また、KPPT型評価関数などは、39,40番目の要素がゼロであることを前提とした
|
||||||
// アクセスをしている箇所があるので注意すること。
|
// アクセスをしている箇所があるので注意すること。
|
||||||
static const int MAX_LENGTH = 40;
|
static const int MAX_LENGTH = 40;
|
||||||
|
|
||||||
|
// 盤上の駒に対して、その駒番号(PieceNumber)を保持している配列
|
||||||
|
// 玉がSQ_NBに移動しているとき用に+1まで保持しておくが、
|
||||||
|
// SQ_NBの玉を移動させないので、この値を使うことはないはず。
|
||||||
|
PieceNumber piece_no_list_board[SQUARE_NB_PLUS1];
|
||||||
private:
|
private:
|
||||||
|
|
||||||
BonaPiece pieceListFw[MAX_LENGTH];
|
BonaPiece pieceListFw[MAX_LENGTH];
|
||||||
BonaPiece pieceListFb[MAX_LENGTH];
|
BonaPiece pieceListFb[MAX_LENGTH];
|
||||||
|
|
||||||
// 盤上の駒に対して、その駒番号(PieceNumber)を保持している配列
|
|
||||||
// 玉がSQ_NBに移動しているとき用に+1まで保持しておくが、
|
|
||||||
// SQ_NBの玉を移動させないので、この値を使うことはないはず。
|
|
||||||
PieceNumber piece_no_list_board[SQUARE_NB_PLUS1];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 評価値の差分計算の管理用
|
// 評価値の差分計算の管理用
|
||||||
|
|
131
src/position.cpp
131
src/position.cpp
|
@ -243,6 +243,20 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
|
||||||
std::fill_n(&pieceList[0][0], sizeof(pieceList) / sizeof(Square), SQ_NONE);
|
std::fill_n(&pieceList[0][0], sizeof(pieceList) / sizeof(Square), SQ_NONE);
|
||||||
st = si;
|
st = si;
|
||||||
|
|
||||||
|
// evalListのclear。上でmemsetでゼロクリアしたときにクリアされているが…。
|
||||||
|
evalList.clear();
|
||||||
|
|
||||||
|
// PieceListを更新する上で、どの駒がどこにあるかを設定しなければならないが、
|
||||||
|
// それぞれの駒をどこまで使ったかのカウンター
|
||||||
|
PieceNumber piece_no_count[KING] = {
|
||||||
|
PIECE_NUMBER_ZERO,
|
||||||
|
PIECE_NUMBER_PAWN,
|
||||||
|
PIECE_NUMBER_KNIGHT,
|
||||||
|
PIECE_NUMBER_BISHOP,
|
||||||
|
PIECE_NUMBER_ROOK,
|
||||||
|
PIECE_NUMBER_QUEEN
|
||||||
|
};
|
||||||
|
|
||||||
ss >> std::noskipws;
|
ss >> std::noskipws;
|
||||||
|
|
||||||
// 1. Piece placement
|
// 1. Piece placement
|
||||||
|
@ -256,7 +270,15 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
|
||||||
|
|
||||||
else if ((idx = PieceToChar.find(token)) != string::npos)
|
else if ((idx = PieceToChar.find(token)) != string::npos)
|
||||||
{
|
{
|
||||||
put_piece(Piece(idx), sq);
|
auto pc = Piece(idx);
|
||||||
|
put_piece(pc, sq);
|
||||||
|
|
||||||
|
PieceNumber piece_no =
|
||||||
|
(idx == W_KING) ? PIECE_NUMBER_WKING : // 先手玉
|
||||||
|
(idx == B_KING) ? PIECE_NUMBER_BKING : // 後手玉
|
||||||
|
piece_no_count[type_of(Piece(idx))]++; // それ以外
|
||||||
|
evalList.put_piece(piece_no, sq, pc); // sqの升にpcの駒を配置する
|
||||||
|
|
||||||
++sq;
|
++sq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,6 +341,7 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th
|
||||||
set_state(st);
|
set_state(st);
|
||||||
|
|
||||||
assert(pos_is_ok());
|
assert(pos_is_ok());
|
||||||
|
assert(evalList.is_valid(*this));
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -739,6 +762,9 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
++st->rule50;
|
++st->rule50;
|
||||||
++st->pliesFromNull;
|
++st->pliesFromNull;
|
||||||
|
|
||||||
|
st->accumulator.computed_accumulation = false;
|
||||||
|
st->accumulator.computed_score = false;
|
||||||
|
|
||||||
Color us = sideToMove;
|
Color us = sideToMove;
|
||||||
Color them = ~us;
|
Color them = ~us;
|
||||||
Square from = from_sq(m);
|
Square from = from_sq(m);
|
||||||
|
@ -750,6 +776,9 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
assert(captured == NO_PIECE || color_of(captured) == (type_of(m) != CASTLING ? them : us));
|
assert(captured == NO_PIECE || color_of(captured) == (type_of(m) != CASTLING ? them : us));
|
||||||
assert(type_of(captured) != KING);
|
assert(type_of(captured) != KING);
|
||||||
|
|
||||||
|
auto& dp = st->dirtyPiece;
|
||||||
|
dp.dirty_num = 1;
|
||||||
|
|
||||||
if (type_of(m) == CASTLING)
|
if (type_of(m) == CASTLING)
|
||||||
{
|
{
|
||||||
assert(pc == make_piece(us, KING));
|
assert(pc == make_piece(us, KING));
|
||||||
|
@ -766,6 +795,8 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
{
|
{
|
||||||
Square capsq = to;
|
Square capsq = to;
|
||||||
|
|
||||||
|
PieceNumber piece_no1;
|
||||||
|
|
||||||
// If the captured piece is a pawn, update pawn hash key, otherwise
|
// If the captured piece is a pawn, update pawn hash key, otherwise
|
||||||
// update non-pawn material.
|
// update non-pawn material.
|
||||||
if (type_of(captured) == PAWN)
|
if (type_of(captured) == PAWN)
|
||||||
|
@ -780,14 +811,22 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
assert(piece_on(to) == NO_PIECE);
|
assert(piece_on(to) == NO_PIECE);
|
||||||
assert(piece_on(capsq) == make_piece(them, PAWN));
|
assert(piece_on(capsq) == make_piece(them, PAWN));
|
||||||
|
|
||||||
|
piece_no1 = piece_no_of(capsq);
|
||||||
|
|
||||||
board[capsq] = NO_PIECE; // Not done by remove_piece()
|
board[capsq] = NO_PIECE; // Not done by remove_piece()
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
piece_no1 = piece_no_of(capsq);
|
||||||
|
}
|
||||||
|
|
||||||
st->pawnKey ^= Zobrist::psq[captured][capsq];
|
st->pawnKey ^= Zobrist::psq[captured][capsq];
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
st->nonPawnMaterial[them] -= PieceValue[MG][captured];
|
st->nonPawnMaterial[them] -= PieceValue[MG][captured];
|
||||||
|
|
||||||
|
piece_no1 = piece_no_of(capsq);
|
||||||
|
}
|
||||||
|
|
||||||
// Update board and piece lists
|
// Update board and piece lists
|
||||||
remove_piece(captured, capsq);
|
remove_piece(captured, capsq);
|
||||||
|
|
||||||
|
@ -798,6 +837,19 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
|
|
||||||
// Reset rule 50 counter
|
// Reset rule 50 counter
|
||||||
st->rule50 = 0;
|
st->rule50 = 0;
|
||||||
|
|
||||||
|
dp.dirty_num = 2; // 動いた駒は2個
|
||||||
|
|
||||||
|
dp.pieceNo[1] = piece_no1;
|
||||||
|
dp.changed_piece[1].old_piece = evalList.bona_piece(piece_no1);
|
||||||
|
// Do not use Eval::EvalList::put_piece() because the piece is removed
|
||||||
|
// from the game, and the corresponding elements of the piece lists
|
||||||
|
// needs to be Eval::BONA_PIECE_ZERO.
|
||||||
|
evalList.set_piece_on_board(piece_no1, Eval::BONA_PIECE_ZERO, Eval::BONA_PIECE_ZERO, capsq);
|
||||||
|
// Set PIECE_NUMBER_NB to piece_no_of_board[capsq] directly because it
|
||||||
|
// will not be overritten to pc if the move type is enpassant.
|
||||||
|
evalList.piece_no_list_board[capsq] = PIECE_NUMBER_NB;
|
||||||
|
dp.changed_piece[1].new_piece = evalList.bona_piece(piece_no1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update hash key
|
// Update hash key
|
||||||
|
@ -819,8 +871,16 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the piece. The tricky Chess960 castling is handled earlier
|
// Move the piece. The tricky Chess960 castling is handled earlier
|
||||||
if (type_of(m) != CASTLING)
|
if (type_of(m) != CASTLING) {
|
||||||
move_piece(pc, from, to);
|
PieceNumber piece_no0 = piece_no_of(from);
|
||||||
|
|
||||||
|
move_piece(pc, from, to);
|
||||||
|
|
||||||
|
dp.pieceNo[0] = piece_no0;
|
||||||
|
dp.changed_piece[0].old_piece = evalList.bona_piece(piece_no0);
|
||||||
|
evalList.put_piece(piece_no0, to, pc);
|
||||||
|
dp.changed_piece[0].new_piece = evalList.bona_piece(piece_no0);
|
||||||
|
}
|
||||||
|
|
||||||
// If the moving piece is a pawn do some special extra work
|
// If the moving piece is a pawn do some special extra work
|
||||||
if (type_of(pc) == PAWN)
|
if (type_of(pc) == PAWN)
|
||||||
|
@ -843,6 +903,12 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
remove_piece(pc, to);
|
remove_piece(pc, to);
|
||||||
put_piece(promotion, to);
|
put_piece(promotion, to);
|
||||||
|
|
||||||
|
PieceNumber piece_no0 = piece_no_of(to);
|
||||||
|
dp.pieceNo[0] = piece_no0;
|
||||||
|
dp.changed_piece[0].old_piece = evalList.bona_piece(piece_no0);
|
||||||
|
evalList.put_piece(piece_no0, to, promotion);
|
||||||
|
dp.changed_piece[0].new_piece = evalList.bona_piece(piece_no0);
|
||||||
|
|
||||||
// Update hash keys
|
// Update hash keys
|
||||||
k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[promotion][to];
|
k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[promotion][to];
|
||||||
st->pawnKey ^= Zobrist::psq[pc][to];
|
st->pawnKey ^= Zobrist::psq[pc][to];
|
||||||
|
@ -894,6 +960,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(pos_is_ok());
|
assert(pos_is_ok());
|
||||||
|
assert(evalList.is_valid(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -923,6 +990,9 @@ void Position::undo_move(Move m) {
|
||||||
remove_piece(pc, to);
|
remove_piece(pc, to);
|
||||||
pc = make_piece(us, PAWN);
|
pc = make_piece(us, PAWN);
|
||||||
put_piece(pc, to);
|
put_piece(pc, to);
|
||||||
|
|
||||||
|
PieceNumber piece_no0 = st->dirtyPiece.pieceNo[0];
|
||||||
|
evalList.put_piece(piece_no0, to, pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type_of(m) == CASTLING)
|
if (type_of(m) == CASTLING)
|
||||||
|
@ -932,8 +1002,12 @@ void Position::undo_move(Move m) {
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
move_piece(pc, to, from); // Put the piece back at the source square
|
move_piece(pc, to, from); // Put the piece back at the source square
|
||||||
|
|
||||||
|
PieceNumber piece_no0 = st->dirtyPiece.pieceNo[0];
|
||||||
|
evalList.put_piece(piece_no0, from, pc);
|
||||||
|
|
||||||
if (st->capturedPiece)
|
if (st->capturedPiece)
|
||||||
{
|
{
|
||||||
Square capsq = to;
|
Square capsq = to;
|
||||||
|
@ -950,6 +1024,11 @@ void Position::undo_move(Move m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
put_piece(st->capturedPiece, capsq); // Restore the captured piece
|
put_piece(st->capturedPiece, capsq); // Restore the captured piece
|
||||||
|
|
||||||
|
PieceNumber piece_no1 = st->dirtyPiece.pieceNo[1];
|
||||||
|
assert(evalList.bona_piece(piece_no1).fw == Eval::BONA_PIECE_ZERO);
|
||||||
|
assert(evalList.bona_piece(piece_no1).fb == Eval::BONA_PIECE_ZERO);
|
||||||
|
evalList.put_piece(piece_no1, capsq, st->capturedPiece);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -958,6 +1037,7 @@ void Position::undo_move(Move m) {
|
||||||
--gamePly;
|
--gamePly;
|
||||||
|
|
||||||
assert(pos_is_ok());
|
assert(pos_is_ok());
|
||||||
|
assert(evalList.is_valid(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -965,18 +1045,50 @@ void Position::undo_move(Move m) {
|
||||||
/// is a bit tricky in Chess960 where from/to squares can overlap.
|
/// is a bit tricky in Chess960 where from/to squares can overlap.
|
||||||
template<bool Do>
|
template<bool Do>
|
||||||
void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto) {
|
void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto) {
|
||||||
|
auto& dp = st->dirtyPiece;
|
||||||
|
// 差分計算のために移動した駒をStateInfoに記録しておく。
|
||||||
|
dp.dirty_num = 2; // 動いた駒は2個
|
||||||
|
|
||||||
|
PieceNumber piece_no0;
|
||||||
|
PieceNumber piece_no1;
|
||||||
|
|
||||||
|
if (Do) {
|
||||||
|
piece_no0 = piece_no_of(from);
|
||||||
|
piece_no1 = piece_no_of(to);
|
||||||
|
}
|
||||||
|
|
||||||
bool kingSide = to > from;
|
bool kingSide = to > from;
|
||||||
rfrom = to; // Castling is encoded as "king captures friendly rook"
|
rfrom = to; // Castling is encoded as "king captures friendly rook"
|
||||||
rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
|
rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
|
||||||
to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
|
to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
|
||||||
|
|
||||||
|
if (!Do) {
|
||||||
|
piece_no0 = piece_no_of(to);
|
||||||
|
piece_no1 = piece_no_of(rto);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove both pieces first since squares could overlap in Chess960
|
// Remove both pieces first since squares could overlap in Chess960
|
||||||
remove_piece(make_piece(us, KING), Do ? from : to);
|
remove_piece(make_piece(us, KING), Do ? from : to);
|
||||||
remove_piece(make_piece(us, ROOK), Do ? rfrom : rto);
|
remove_piece(make_piece(us, ROOK), Do ? rfrom : rto);
|
||||||
board[Do ? from : to] = board[Do ? rfrom : rto] = NO_PIECE; // Since remove_piece doesn't do it for us
|
board[Do ? from : to] = board[Do ? rfrom : rto] = NO_PIECE; // Since remove_piece doesn't do it for us
|
||||||
put_piece(make_piece(us, KING), Do ? to : from);
|
put_piece(make_piece(us, KING), Do ? to : from);
|
||||||
put_piece(make_piece(us, ROOK), Do ? rto : rfrom);
|
put_piece(make_piece(us, ROOK), Do ? rto : rfrom);
|
||||||
|
|
||||||
|
if (Do) {
|
||||||
|
dp.pieceNo[0] = piece_no0;
|
||||||
|
dp.changed_piece[0].old_piece = evalList.bona_piece(piece_no0);
|
||||||
|
evalList.put_piece(piece_no0, to, make_piece(us, KING));
|
||||||
|
dp.changed_piece[0].new_piece = evalList.bona_piece(piece_no0);
|
||||||
|
|
||||||
|
dp.pieceNo[1] = piece_no1;
|
||||||
|
dp.changed_piece[1].old_piece = evalList.bona_piece(piece_no1);
|
||||||
|
evalList.put_piece(piece_no1, rto, make_piece(us, ROOK));
|
||||||
|
dp.changed_piece[1].new_piece = evalList.bona_piece(piece_no1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
evalList.put_piece(piece_no0, from, make_piece(us, KING));
|
||||||
|
evalList.put_piece(piece_no1, rfrom, make_piece(us, ROOK));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1313,3 +1425,14 @@ bool Position::pos_is_ok() const {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PieceNumber Position::piece_no_of(Square sq) const
|
||||||
|
{
|
||||||
|
if (piece_on(sq) == NO_PIECE) {
|
||||||
|
sync_cout << *this << sync_endl;
|
||||||
|
}
|
||||||
|
assert(piece_on(sq) != NO_PIECE);
|
||||||
|
PieceNumber n = evalList.piece_no_of_board(sq);
|
||||||
|
assert(is_ok(n));
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
|
@ -23,10 +23,12 @@
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <iostream>
|
||||||
#include <memory> // For std::unique_ptr
|
#include <memory> // For std::unique_ptr
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "bitboard.h"
|
#include "bitboard.h"
|
||||||
|
#include "misc.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#include "eval/nnue/nnue_accumulator.h"
|
#include "eval/nnue/nnue_accumulator.h"
|
||||||
|
@ -194,6 +196,9 @@ private:
|
||||||
template<bool Do>
|
template<bool Do>
|
||||||
void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto);
|
void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto);
|
||||||
|
|
||||||
|
// 盤上のsqの升にある駒のPieceNumberを返す。
|
||||||
|
PieceNumber piece_no_of(Square sq) const;
|
||||||
|
|
||||||
// Data members
|
// Data members
|
||||||
Piece board[SQUARE_NB];
|
Piece board[SQUARE_NB];
|
||||||
Bitboard byTypeBB[PIECE_TYPE_NB];
|
Bitboard byTypeBB[PIECE_TYPE_NB];
|
||||||
|
|
11
src/types.h
11
src/types.h
|
@ -469,7 +469,7 @@ constexpr bool is_ok(Move m) {
|
||||||
// --------------------
|
// --------------------
|
||||||
|
|
||||||
// Positionクラスで用いる、駒リスト(どの駒がどこにあるのか)を管理するときの番号。
|
// Positionクラスで用いる、駒リスト(どの駒がどこにあるのか)を管理するときの番号。
|
||||||
enum PieceNumber : int8_t
|
enum PieceNumber : uint8_t
|
||||||
{
|
{
|
||||||
PIECE_NUMBER_PAWN = 0,
|
PIECE_NUMBER_PAWN = 0,
|
||||||
PIECE_NUMBER_KNIGHT = 16,
|
PIECE_NUMBER_KNIGHT = 16,
|
||||||
|
@ -483,8 +483,13 @@ enum PieceNumber : int8_t
|
||||||
PIECE_NUMBER_NB = 32,
|
PIECE_NUMBER_NB = 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
inline PieceNumber& operator++(PieceNumber& d) { return d = PieceNumber(int(d) + 1); } \
|
inline PieceNumber& operator++(PieceNumber& d) { return d = PieceNumber(int8_t(d) + 1); }
|
||||||
inline PieceNumber& operator--(PieceNumber& d) { return d = PieceNumber(int(d) - 1); }
|
inline PieceNumber operator++(PieceNumber& d, int) {
|
||||||
|
PieceNumber x = d;
|
||||||
|
d = PieceNumber(int8_t(d) + 1);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
inline PieceNumber& operator--(PieceNumber& d) { return d = PieceNumber(int8_t(d) - 1); }
|
||||||
|
|
||||||
// PieceNumberの整合性の検査。assert用。
|
// PieceNumberの整合性の検査。assert用。
|
||||||
constexpr bool is_ok(PieceNumber pn) { return pn < PIECE_NUMBER_NB; }
|
constexpr bool is_ok(PieceNumber pn) { return pn < PIECE_NUMBER_NB; }
|
||||||
|
|
69
src/uci.cpp
69
src/uci.cpp
|
@ -177,6 +177,73 @@ namespace {
|
||||||
<< "\nNodes/second : " << 1000 * nodes / elapsed << endl;
|
<< "\nNodes/second : " << 1000 * nodes / elapsed << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check sumを計算したとき、それを保存しておいてあとで次回以降、整合性のチェックを行なう。
|
||||||
|
uint64_t eval_sum;
|
||||||
|
|
||||||
|
// is_ready_cmd()を外部から呼び出せるようにしておく。(benchコマンドなどから呼び出したいため)
|
||||||
|
// 局面は初期化されないので注意。
|
||||||
|
void is_ready(Position& pos, istringstream& is, StateListPtr& states)
|
||||||
|
{
|
||||||
|
// "isready"を受け取ったあと、"readyok"を返すまで5秒ごとに改行を送るように修正する。(keep alive的な処理)
|
||||||
|
// USI2.0の仕様より。
|
||||||
|
// -"isready"のあとのtime out時間は、30秒程度とする。これを超えて、評価関数の初期化、hashテーブルの確保をしたい場合、
|
||||||
|
// 思考エンジン側から定期的に何らかのメッセージ(改行可)を送るべきである。
|
||||||
|
// -ShogiGUIではすでにそうなっているので、MyShogiもそれに追随する。
|
||||||
|
// -また、やねうら王のエンジン側は、"isready"を受け取ったあと、"readyok"を返すまで5秒ごとに改行を送るように修正する。
|
||||||
|
|
||||||
|
auto ended = false;
|
||||||
|
auto th = std::thread([&ended] {
|
||||||
|
int count = 0;
|
||||||
|
while (!ended)
|
||||||
|
{
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
if (++count >= 50 /* 5秒 */)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
sync_cout << sync_endl; // 改行を送信する。
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 評価関数の読み込みなど時間のかかるであろう処理はこのタイミングで行なう。
|
||||||
|
// 起動時に時間のかかる処理をしてしまうと将棋所がタイムアウト判定をして、思考エンジンとしての認識をリタイアしてしまう。
|
||||||
|
if (!UCI::load_eval_finished)
|
||||||
|
{
|
||||||
|
// 評価関数の読み込み
|
||||||
|
Eval::load_eval();
|
||||||
|
|
||||||
|
// チェックサムの計算と保存(その後のメモリ破損のチェックのため)
|
||||||
|
eval_sum = Eval::calc_check_sum();
|
||||||
|
|
||||||
|
// ソフト名の表示
|
||||||
|
Eval::print_softname(eval_sum);
|
||||||
|
|
||||||
|
UCI::load_eval_finished = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// メモリが破壊されていないかを調べるためにチェックサムを毎回調べる。
|
||||||
|
// 時間が少しもったいない気もするが.. 0.1秒ぐらいのことなので良しとする。
|
||||||
|
if (eval_sum != Eval::calc_check_sum())
|
||||||
|
sync_cout << "Error! : EVAL memory is corrupted" << sync_endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// isreadyに対してはreadyokを返すまで次のコマンドが来ないことは約束されているので
|
||||||
|
// このタイミングで各種変数の初期化もしておく。
|
||||||
|
|
||||||
|
TT.resize(Options["Hash"]);
|
||||||
|
Search::clear();
|
||||||
|
Time.availableNodes = 0;
|
||||||
|
|
||||||
|
Threads.stop = false;
|
||||||
|
|
||||||
|
// keep aliveを送信するために生成したスレッドを終了させ、待機する。
|
||||||
|
ended = true;
|
||||||
|
th.join();
|
||||||
|
|
||||||
|
sync_cout << "readyok" << sync_endl;
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
@ -227,7 +294,7 @@ void UCI::loop(int argc, char* argv[]) {
|
||||||
else if (token == "go") go(pos, is, states);
|
else if (token == "go") go(pos, is, states);
|
||||||
else if (token == "position") position(pos, is, states);
|
else if (token == "position") position(pos, is, states);
|
||||||
else if (token == "ucinewgame") Search::clear();
|
else if (token == "ucinewgame") Search::clear();
|
||||||
else if (token == "isready") sync_cout << "readyok" << sync_endl;
|
else if (token == "isready") is_ready(pos, is, states);
|
||||||
|
|
||||||
// Additional custom non-UCI commands, mainly for debugging
|
// Additional custom non-UCI commands, mainly for debugging
|
||||||
else if (token == "flip") pos.flip();
|
else if (token == "flip") pos.flip();
|
||||||
|
|
|
@ -75,6 +75,8 @@ std::string move(Move m, bool chess960);
|
||||||
std::string pv(const Position& pos, Depth depth, Value alpha, Value beta);
|
std::string pv(const Position& pos, Depth depth, Value alpha, Value beta);
|
||||||
Move to_move(const Position& pos, std::string& str);
|
Move to_move(const Position& pos, std::string& str);
|
||||||
|
|
||||||
|
// 評価関数を読み込んだかのフラグ。これはevaldirの変更にともなってfalseにする。
|
||||||
|
extern bool load_eval_finished; // = false;
|
||||||
} // namespace UCI
|
} // namespace UCI
|
||||||
|
|
||||||
extern UCI::OptionsMap Options;
|
extern UCI::OptionsMap Options;
|
||||||
|
|
|
@ -42,6 +42,7 @@ void on_hash_size(const Option& o) { TT.resize(o); }
|
||||||
void on_logger(const Option& o) { start_logger(o); }
|
void on_logger(const Option& o) { start_logger(o); }
|
||||||
void on_threads(const Option& o) { Threads.set(o); }
|
void on_threads(const Option& o) { Threads.set(o); }
|
||||||
void on_tb_path(const Option& o) { Tablebases::init(o); }
|
void on_tb_path(const Option& o) { Tablebases::init(o); }
|
||||||
|
void on_eval_dir(const Option& o) { load_eval_finished = false; }
|
||||||
|
|
||||||
|
|
||||||
/// Our case insensitive less() function as required by UCI protocol
|
/// Our case insensitive less() function as required by UCI protocol
|
||||||
|
@ -78,6 +79,14 @@ void init(OptionsMap& o) {
|
||||||
o["SyzygyProbeDepth"] << Option(1, 1, 100);
|
o["SyzygyProbeDepth"] << Option(1, 1, 100);
|
||||||
o["Syzygy50MoveRule"] << Option(true);
|
o["Syzygy50MoveRule"] << Option(true);
|
||||||
o["SyzygyProbeLimit"] << Option(7, 0, 7);
|
o["SyzygyProbeLimit"] << Option(7, 0, 7);
|
||||||
|
// 評価関数フォルダ。これを変更したとき、評価関数を次のisreadyタイミングで読み直す必要がある。
|
||||||
|
o["EvalDir"] << Option("eval", on_eval_dir);
|
||||||
|
// isreadyタイミングで評価関数を読み込まれると、新しい評価関数の変換のために
|
||||||
|
// test evalconvertコマンドを叩きたいのに、その新しい評価関数がないがために
|
||||||
|
// このコマンドの実行前に異常終了してしまう。
|
||||||
|
// そこでこの隠しオプションでisready時の評価関数の読み込みを抑制して、
|
||||||
|
// test evalconvertコマンドを叩く。
|
||||||
|
o["SkipLoadingEval"] << Option(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -186,4 +195,6 @@ Option& Option::operator=(const string& v) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 評価関数を読み込んだかのフラグ。これはevaldirの変更にともなってfalseにする。
|
||||||
|
bool load_eval_finished = false;
|
||||||
} // namespace UCI
|
} // namespace UCI
|
||||||
|
|
Loading…
Add table
Reference in a new issue