diff --git a/src/eval/nnue/evaluate_nnue.cpp b/src/eval/nnue/evaluate_nnue.cpp index 84707bf9..de86ebe9 100644 --- a/src/eval/nnue/evaluate_nnue.cpp +++ b/src/eval/nnue/evaluate_nnue.cpp @@ -1,10 +1,12 @@ // NNUE評価関数の計算に関するコード #include +#include #include "../../evaluate.h" #include "../../position.h" #include "../../misc.h" +#include "../../uci.h" #include "evaluate_nnue.h" @@ -263,7 +265,7 @@ Value compute_eval(const Position& pos) { } // 評価関数 -Value evaluate(const Position& pos) { +Value NNUE::evaluate(const Position& pos) { const auto& accumulator = pos.state()->accumulator; if (accumulator.computed_score) { return accumulator.score; diff --git a/src/eval/nnue/evaluate_nnue.h b/src/eval/nnue/evaluate_nnue.h index a95f2bd9..1ca48d5b 100644 --- a/src/eval/nnue/evaluate_nnue.h +++ b/src/eval/nnue/evaluate_nnue.h @@ -55,6 +55,8 @@ bool ReadParameters(std::istream& stream); // 評価関数パラメータを書き込む bool WriteParameters(std::ostream& stream); +Value evaluate(const Position& pos); + } // namespace NNUE } // namespace Eval diff --git a/src/eval/nnue/features/feature_set.h b/src/eval/nnue/features/feature_set.h index 5d312a2e..919be65d 100644 --- a/src/eval/nnue/features/feature_set.h +++ b/src/eval/nnue/features/feature_set.h @@ -71,7 +71,7 @@ class FeatureSetBase { template static void AppendActiveIndices( const Position& pos, TriggerEvent trigger, IndexListType active[2]) { - for (const auto perspective : COLOR) { + for (const auto perspective : Colors) { Derived::CollectActiveIndices( pos, trigger, perspective, &active[perspective]); } @@ -85,7 +85,7 @@ class FeatureSetBase { const auto& dp = pos.state()->dirtyPiece; if (dp.dirty_num == 0) return; - for (const auto perspective : COLOR) { + for (const auto perspective : Colors) { reset[perspective] = false; switch (trigger) { case TriggerEvent::kNone: @@ -105,7 +105,7 @@ class FeatureSetBase { reset[perspective] = true; break; default: - ASSERT_LV5(false); + assert(false); break; } if (reset[perspective]) { diff --git a/src/eval/nnue/features/half_kp.cpp b/src/eval/nnue/features/half_kp.cpp index f1a1f57f..1741f3ce 100644 --- a/src/eval/nnue/features/half_kp.cpp +++ b/src/eval/nnue/features/half_kp.cpp @@ -28,7 +28,7 @@ inline void HalfKP::GetPieces( const PieceNumber target = (AssociatedKing == Side::kFriend) ? static_cast(PIECE_NUMBER_KING + perspective) : static_cast(PIECE_NUMBER_KING + ~perspective); - *sq_target_k = static_cast(((*pieces)[target] - f_king) % SQ_NB); + *sq_target_k = static_cast(((*pieces)[target] - f_king) % SQUARE_NB); } // 特徴量のうち、値が1であるインデックスのリストを取得する diff --git a/src/eval/nnue/features/half_kp.h b/src/eval/nnue/features/half_kp.h index ffbc2947..556127d3 100644 --- a/src/eval/nnue/features/half_kp.h +++ b/src/eval/nnue/features/half_kp.h @@ -26,7 +26,7 @@ class HalfKP { 0x5D69D5B9u ^ (AssociatedKing == Side::kFriend); // 特徴量の次元数 static constexpr IndexType kDimensions = - static_cast(SQ_NB) * static_cast(fe_end); + static_cast(SQUARE_NB) * static_cast(fe_end); // 特徴量のうち、同時に値が1となるインデックスの数の最大値 static constexpr IndexType kMaxActiveDimensions = PIECE_NUMBER_KING; // 差分計算の代わりに全計算を行うタイミング diff --git a/src/eval/nnue/features/half_relative_kp.cpp b/src/eval/nnue/features/half_relative_kp.cpp index 3ee49ff9..d0810df6 100644 --- a/src/eval/nnue/features/half_relative_kp.cpp +++ b/src/eval/nnue/features/half_relative_kp.cpp @@ -17,8 +17,8 @@ inline IndexType HalfRelativeKP::MakeIndex( Square sq_k, BonaPiece p) { constexpr IndexType W = kBoardWidth; constexpr IndexType H = kBoardHeight; - const IndexType piece_index = (p - fe_hand_end) / SQ_NB; - const Square sq_p = static_cast((p - fe_hand_end) % SQ_NB); + const IndexType piece_index = (p - fe_hand_end) / SQUARE_NB; + const Square sq_p = static_cast((p - fe_hand_end) % SQUARE_NB); const IndexType relative_file = file_of(sq_p) - file_of(sq_k) + (W / 2); const IndexType relative_rank = rank_of(sq_p) - rank_of(sq_k) + (H / 2); return H * W * piece_index + H * relative_file + relative_rank; @@ -35,7 +35,7 @@ inline void HalfRelativeKP::GetPieces( const PieceNumber target = (AssociatedKing == Side::kFriend) ? static_cast(PIECE_NUMBER_KING + perspective) : static_cast(PIECE_NUMBER_KING + ~perspective); - *sq_target_k = static_cast(((*pieces)[target] - f_king) % SQ_NB); + *sq_target_k = static_cast(((*pieces)[target] - f_king) % SQUARE_NB); } // 特徴量のうち、値が1であるインデックスのリストを取得する diff --git a/src/eval/nnue/features/half_relative_kp.h b/src/eval/nnue/features/half_relative_kp.h index f9afd446..99e10c57 100644 --- a/src/eval/nnue/features/half_relative_kp.h +++ b/src/eval/nnue/features/half_relative_kp.h @@ -25,7 +25,7 @@ class HalfRelativeKP { static constexpr std::uint32_t kHashValue = 0xF9180919u ^ (AssociatedKing == Side::kFriend); // 玉を除いた駒種 - static constexpr IndexType kNumPieceKinds = (fe_end - fe_hand_end) / SQ_NB; + static constexpr IndexType kNumPieceKinds = (fe_end - fe_hand_end) / SQUARE_NB; // 玉を中央に置いた仮想的な盤の幅 static constexpr IndexType kBoardWidth = FILE_NB * 2 - 1; // 玉を中央に置いた仮想的な盤の高さ diff --git a/src/eval/nnue/features/k.cpp b/src/eval/nnue/features/k.cpp index 9c019e08..03f66ff5 100644 --- a/src/eval/nnue/features/k.cpp +++ b/src/eval/nnue/features/k.cpp @@ -20,8 +20,8 @@ void K::AppendActiveIndices( const BonaPiece* pieces = (perspective == BLACK) ? pos.eval_list()->piece_list_fb() : pos.eval_list()->piece_list_fw(); - ASSERT_LV5(pieces[PIECE_NUMBER_BKING] != BONA_PIECE_ZERO); - ASSERT_LV5(pieces[PIECE_NUMBER_WKING] != BONA_PIECE_ZERO); + assert(pieces[PIECE_NUMBER_BKING] != BONA_PIECE_ZERO); + assert(pieces[PIECE_NUMBER_WKING] != BONA_PIECE_ZERO); for (PieceNumber i = PIECE_NUMBER_KING; i < PIECE_NUMBER_NB; ++i) { active->push_back(pieces[i] - fe_end); } diff --git a/src/eval/nnue/features/k.h b/src/eval/nnue/features/k.h index a5dda8fd..1a01c471 100644 --- a/src/eval/nnue/features/k.h +++ b/src/eval/nnue/features/k.h @@ -22,7 +22,7 @@ class K { // 評価関数ファイルに埋め込むハッシュ値 static constexpr std::uint32_t kHashValue = 0xD3CEE169u; // 特徴量の次元数 - static constexpr IndexType kDimensions = SQ_NB * 2; + static constexpr IndexType kDimensions = SQUARE_NB * 2; // 特徴量のうち、同時に値が1となるインデックスの数の最大値 static constexpr IndexType kMaxActiveDimensions = 2; // 差分計算の代わりに全計算を行うタイミング diff --git a/src/eval/nnue/nnue_accumulator.h b/src/eval/nnue/nnue_accumulator.h index c7c43a3e..4241edb3 100644 --- a/src/eval/nnue/nnue_accumulator.h +++ b/src/eval/nnue/nnue_accumulator.h @@ -3,8 +3,6 @@ #ifndef _NNUE_ACCUMULATOR_H_ #define _NNUE_ACCUMULATOR_H_ -#include "../../config.h" - #if defined(EVAL_NNUE) #include "nnue_architecture.h" diff --git a/src/eval/nnue/nnue_architecture.h b/src/eval/nnue/nnue_architecture.h index 6815ada5..5f11a02b 100644 --- a/src/eval/nnue/nnue_architecture.h +++ b/src/eval/nnue/nnue_architecture.h @@ -8,6 +8,7 @@ // 入力特徴量とネットワーク構造が定義されたヘッダをincludeする // KP256型を使いたいときは、これを事前にdefineする。 +#define EVAL_NNUE_KP256 #if defined(EVAL_NNUE_KP256) #include "architectures/k-p_256x2-32-32.h" #else // #if defined(EVAL_NNUE_HALFKP256) diff --git a/src/eval/nnue/nnue_feature_transformer.h b/src/eval/nnue/nnue_feature_transformer.h index 22f5df82..f7c2080f 100644 --- a/src/eval/nnue/nnue_feature_transformer.h +++ b/src/eval/nnue/nnue_feature_transformer.h @@ -142,9 +142,9 @@ class FeatureTransformer { } #else for (IndexType j = 0; j < kHalfDimensions; ++j) { - BiasType sum = accumulation[perspectives[p]][0][j]; + BiasType sum = accumulation[static_cast(perspectives[p])][0][j]; for (IndexType i = 1; i < kRefreshTriggers.size(); ++i) { - sum += accumulation[perspectives[p]][i][j]; + sum += accumulation[static_cast(perspectives[p])][i][j]; } output[offset + j] = static_cast( std::max(0, std::min(127, sum))); @@ -161,7 +161,7 @@ class FeatureTransformer { Features::IndexList active_indices[2]; RawFeatures::AppendActiveIndices(pos, kRefreshTriggers[i], active_indices); - for (const auto perspective : COLOR) { + for (const auto perspective : Colors) { if (i == 0) { std::memcpy(accumulator.accumulation[perspective][i], biases_, kHalfDimensions * sizeof(BiasType)); @@ -217,7 +217,7 @@ class FeatureTransformer { bool reset[2]; RawFeatures::AppendChangedIndices(pos, kRefreshTriggers[i], removed_indices, added_indices, reset); - for (const auto perspective : COLOR) { + for (const auto perspective : Colors) { #if defined(USE_AVX2) constexpr IndexType kNumChunks = kHalfDimensions / (kSimdWidth / 2); auto accumulation = reinterpret_cast<__m256i*>( diff --git a/src/eval/nnue/trainer/features/factorizer_half_kp.h b/src/eval/nnue/trainer/features/factorizer_half_kp.h index 20e4460e..5682e8e6 100644 --- a/src/eval/nnue/trainer/features/factorizer_half_kp.h +++ b/src/eval/nnue/trainer/features/factorizer_half_kp.h @@ -43,7 +43,7 @@ class Factorizer> { // kFeaturesHalfKP {true, FeatureType::kDimensions}, // kFeaturesHalfK - {true, SQ_NB}, + {true, SQUARE_NB}, // kFeaturesP {true, Factorizer

::GetDimensions()}, // kFeaturesHalfRelativeKP diff --git a/src/evaluate.h b/src/evaluate.h index cccdd25d..c96a1288 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -34,6 +34,181 @@ constexpr Value Tempo = Value(28); // Must be visible to search std::string trace(const Position& pos); Value evaluate(const Position& pos); + +// --- ]֐Ŏg萔 KPP(ʂƔC2)Pɑenum + +// (]֐̎̂Ƃɂ́ABonaPiece͎Rɒ`̂łł͒`ȂB) + + +// BonanzaKKP/KPPƌƂP(Piece)\^B +// KPP߂ƂɁA39̒n_̂̕悤ɁA~ɑ΂ĈӂȔԍKvƂȂB +enum BonaPiece : int32_t +{ + // f = friend()̈ӖBe = enemy()̈Ӗ + + // ̎̒l + BONA_PIECE_NOT_INIT = -1, + + // ȋB̂ƂȂǂ́AsvȋɈړB + BONA_PIECE_ZERO = 0, + + fe_hand_end = BONA_PIECE_ZERO + 1, + + // Bonanzâ悤ɔՏ̂肦Ȃ̕⍁̔ԍl߂ȂB + // R1) wK̂ƂɑPP1iڂɍƂāAtϊɂĐ\̂B + // R2) c^BitboardSquare̕ϊɍB + + // --- Տ̋ + f_pawn = fe_hand_end, + e_pawn = f_pawn + SQUARE_NB, + f_knight = e_pawn + SQUARE_NB, + e_knight = f_knight + SQUARE_NB, + f_bishop = e_knight + SQUARE_NB, + e_bishop = f_bishop + SQUARE_NB, + f_rook = e_bishop + SQUARE_NB, + e_rook = f_rook + SQUARE_NB, + f_queen = e_rook + SQUARE_NB, + e_queen = f_queen + SQUARE_NB, + fe_end = e_queen + SQUARE_NB, + f_king = fe_end, + e_king = f_king + SQUARE_NB, + fe_end2 = e_king + SQUARE_NB, // ʂ܂߂̔ԍB +}; + + +// BonaPiece肩猩Ƃ(39̕肩猩ƌ71̕)̔ԍƂ +// yAɂ̂ExtBonaPiece^ƌĂԂƂɂB +union ExtBonaPiece +{ + struct { + BonaPiece fw; // from white + BonaPiece fb; // from black + }; + BonaPiece from[2]; + + ExtBonaPiece() {} + ExtBonaPiece(BonaPiece fw_, BonaPiece fb_) : fw(fw_), fb(fb_) {} +}; + +// ̎wɂĂǂǂɈړ̂̏B +// ExtBonaPiece\łƂB +struct ChangedBonaPiece +{ + ExtBonaPiece old_piece; + ExtBonaPiece new_piece; +}; + +// KPPe[u̔Տ̋pcɑΉBonaPiece߂邽߂̔zB +// ) +// BonaPiece fb = kpp_board_index[pc].fb + sq; // 肩猩sqɂpcɑΉBonaPiece +// BonaPiece fw = kpp_board_index[pc].fw + sq; // 肩猩sqɂpcɑΉBonaPiece +extern ExtBonaPiece kpp_board_index[PIECE_NB]; + +// ]֐ŗpXgBǂ̋(PieceNumber)ǂɂ̂(BonaPiece)ێĂ\ +struct EvalList +{ + // ]֐(FV38^)ŗpԍ̃Xg + BonaPiece* piece_list_fw() const { return const_cast(pieceListFw); } + BonaPiece* piece_list_fb() const { return const_cast(pieceListFb); } + + // w肳ꂽpiece_nőExtBonaPiece^ɕϊĕԂB + ExtBonaPiece bona_piece(PieceNumber piece_no) const + { + ExtBonaPiece bp; + bp.fw = pieceListFw[piece_no]; + bp.fb = pieceListFb[piece_no]; + return bp; + } + + // Տsq̏piece_nopc̋zu + void put_piece(PieceNumber piece_no, Square sq, Piece pc) { + set_piece_on_board(piece_no, BonaPiece(kpp_board_index[pc].fw + sq), BonaPiece(kpp_board_index[pc].fb + inverse(sq)), sq); + } + + // Տ̂鏡sqɑΉPieceNumberԂB + PieceNumber piece_no_of_board(Square sq) const { return piece_no_list_board[sq]; } + + // pieceListB + // ɑΉ鎞̂߂ɁAgp̋̒lBONA_PIECE_ZEROɂĂB + // ʏ̕]֐̕]֐ƂėpłB + // piece_no_list̂ق̓fobO悤PIECE_NUMBER_NBŏB + void clear() + { + + for (auto& p : pieceListFw) + p = BONA_PIECE_ZERO; + + for (auto& p : pieceListFb) + p = BONA_PIECE_ZERO; + + for (auto& v : piece_no_list_board) + v = PIECE_NUMBER_NB; + } + + // list•ς̂Ƃ́Aadd()/remove()T|[gB + // DirtyPiecêقĂяoB + + // listadd()B + void add(BonaPiece fb); + + // listremoveB + void remove(BonaPiece fb); + + // ŕێĂpieceListFb[]BonaPieceł邩B + // : fobOpBxB + bool is_valid(const Position& pos); + + +protected: + + // Տsqɂpiece_nőBonaPiecefb,fwł邱Ƃݒ肷B + inline void set_piece_on_board(PieceNumber piece_no, BonaPiece fw, BonaPiece fb, Square sq) + { + assert(is_ok(piece_no)); + pieceListFw[piece_no] = fw; + pieceListFb[piece_no] = fb; + piece_no_list_board[sq] = piece_no; + } + + // XgBԍ(PieceNumber)‚̋ǂɂ̂(BonaPiece)BFV38ȂǂŗpB + + // Xg̒ + // 38Œ +public: + int length() const { return PIECE_NUMBER_KING; } + + // VPGATHERDDgsA4̔{łȂ΂ȂȂB + // ܂AKPPT^]֐Ȃǂ́A39,40Ԗڂ̗vf[ł邱ƂOƂ + // ANZXĂӏ̂Œӂ邱ƁB + static const int MAX_LENGTH = 40; +private: + + BonaPiece pieceListFw[MAX_LENGTH]; + BonaPiece pieceListFb[MAX_LENGTH]; + + // Տ̋ɑ΂āA̋ԍ(PieceNumber)ێĂz + // ʂSQ_NBɈړĂƂp+1܂ŕێĂA + // SQ_NB̋ʂړȂ̂ŁA̒lgƂ͂Ȃ͂B + PieceNumber piece_no_list_board[SQUARE_NB_PLUS1]; +}; + +// ]l̍vZ̊Ǘp +// ŐǖʂړԍǗ邽߂̍\ +// ́Aő2B +struct DirtyPiece +{ + // ̋ԍ̋牽ɕς̂ + Eval::ChangedBonaPiece changed_piece[2]; + + // dirtyɂȂԍ + PieceNumber pieceNo[2]; + + // dirtyɂȂB + // null move0ƂƂ肤B + // ƎƂōő2B + int dirty_num; + +}; } #endif // #ifndef EVALUATE_H_INCLUDED diff --git a/src/misc.cpp b/src/misc.cpp index 8d3b202d..69c6bacc 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -315,3 +315,19 @@ void bindThisThread(size_t idx) { #endif } // namespace WinProcGroup + +void sleep(int ms) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); +} + +void* aligned_malloc(size_t size, size_t align) +{ + void* p = _mm_malloc(size, align); + if (p == nullptr) + { + std::cout << "info string can't allocate memory. sise = " << size << std::endl; + exit(1); + } + return p; +} diff --git a/src/misc.h b/src/misc.h index ddd05e4e..5b63ef1c 100644 --- a/src/misc.h +++ b/src/misc.h @@ -21,6 +21,7 @@ #ifndef MISC_H_INCLUDED #define MISC_H_INCLUDED +#include #include #include #include @@ -110,4 +111,69 @@ namespace WinProcGroup { void bindThisThread(size_t idx); } +// 指定されたミリ秒だけsleepする。 +extern void sleep(int ms); + +// 途中での終了処理のためのwrapper +static void my_exit() +{ + sleep(3000); // エラーメッセージが出力される前に終了するのはまずいのでwaitを入れておく。 + exit(EXIT_FAILURE); +} + +// -------------------- +// Math +// -------------------- + +// 進行度の計算や学習で用いる数学的な関数 +namespace Math { + // シグモイド関数 + // = 1.0 / (1.0 + std::exp(-x)) + double sigmoid(double x); + + // シグモイド関数の微分 + // = sigmoid(x) * (1.0 - sigmoid(x)) + double dsigmoid(double x); + + // vを[lo,hi]の間に収まるようにクリップする。 + // ※ Stockfishではこの関数、bitboard.hに書いてある。 + template constexpr const T& clamp(const T& v, const T& lo, const T& hi) { + return v < lo ? lo : v > hi ? hi : v; + } + +} + +// -------------------- +// Path +// -------------------- + +// C#にあるPathクラス的なもの。ファイル名の操作。 +// C#のメソッド名に合わせておく。 +struct Path +{ + // path名とファイル名を結合して、それを返す。 + // folder名のほうは空文字列でないときに、末尾に'/'か'\\'がなければそれを付与する。 + static std::string Combine(const std::string& folder, const std::string& filename) + { + if (folder.length() >= 1 && *folder.rbegin() != '/' && *folder.rbegin() != '\\') + return folder + "/" + filename; + + return folder + filename; + } + + // full path表現から、(フォルダ名を除いた)ファイル名の部分を取得する。 + static std::string GetFileName(const std::string& path) + { + // "\"か"/"か、どちらを使ってあるかはわからない。 + auto path_index1 = path.find_last_of("\\") + 1; + auto path_index2 = path.find_last_of("/") + 1; + auto path_index = std::max(path_index1, path_index2); + + return path.substr(path_index); + } +}; + +extern void* aligned_malloc(size_t size, size_t align); +static void aligned_free(void* ptr) { _mm_free(ptr); } + #endif // #ifndef MISC_H_INCLUDED diff --git a/src/position.h b/src/position.h index 343751ed..d26b1a63 100644 --- a/src/position.h +++ b/src/position.h @@ -29,6 +29,8 @@ #include "bitboard.h" #include "types.h" +#include "eval/nnue/nnue_accumulator.h" + /// StateInfo struct stores information needed to restore a Position object to /// its previous state when we retract a move. Whenever a move is made on the @@ -54,6 +56,11 @@ struct StateInfo { Bitboard blockersForKing[COLOR_NB]; Bitboard pinners[COLOR_NB]; Bitboard checkSquares[PIECE_TYPE_NB]; + + Eval::NNUE::Accumulator accumulator; + + // ]l̍vZ̊Ǘp + Eval::DirtyPiece dirtyPiece; }; /// A list to keep track of the position states along the setup moves (from the @@ -165,6 +172,15 @@ public: bool pos_is_ok() const; void flip(); + // --- StateInfo + + // ݂̋ǖʂɑΉStateInfoԂB + // Ƃ΁Astate()->capturedPieceł΁AOǖʂŕߊlꂽi[ĂB + StateInfo* state() const { return st; } + + // ]֐Ŏg߂́Aǂ̋ԍ̋ǂɂ邩Ȃǂ̏B + const Eval::EvalList* eval_list() const { return &evalList; } + private: // Initialization helpers (used while setting up a position) void set_castling_right(Color c, Square rfrom); @@ -194,6 +210,9 @@ private: Thread* thisThread; StateInfo* st; bool chess960; + + // ]֐ŗp̃Xg + Eval::EvalList evalList; }; namespace PSQT { diff --git a/src/types.h b/src/types.h index b0758f43..c4458fe4 100644 --- a/src/types.h +++ b/src/types.h @@ -131,6 +131,8 @@ enum Color { WHITE, BLACK, COLOR_NB = 2 }; +constexpr Color Colors[2] = { WHITE, BLACK }; + enum CastlingSide { KING_SIDE, QUEEN_SIDE, CASTLING_SIDE_NB = 2 }; @@ -186,7 +188,10 @@ enum Value : int { RookValueMg = 1289, RookValueEg = 1378, QueenValueMg = 2529, QueenValueEg = 2687, - MidgameLimit = 15258, EndgameLimit = 3915 + MidgameLimit = 15258, EndgameLimit = 3915, + + // ]֐̕Ԃl̍ől(2**14炢Ɏ܂Ăė~Ƃ낾..) + VALUE_MAX_EVAL = 27000, }; enum PieceType { @@ -230,7 +235,8 @@ enum Square : int { SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8, SQ_NONE, - SQUARE_NB = 64 + SQUARE_NB = 64, + SQUARE_NB_PLUS1 = SQUARE_NB + 1, // ʂȂꍇASQ_NBɈړ̂ƂĈ߁AzSQ_NB+1ŊmۂȂƂȂƂ̂ł̒萔pB }; enum Direction : int { @@ -356,6 +362,10 @@ constexpr Square operator~(Square s) { return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8 } +constexpr Square inverse(Square s) { + return static_cast(static_cast(SQUARE_NB) - s - 1); +} + constexpr File operator~(File f) { return File(f ^ FILE_H); // Horizontal flip FILE_A -> FILE_H } @@ -454,4 +464,29 @@ constexpr bool is_ok(Move m) { return from_sq(m) != to_sq(m); // Catch MOVE_NULL and MOVE_NONE } +// -------------------- +//  +// -------------------- + +// PositionNXŗpAXg(ǂ̋ǂɂ̂)ǗƂ̔ԍB +enum PieceNumber : int8_t +{ + PIECE_NUMBER_PAWN = 0, + PIECE_NUMBER_KNIGHT = 16, + PIECE_NUMBER_BISHOP = 20, + PIECE_NUMBER_ROOK = 24, + PIECE_NUMBER_QUEEN = 28, + PIECE_NUMBER_KING = 30, + PIECE_NUMBER_WKING = 30, + PIECE_NUMBER_BKING = 31, // A̋ʂ̔ԍKvȏꍇ͂p + PIECE_NUMBER_ZERO = 0, + PIECE_NUMBER_NB = 32, +}; + +inline PieceNumber& operator++(PieceNumber& d) { return d = PieceNumber(int(d) + 1); } \ +inline PieceNumber& operator--(PieceNumber& d) { return d = PieceNumber(int(d) - 1); } + +// PieceNumber̐̌BassertpB +constexpr bool is_ok(PieceNumber pn) { return pn < PIECE_NUMBER_NB; } + #endif // #ifndef TYPES_H_INCLUDED