material.cpp misc.cpp movegen.cpp movepick.cpp pawns.cpp position.cpp psqt.cpp \
search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp \
nnue/evaluate_nnue.cpp nnue/features/half_kp.cpp \
- partner.cpp parser.cpp piece.cpp variant.cpp xboard.cpp
+ partner.cpp parser.cpp piece.cpp variant.cpp xboard.cpp \
+ nnue/features/half_kp_shogi.cpp nnue/features/half_kp_variants.cpp
OBJS = $(notdir $(SRCS:.cpp=.o))
DEPENDFLAGS += -std=c++17
LDFLAGS += $(EXTRALDFLAGS)
+# Ignore warning due to missing profile information from unused NNUE features
+CXXFLAGS += -Wno-profile-instr-out-of-date
+
# Compile version with support for large board variants
# Use precomputed magics by default if pext is not available
ifneq ($(largeboards),no)
material.cpp misc.cpp movegen.cpp movepick.cpp pawns.cpp position.cpp psqt.cpp \
search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp \
nnue/evaluate_nnue.cpp nnue/features/half_kp.cpp \
- partner.cpp parser.cpp piece.cpp variant.cpp xboard.cpp
+ partner.cpp parser.cpp piece.cpp variant.cpp xboard.cpp \
+ nnue/features/half_kp_shogi.cpp nnue/features/half_kp_variants.cpp
CXX=emcc
CXXFLAGS += --bind -DNNUE_EMBEDDING_OFF -DNO_THREADS -std=c++17 -Wall
using namespace std;
using namespace Eval::NNUE;
+NnueFeatures currentNnueFeatures;
+
namespace Eval {
bool useNNUE;
if (!useNNUE)
return;
+ currentNnueFeatures = variants.find(variant)->second->nnueFeatures;
+
#if defined(DEFAULT_NNUE_DIRECTORY)
#define stringify2(x) #x
#define stringify(x) stringify2(x)
} // namespace Eval
+extern NnueFeatures currentNnueFeatures;
+
#endif // #ifndef EVALUATE_H_INCLUDED
#include "../layers/affine_transform.h"
#include "../layers/clipped_relu.h"
+namespace Eval::NNUE::Features {
+// Alias for compatibility with upstream code
+template <Side AssociatedKing>
+using HalfKP = HalfKPChess<AssociatedKing>;
+}
+
namespace Eval::NNUE {
// Input features used in evaluation function
--- /dev/null
+/*
+ Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+ Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
+
+ Stockfish is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Stockfish is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// Definition of input features and network structure used in NNUE evaluation function
+
+#ifndef NNUE_HALFKP_SHOGI_256X2_32_32_H_INCLUDED
+#define NNUE_HALFKP_SHOGI_256X2_32_32_H_INCLUDED
+
+#include "../features/feature_set.h"
+#include "../features/half_kp_shogi.h"
+
+#include "../layers/input_slice.h"
+#include "../layers/affine_transform.h"
+#include "../layers/clipped_relu.h"
+
+namespace Eval::NNUE::Features {
+// Alias for compatibility with upstream code
+template <Side AssociatedKing>
+using HalfKP = HalfKPShogi<AssociatedKing>;
+}
+
+namespace Eval::NNUE {
+
+// Input features used in evaluation function
+using RawFeatures = Features::FeatureSet<
+ Features::HalfKPShogi<Features::Side::kFriend>>;
+
+// Number of input feature dimensions after conversion
+constexpr IndexType kTransformedFeatureDimensions = 256;
+
+namespace Layers {
+
+// Define network structure
+using InputLayer = InputSlice<kTransformedFeatureDimensions * 2>;
+using HiddenLayer1 = ClippedReLU<AffineTransform<InputLayer, 32>>;
+using HiddenLayer2 = ClippedReLU<AffineTransform<HiddenLayer1, 32>>;
+using OutputLayer = AffineTransform<HiddenLayer2, 1>;
+
+} // namespace Layers
+
+using Network = Layers::OutputLayer;
+
+} // namespace Eval::NNUE
+
+#endif // #ifndef NNUE_HALFKP_SHOGI_256X2_32_32_H_INCLUDED
--- /dev/null
+/*
+ Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+ Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
+
+ Stockfish is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Stockfish is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// Definition of input features and network structure used in NNUE evaluation function
+
+#ifndef NNUE_HALFKP_VARIANTS_256X2_32_32_H_INCLUDED
+#define NNUE_HALFKP_VARIANTS_256X2_32_32_H_INCLUDED
+
+#include "../features/feature_set.h"
+#include "../features/half_kp_variants.h"
+
+#include "../layers/input_slice.h"
+#include "../layers/affine_transform.h"
+#include "../layers/clipped_relu.h"
+
+namespace Eval::NNUE::Features {
+// Alias for compatibility with upstream code
+template <Side AssociatedKing>
+using HalfKP = HalfKPVariants<AssociatedKing>;
+}
+
+namespace Eval::NNUE {
+
+// Input features used in evaluation function
+using RawFeatures = Features::FeatureSet<
+ Features::HalfKPVariants<Features::Side::kFriend>>;
+
+// Number of input feature dimensions after conversion
+constexpr IndexType kTransformedFeatureDimensions = 256;
+
+namespace Layers {
+
+// Define network structure
+using InputLayer = InputSlice<kTransformedFeatureDimensions * 2>;
+using HiddenLayer1 = ClippedReLU<AffineTransform<InputLayer, 32>>;
+using HiddenLayer2 = ClippedReLU<AffineTransform<HiddenLayer1, 32>>;
+using OutputLayer = AffineTransform<HiddenLayer2, 1>;
+
+} // namespace Layers
+
+using Network = Layers::OutputLayer;
+
+} // namespace Eval::NNUE
+
+#endif // #ifndef NNUE_HALFKP_256X2_32_32_H_INCLUDED
namespace Eval::NNUE::Features {
// Map square to numbering on 8x8 board
- constexpr Square map_to_standard_board(Square s) {
+ constexpr Square to_chess_square(Square s) {
return Square(s - rank_of(s) * (FILE_MAX - FILE_H));
}
// Orient a square according to perspective (rotates by 180 for black)
- inline Square orient(const Position& pos, Color perspective, Square s) {
- return map_to_standard_board( perspective == WHITE || (pos.capture_the_flag(BLACK) & Rank8BB) ? s
- : flip_rank(flip_file(s, pos.max_file()), pos.max_rank()));
+ inline Square orient(Color perspective, Square s) {
+ return Square(int(to_chess_square(s)) ^ (bool(perspective) * 63));
}
// Index of a feature for a given king position and another piece on some square
- inline IndexType make_index(const Position& pos, Color perspective, Square s, Piece pc, Square ksq) {
- return IndexType(orient(pos, perspective, s) + kpp_board_index[perspective][pc] + PS_END * ksq);
+ inline IndexType make_index(Color perspective, Square s, Piece pc, Square ksq) {
+ return IndexType(orient(perspective, s) + kpp_board_index[perspective][pc] + PS_END * ksq);
}
// Get a list of indices for active features
template <Side AssociatedKing>
- void HalfKP<AssociatedKing>::AppendActiveIndices(
+ void HalfKPChess<AssociatedKing>::AppendActiveIndices(
const Position& pos, Color perspective, IndexList* active) {
- Square ksq = orient(pos, perspective, pos.square(perspective, pos.nnue_king()));
- Bitboard bb = pos.pieces() & ~pos.pieces(pos.nnue_king());
+ Square ksq = orient(perspective, pos.square<KING>(perspective));
+ Bitboard bb = pos.pieces() & ~pos.pieces(KING);
while (bb) {
Square s = pop_lsb(&bb);
- active->push_back(make_index(pos, perspective, s, pos.piece_on(s), ksq));
+ active->push_back(make_index(perspective, s, pos.piece_on(s), ksq));
}
}
// Get a list of indices for recently changed features
template <Side AssociatedKing>
- void HalfKP<AssociatedKing>::AppendChangedIndices(
+ void HalfKPChess<AssociatedKing>::AppendChangedIndices(
const Position& pos, const DirtyPiece& dp, Color perspective,
IndexList* removed, IndexList* added) {
- Square ksq = orient(pos, perspective, pos.square(perspective, pos.nnue_king()));
+ Square ksq = orient(perspective, pos.square<KING>(perspective));
for (int i = 0; i < dp.dirty_num; ++i) {
Piece pc = dp.piece[i];
- if (type_of(pc) == pos.nnue_king()) continue;
+ if (type_of(pc) == KING) continue;
if (dp.from[i] != SQ_NONE)
- removed->push_back(make_index(pos, perspective, dp.from[i], pc, ksq));
+ removed->push_back(make_index(perspective, dp.from[i], pc, ksq));
if (dp.to[i] != SQ_NONE)
- added->push_back(make_index(pos, perspective, dp.to[i], pc, ksq));
+ added->push_back(make_index(perspective, dp.to[i], pc, ksq));
}
}
- template class HalfKP<Side::kFriend>;
+ template class HalfKPChess<Side::kFriend>;
} // namespace Eval::NNUE::Features
// Feature HalfKP: Combination of the position of own king
// and the position of pieces other than kings
template <Side AssociatedKing>
- class HalfKP {
+ class HalfKPChess {
public:
// Feature name
--- /dev/null
+/*
+ Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+ Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
+
+ Stockfish is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Stockfish is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+//Definition of input features HalfKP of NNUE evaluation function
+
+#include "half_kp_shogi.h"
+#include "index_list.h"
+
+namespace Eval::NNUE::Features {
+
+ constexpr Square rotate(Square s) {
+ return Square(SQUARE_NB_SHOGI - 1 - int(s));
+ }
+
+ constexpr Square to_shogi_square(Square s) {
+ return Square((8 - s % 12) * 9 + 8 - s / 12);
+ }
+
+ // Orient a square according to perspective (rotates by 180 for black)
+ inline Square orient(Color perspective, Square s) {
+ return perspective == WHITE ? to_shogi_square(s) : rotate(to_shogi_square(s));
+ }
+
+ // Index of a feature for a given king position and another piece on some square
+ inline IndexType make_index(Color perspective, Square s, Piece pc, Square ksq) {
+ return IndexType(orient(perspective, s) + shogi_kpp_board_index[perspective][pc] + SHOGI_PS_END * ksq);
+ }
+
+ // Index of a feature for a given king position and hand piece
+ inline IndexType make_index(Color perspective, Color c, int hand_index, PieceType pt, Square ksq) {
+ Color color = (c == perspective) ? WHITE : BLACK;
+ return IndexType(hand_index + shogi_kpp_hand_index[color][pt] + SHOGI_PS_END * ksq);
+ }
+
+ // Get a list of indices for active features
+ template <Side AssociatedKing>
+ void HalfKPShogi<AssociatedKing>::AppendActiveIndices(
+ const Position& pos, Color perspective, IndexList* active) {
+
+ Square ksq = orient(perspective, pos.square<KING>(perspective));
+ Bitboard bb = pos.pieces() & ~pos.pieces(KING);
+ while (bb) {
+ Square s = pop_lsb(&bb);
+ active->push_back(make_index(perspective, s, pos.piece_on(s), ksq));
+ }
+
+ // Indices for pieces in hand
+ for (Color c : {WHITE, BLACK})
+ for (PieceType pt : pos.piece_types())
+ for (int i = 0; i < pos.count_in_hand(c, pt); i++)
+ active->push_back(make_index(perspective, c, i, pt, ksq));
+ }
+
+ // Get a list of indices for recently changed features
+ template <Side AssociatedKing>
+ void HalfKPShogi<AssociatedKing>::AppendChangedIndices(
+ const Position& pos, const DirtyPiece& dp, Color perspective,
+ IndexList* removed, IndexList* added) {
+
+ Square ksq = orient(perspective, pos.square<KING>(perspective));
+ for (int i = 0; i < dp.dirty_num; ++i) {
+ Piece pc = dp.piece[i];
+ if (type_of(pc) == KING) continue;
+ if (dp.from[i] != SQ_NONE)
+ removed->push_back(make_index(perspective, dp.from[i], pc, ksq));
+ else if (dp.dirty_num == 1)
+ {
+ Piece handPc = dp.handPiece[i];
+ removed->push_back(make_index(perspective, color_of(handPc), pos.count_in_hand(color_of(handPc), type_of(handPc)), type_of(handPc), ksq));
+ }
+ if (dp.to[i] != SQ_NONE)
+ added->push_back(make_index(perspective, dp.to[i], pc, ksq));
+ else if (i == 1)
+ {
+ Piece handPc = dp.handPiece[i];
+ added->push_back(make_index(perspective, color_of(handPc), pos.count_in_hand(color_of(handPc), type_of(handPc)) - 1, type_of(handPc), ksq));
+ }
+ }
+ }
+
+ template class HalfKPShogi<Side::kFriend>;
+
+} // namespace Eval::NNUE::Features
--- /dev/null
+/*
+ Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+ Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
+
+ Stockfish is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Stockfish is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+//Definition of input features HalfKP of NNUE evaluation function
+
+#ifndef NNUE_FEATURES_HALF_KP_SHOGI_H_INCLUDED
+#define NNUE_FEATURES_HALF_KP_SHOGI_H_INCLUDED
+
+#include "../../evaluate.h"
+#include "features_common.h"
+
+namespace Eval::NNUE::Features {
+
+ // Feature HalfKP: Combination of the position of own king
+ // and the position of pieces other than kings
+ template <Side AssociatedKing>
+ class HalfKPShogi {
+
+ public:
+ // Feature name
+ static constexpr const char* kName = "HalfKP(Friend)";
+ // Hash value embedded in the evaluation file
+ static constexpr std::uint32_t kHashValue =
+ 0x5D69D5B9u ^ (AssociatedKing == Side::kFriend);
+ // Number of feature dimensions
+ static constexpr IndexType kDimensions =
+ static_cast<IndexType>(SQUARE_NB_SHOGI) * static_cast<IndexType>(SHOGI_PS_END);
+ // Maximum number of simultaneously active features
+ static constexpr IndexType kMaxActiveDimensions = 38; // Kings don't count
+ // Trigger for full calculation instead of difference calculation
+ static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kFriendKingMoved;
+
+ // Get a list of indices for active features
+ static void AppendActiveIndices(const Position& pos, Color perspective,
+ IndexList* active);
+
+ // Get a list of indices for recently changed features
+ static void AppendChangedIndices(const Position& pos, const DirtyPiece& dp, Color perspective,
+ IndexList* removed, IndexList* added);
+ };
+
+} // namespace Eval::NNUE::Features
+
+#endif // #ifndef NNUE_FEATURES_HALF_KP_SHOGI_H_INCLUDED
--- /dev/null
+/*
+ Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+ Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
+
+ Stockfish is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Stockfish is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+//Definition of input features HalfKP of NNUE evaluation function
+
+#include "half_kp_variants.h"
+#include "index_list.h"
+
+#ifdef LARGEBOARDS
+#include "half_kp_shogi.h"
+#endif
+
+namespace Eval::NNUE::Features {
+
+ // Map square to numbering on 8x8 board
+ constexpr Square to_chess_square(Square s) {
+ return Square(s - rank_of(s) * (FILE_MAX - FILE_H));
+ }
+
+ // Orient a square according to perspective (rotates by 180 for black)
+ inline Square orient(const Position& pos, Color perspective, Square s) {
+ return to_chess_square( perspective == WHITE || (pos.capture_the_flag(BLACK) & Rank8BB) ? s
+ : flip_rank(flip_file(s, pos.max_file()), pos.max_rank()));
+ }
+
+ // Index of a feature for a given king position and another piece on some square
+ inline IndexType make_index(const Position& pos, Color perspective, Square s, Piece pc, Square ksq) {
+ return IndexType(orient(pos, perspective, s) + kpp_board_index[perspective][pc] + PS_END * ksq);
+ }
+
+ // Get a list of indices for active features
+ template <Side AssociatedKing>
+ void HalfKPVariants<AssociatedKing>::AppendActiveIndices(
+ const Position& pos, Color perspective, IndexList* active) {
+
+ // Re-route to shogi features
+#ifdef LARGEBOARDS
+ if (currentNnueFeatures == NNUE_SHOGI)
+ {
+ assert(HalfKPShogi<AssociatedKing>::kDimensions <= kDimensions);
+ return HalfKPShogi<AssociatedKing>::AppendActiveIndices(pos, perspective, active);
+ }
+#endif
+
+ Square ksq = orient(pos, perspective, pos.square(perspective, pos.nnue_king()));
+ Bitboard bb = pos.pieces() & ~pos.pieces(pos.nnue_king());
+ while (bb) {
+ Square s = pop_lsb(&bb);
+ active->push_back(make_index(pos, perspective, s, pos.piece_on(s), ksq));
+ }
+ }
+
+ // Get a list of indices for recently changed features
+ template <Side AssociatedKing>
+ void HalfKPVariants<AssociatedKing>::AppendChangedIndices(
+ const Position& pos, const DirtyPiece& dp, Color perspective,
+ IndexList* removed, IndexList* added) {
+
+ // Re-route to shogi features
+#ifdef LARGEBOARDS
+ if (currentNnueFeatures == NNUE_SHOGI)
+ {
+ assert(HalfKPShogi<AssociatedKing>::kDimensions <= kDimensions);
+ return HalfKPShogi<AssociatedKing>::AppendChangedIndices(pos, dp, perspective, removed, added);
+ }
+#endif
+
+ Square ksq = orient(pos, perspective, pos.square(perspective, pos.nnue_king()));
+ for (int i = 0; i < dp.dirty_num; ++i) {
+ Piece pc = dp.piece[i];
+ if (type_of(pc) == pos.nnue_king()) continue;
+ if (dp.from[i] != SQ_NONE)
+ removed->push_back(make_index(pos, perspective, dp.from[i], pc, ksq));
+ if (dp.to[i] != SQ_NONE)
+ added->push_back(make_index(pos, perspective, dp.to[i], pc, ksq));
+ }
+ }
+
+ template class HalfKPVariants<Side::kFriend>;
+
+} // namespace Eval::NNUE::Features
--- /dev/null
+/*
+ Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+ Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
+
+ Stockfish is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Stockfish is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+//Definition of input features HalfKP of NNUE evaluation function
+
+#ifndef NNUE_FEATURES_HALF_KP_VARIANTS_H_INCLUDED
+#define NNUE_FEATURES_HALF_KP_VARIANTS_H_INCLUDED
+
+#include "../../evaluate.h"
+#include "features_common.h"
+
+namespace Eval::NNUE::Features {
+
+ // Feature HalfKP: Combination of the position of own king
+ // and the position of pieces other than kings
+ template <Side AssociatedKing>
+ class HalfKPVariants {
+
+ public:
+ // Feature name
+ static constexpr const char* kName = "HalfKP(Friend)";
+ // Hash value embedded in the evaluation file
+ static constexpr std::uint32_t kHashValue =
+ 0x5D69D5B9u ^ (AssociatedKing == Side::kFriend);
+ // Number of feature dimensions
+ static constexpr IndexType kDimensions =
+#ifdef LARGEBOARDS
+ static_cast<IndexType>(SQUARE_NB_SHOGI) * static_cast<IndexType>(SHOGI_PS_END);
+#else
+ static_cast<IndexType>(SQUARE_NB_CHESS) * static_cast<IndexType>(PS_END);
+#endif
+ // Maximum number of simultaneously active features
+ static constexpr IndexType kMaxActiveDimensions = 64; // Kings don't count
+ // Trigger for full calculation instead of difference calculation
+ static constexpr TriggerEvent kRefreshTrigger = TriggerEvent::kFriendKingMoved;
+
+ // Get a list of indices for active features
+ static void AppendActiveIndices(const Position& pos, Color perspective,
+ IndexList* active);
+
+ // Get a list of indices for recently changed features
+ static void AppendChangedIndices(const Position& pos, const DirtyPiece& dp, Color perspective,
+ IndexList* removed, IndexList* added);
+ };
+
+} // namespace Eval::NNUE::Features
+
+#endif // #ifndef NNUE_FEATURES_HALF_KP_VARIANTS_H_INCLUDED
#define NNUE_ARCHITECTURE_H_INCLUDED
// Defines the network structure
-#include "architectures/halfkp_256x2-32-32.h"
+// #include "architectures/halfkp_256x2-32-32.h"
+// #include "architectures/halfkp_shogi_256x2-32-32.h"
+#include "architectures/halfkp_variants_256x2-32-32.h"
namespace Eval::NNUE {
PS_END2 = 12 * SQUARE_NB_CHESS + 1
};
+ enum {
+ SHOGI_HAND_W_PAWN = 1,
+ SHOGI_HAND_B_PAWN = 20,
+ SHOGI_HAND_W_LANCE = 39,
+ SHOGI_HAND_B_LANCE = 44,
+ SHOGI_HAND_W_KNIGHT = 49,
+ SHOGI_HAND_B_KNIGHT = 54,
+ SHOGI_HAND_W_SILVER = 59,
+ SHOGI_HAND_B_SILVER = 64,
+ SHOGI_HAND_W_GOLD = 69,
+ SHOGI_HAND_B_GOLD = 74,
+ SHOGI_HAND_W_BISHOP = 79,
+ SHOGI_HAND_B_BISHOP = 82,
+ SHOGI_HAND_W_ROOK = 85,
+ SHOGI_HAND_B_ROOK = 88,
+ SHOGI_HAND_END = 90,
+
+ SHOGI_PS_W_PAWN = SHOGI_HAND_END,
+ SHOGI_PS_B_PAWN = 1 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_W_LANCE = 2 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_B_LANCE = 3 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_W_KNIGHT = 4 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_B_KNIGHT = 5 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_W_SILVER = 6 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_B_SILVER = 7 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_W_GOLD = 8 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_B_GOLD = 9 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_W_BISHOP = 10 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_B_BISHOP = 11 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_W_HORSE = 12 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_B_HORSE = 13 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_W_ROOK = 14 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_B_ROOK = 15 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_W_DRAGON = 16 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_B_DRAGON = 17 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_W_KING = 18 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_END = SHOGI_PS_W_KING, // pieces without kings (pawns included)
+ SHOGI_PS_B_KING = 19 * SQUARE_NB_SHOGI + SHOGI_HAND_END,
+ SHOGI_PS_END2 = 20 * SQUARE_NB_SHOGI + SHOGI_HAND_END
+ };
+
+ constexpr uint32_t shogi_kpp_board_index[COLOR_NB][PIECE_NB] = {
+ // convention: W - us, B - them
+ // viewed from other side, W and B are reversed
+ { PS_NONE, PS_NONE, PS_NONE, SHOGI_PS_W_BISHOP, SHOGI_PS_W_ROOK, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, SHOGI_PS_W_SILVER, PS_NONE, SHOGI_PS_W_DRAGON, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, SHOGI_PS_W_PAWN, SHOGI_PS_W_LANCE, SHOGI_PS_W_KNIGHT, PS_NONE, SHOGI_PS_W_GOLD,
+ SHOGI_PS_W_HORSE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ SHOGI_PS_W_KING, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+
+ PS_NONE, PS_NONE, PS_NONE, SHOGI_PS_B_BISHOP, SHOGI_PS_B_ROOK, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, SHOGI_PS_B_SILVER, PS_NONE, SHOGI_PS_B_DRAGON, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, SHOGI_PS_B_PAWN, SHOGI_PS_B_LANCE, SHOGI_PS_B_KNIGHT, PS_NONE, SHOGI_PS_B_GOLD,
+ SHOGI_PS_B_HORSE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ SHOGI_PS_B_KING, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE },
+
+ { PS_NONE, PS_NONE, PS_NONE, SHOGI_PS_B_BISHOP, SHOGI_PS_B_ROOK, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, SHOGI_PS_B_SILVER, PS_NONE, SHOGI_PS_B_DRAGON, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, SHOGI_PS_B_PAWN, SHOGI_PS_B_LANCE, SHOGI_PS_B_KNIGHT, PS_NONE, SHOGI_PS_B_GOLD,
+ SHOGI_PS_B_HORSE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ SHOGI_PS_B_KING, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+
+ PS_NONE, PS_NONE, PS_NONE, SHOGI_PS_W_BISHOP, SHOGI_PS_W_ROOK, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, SHOGI_PS_W_SILVER, PS_NONE, SHOGI_PS_W_DRAGON, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, SHOGI_PS_W_PAWN, SHOGI_PS_W_LANCE, SHOGI_PS_W_KNIGHT, PS_NONE, SHOGI_PS_W_GOLD,
+ SHOGI_PS_W_HORSE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ SHOGI_PS_W_KING, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE }
+ };
+ static_assert(shogi_kpp_board_index[WHITE][make_piece(WHITE, SHOGI_PAWN)] == SHOGI_PS_W_PAWN);
+ static_assert(shogi_kpp_board_index[WHITE][make_piece(WHITE, KING)] == SHOGI_PS_W_KING);
+ static_assert(shogi_kpp_board_index[WHITE][make_piece(BLACK, SHOGI_PAWN)] == SHOGI_PS_B_PAWN);
+ static_assert(shogi_kpp_board_index[WHITE][make_piece(BLACK, KING)] == SHOGI_PS_B_KING);
+
+ constexpr uint32_t shogi_kpp_hand_index[COLOR_NB][PIECE_TYPE_NB] = {
+ // convention: W - us, B - them
+ // viewed from other side, W and B are reversed
+ { PS_NONE, PS_NONE, PS_NONE, SHOGI_HAND_W_BISHOP, SHOGI_HAND_W_ROOK, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, SHOGI_HAND_W_SILVER, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, SHOGI_HAND_W_PAWN, SHOGI_HAND_W_LANCE, SHOGI_HAND_W_KNIGHT, PS_NONE, SHOGI_HAND_W_GOLD,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE },
+
+ { PS_NONE, PS_NONE, PS_NONE, SHOGI_HAND_B_BISHOP, SHOGI_HAND_B_ROOK, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, SHOGI_HAND_B_SILVER, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, SHOGI_HAND_B_PAWN, SHOGI_HAND_B_LANCE, SHOGI_HAND_B_KNIGHT, PS_NONE, SHOGI_HAND_B_GOLD,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE,
+ PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE, PS_NONE }
+ };
+ static_assert(shogi_kpp_hand_index[WHITE][SHOGI_PAWN] == SHOGI_HAND_W_PAWN);
+ static_assert(shogi_kpp_hand_index[WHITE][GOLD] == SHOGI_HAND_W_GOLD);
+ static_assert(shogi_kpp_hand_index[BLACK][SHOGI_PAWN] == SHOGI_HAND_B_PAWN);
+ static_assert(shogi_kpp_hand_index[BLACK][GOLD] == SHOGI_HAND_B_GOLD);
+
constexpr uint32_t kpp_board_index[COLOR_NB][PIECE_NB] = {
// convention: W - us, B - them
// viewed from other side, W and B are reversed
for (std::size_t i = 0; i < kHalfDimensions; ++i)
biases_[i] = read_little_endian<BiasType>(stream);
- for (std::size_t i = 0; i < kHalfDimensions * kInputDimensions; ++i)
+ for (std::size_t i = 0; i < kHalfDimensions * ( currentNnueFeatures == NNUE_SHOGI ? SQUARE_NB_SHOGI * SHOGI_PS_END
+ : currentNnueFeatures == NNUE_CHESS ? SQUARE_NB_CHESS * PS_END
+ : SQUARE_NB_CHESS * PS_END); ++i)
weights_[i] = read_little_endian<WeightType>(stream);
return !stream.fail();
}
// of the estimated gain in terms of features to be added/subtracted.
StateInfo *st = pos.state(), *next = nullptr;
int gain = pos.count<ALL_PIECES>() - 2;
+
while (st->accumulator.state[c] == EMPTY)
{
auto& dp = st->dirtyPiece;
add_to_hand(pieceToHand);
k ^= Zobrist::inHand[pieceToHand][pieceCountInHand[color_of(pieceToHand)][type_of(pieceToHand)] - 1]
^ Zobrist::inHand[pieceToHand][pieceCountInHand[color_of(pieceToHand)][type_of(pieceToHand)]];
+
+ if (Eval::useNNUE)
+ dp.handPiece[1] = pieceToHand;
}
+ else
+ dp.handPiece[1] = NO_PIECE;
// Update material hash key and prefetch access to materialTable
k ^= Zobrist::psq[captured][capsq];
{
// Add drop piece
dp.piece[0] = pc;
+ dp.handPiece[0] = make_piece(us, in_hand_piece_type(m));
dp.from[0] = SQ_NONE;
dp.to[0] = to;
}
// Promoting pawn to SQ_NONE, promoted piece from SQ_NONE
dp.to[0] = SQ_NONE;
dp.piece[dp.dirty_num] = promotion;
+ dp.handPiece[dp.dirty_num] = NO_PIECE;
dp.from[dp.dirty_num] = SQ_NONE;
dp.to[dp.dirty_num] = to;
dp.dirty_num++;
// Promoting piece to SQ_NONE, promoted piece from SQ_NONE
dp.to[0] = SQ_NONE;
dp.piece[dp.dirty_num] = promotion;
+ dp.handPiece[dp.dirty_num] = NO_PIECE;
dp.from[dp.dirty_num] = SQ_NONE;
dp.to[dp.dirty_num] = to;
dp.dirty_num++;
// Demoting piece to SQ_NONE, demoted piece from SQ_NONE
dp.to[0] = SQ_NONE;
dp.piece[dp.dirty_num] = demotion;
+ dp.handPiece[dp.dirty_num] = NO_PIECE;
dp.from[dp.dirty_num] = SQ_NONE;
dp.to[dp.dirty_num] = to;
dp.dirty_num++;
{
// Add gating piece
dp.piece[dp.dirty_num] = gating_piece;
+ dp.handPiece[dp.dirty_num] = gating_piece;
dp.from[dp.dirty_num] = SQ_NONE;
dp.to[dp.dirty_num] = gate;
dp.dirty_num++;
if (Eval::useNNUE)
{
dp.piece[dp.dirty_num] = bpc;
+ dp.handPiece[dp.dirty_num] = NO_PIECE;
dp.from[dp.dirty_num] = bsq;
dp.to[dp.dirty_num] = SQ_NONE;
dp.dirty_num++;
add_to_hand(pieceToHand);
k ^= Zobrist::inHand[pieceToHand][pieceCountInHand[color_of(pieceToHand)][type_of(pieceToHand)] - 1]
^ Zobrist::inHand[pieceToHand][pieceCountInHand[color_of(pieceToHand)][type_of(pieceToHand)]];
+
+ if (Eval::useNNUE)
+ dp.handPiece[dp.dirty_num - 1] = pieceToHand;
}
// Update material hash key
SQUARE_BIT_MASK = 63,
#endif
SQ_MAX = SQUARE_NB - 1,
- SQUARE_NB_CHESS = 64
+ SQUARE_NB_CHESS = 64,
+ SQUARE_NB_SHOGI = 81,
};
enum Direction : int {
// both the pawn and the captured piece to SQ_NONE and the piece promoted
// to from SQ_NONE to the capture square.
Piece piece[12];
+ Piece handPiece[12];
// From and to squares, which may be SQ_NONE
Square from[12];
Square to[12];
};
+enum NnueFeatures {
+ NNUE_CHESS,
+ NNUE_SHOGI,
+ NNUE_VARIANT,
+};
+
/// Score enum stores a middlegame and an endgame value in a single integer (enum).
/// The least significant 16 bits are used to store the middlegame value and the
/// upper 16 bits are used to store the endgame value. We have to take care to
Variant* chess_variant() {
Variant* v = fairy_variant_base();
v->endgameEval = true;
+ v->nnueFeatures = NNUE_CHESS;
return v;
}
Variant* chess960_variant() {
v->promotionRank = RANK_7;
v->promotedPieceType[LANCE] = GOLD;
v->promotedPieceType[SHOGI_KNIGHT] = GOLD;
+ v->nnueFeatures = NNUE_SHOGI;
return v;
}
Variant* capablanca_variant() {
MaterialCounting materialCounting = NO_MATERIAL_COUNTING;
CountingRule countingRule = NO_COUNTING;
+ NnueFeatures nnueFeatures = NNUE_VARIANT;
+
// Derived properties
bool fastAttacks = true;
bool fastAttacks2 = true;