Closes #115.
return value == "win" || value == "loss" || value == "draw" || value == "none";
}
+ template <> bool set(const std::string& value, MaterialCounting& target) {
+ target = value == "janggi" ? JANGGI_MATERIAL
+ : value == "unweighted" ? UNWEIGHTED_MATERIAL
+ : NO_MATERIAL_COUNTING;
+ return value == "janggi" || value == "unweighted" || value == "none";
+ }
+
template <> bool set(const std::string& value, CountingRule& target) {
target = value == "makruk" ? MAKRUK_COUNTING
: value == "asean" ? ASEAN_COUNTING
: std::is_same<T, File>() ? "File"
: std::is_same<T, bool>() ? "bool"
: std::is_same<T, Value>() ? "Value"
+ : std::is_same<T, MaterialCounting>() ? "MaterialCounting"
: std::is_same<T, CountingRule>() ? "CountingRule"
: std::is_same<T, Bitboard>() ? "Bitboard"
: typeid(T).name();
parse_attribute("checkmateValue", v->checkmateValue);
parse_attribute("shogiPawnDropMateIllegal", v->shogiPawnDropMateIllegal);
parse_attribute("shatarMateRule", v->shatarMateRule);
- parse_attribute("bikjangValue", v->bikjangValue);
+ parse_attribute("bikjangRule", v->bikjangRule);
parse_attribute("bareKingValue", v->bareKingValue);
parse_attribute("extinctionValue", v->extinctionValue);
parse_attribute("bareKingMove", v->bareKingMove);
parse_attribute("flagMove", v->flagMove);
parse_attribute("checkCounting", v->checkCounting);
parse_attribute("connectN", v->connectN);
+ parse_attribute("materialCounting", v->materialCounting);
parse_attribute("countingRule", v->countingRule);
// Report invalid options
if (DoCheck)
si->checkSquares[pt] = ksq != SQ_NONE ? attacks_bb(~sideToMove, pt, ksq, pieces()) : Bitboard(0);
si->checkSquares[KING] = 0;
si->shak = si->checkersBB & (byTypeBB[KNIGHT] | byTypeBB[ROOK] | byTypeBB[BERS]);
- si->bikjang = var->bikjangValue != VALUE_NONE && ksq != SQ_NONE ? bool(attacks_bb(sideToMove, ROOK, ksq, pieces()) & pieces(sideToMove, KING)) : false;
+ si->bikjang = var->bikjangRule && ksq != SQ_NONE ? bool(attacks_bb(sideToMove, ROOK, ksq, pieces()) & pieces(sideToMove, KING)) : false;
}
}
}
}
- // Check for bikjang rule (Janggi)
- if (var->bikjangValue != VALUE_NONE && st->pliesFromNull > 0 && ( (st->bikjang && st->previous->bikjang)
- || (st->pass && st->previous->pass)))
- {
- // material counting
- auto weigth_count = [this](PieceType pt, int v){ return v * (count(WHITE, pt) - count(BLACK, pt)); };
- int materialCount = weigth_count(ROOK, 13)
- + weigth_count(JANGGI_CANNON, 7)
- + weigth_count(HORSE, 5)
- + weigth_count(JANGGI_ELEPHANT, 3)
- + weigth_count(WAZIR, 3)
- + weigth_count(SOLDIER, 2)
- - 1;
- bool stmUpMaterial = (sideToMove == WHITE) == (materialCount > 0);
- result = convert_mate_value(stmUpMaterial ? var->bikjangValue : -var->bikjangValue, ply);
+ // Check for bikjang rule (Janggi) and double passing
+ if (st->pliesFromNull > 0 && ((st->bikjang && st->previous->bikjang) || (st->pass && st->previous->pass)))
+ {
+ result = var->materialCounting ? convert_mate_value(sideToMove == WHITE ? material_counting_result()
+ : -material_counting_result(), ply)
+ : VALUE_DRAW;
return true;
}
// Tsume mode: Assume that side with king wins when not in check
bool check_counting() const;
int connect_n() const;
CheckCount checks_remaining(Color c) const;
+ MaterialCounting material_counting() const;
CountingRule counting_rule() const;
// Variant-specific properties
bool is_game_end(Value& result, int ply = 0) const;
bool is_optional_game_end(Value& result, int ply = 0, int countStarted = 0) const;
bool is_immediate_game_end(Value& result, int ply = 0) const;
+ Value material_counting_result() const;
bool has_game_cycle(int ply) const;
bool has_repeated() const;
int counting_limit() const;
return st->checksRemaining[c];
}
+inline MaterialCounting Position::material_counting() const {
+ assert(var != nullptr);
+ return var->materialCounting;
+}
+
inline CountingRule Position::counting_rule() const {
assert(var != nullptr);
return var->countingRule;
return st->bikjang;
}
+inline Value Position::material_counting_result() const {
+ auto weigth_count = [this](PieceType pt, int v){ return v * (count(WHITE, pt) - count(BLACK, pt)); };
+ int materialCount;
+ switch (var->materialCounting)
+ {
+ case JANGGI_MATERIAL:
+ materialCount = weigth_count(ROOK, 13)
+ + weigth_count(JANGGI_CANNON, 7)
+ + weigth_count(HORSE, 5)
+ + weigth_count(JANGGI_ELEPHANT, 3)
+ + weigth_count(WAZIR, 3)
+ + weigth_count(SOLDIER, 2)
+ - 1;
+ return materialCount > 0 ? VALUE_MATE : -VALUE_MATE;
+ case UNWEIGHTED_MATERIAL:
+ return count(WHITE, ALL_PIECES) > count(BLACK, ALL_PIECES) ? VALUE_MATE
+ : count(WHITE, ALL_PIECES) < count(BLACK, ALL_PIECES) ? -VALUE_MATE
+ : VALUE_DRAW;
+ default:
+ assert(false);
+ return VALUE_DRAW;
+ }
+}
+
inline void Position::add_to_hand(Piece pc) {
pieceCountInHand[color_of(pc)][type_of(pc)]++;
pieceCountInHand[color_of(pc)][ALL_PIECES]++;
CHECKS_0 = 0, CHECKS_NB = 11
};
+enum MaterialCounting {
+ NO_MATERIAL_COUNTING, JANGGI_MATERIAL, UNWEIGHTED_MATERIAL
+};
+
enum CountingRule {
NO_COUNTING, MAKRUK_COUNTING, ASEAN_COUNTING
};
}
inline bool is_pass(Move m) {
- return type_of(m) == SPECIAL || from_sq(m) == to_sq(m);
+ return type_of(m) == SPECIAL && from_sq(m) == to_sq(m);
}
constexpr Move make_move(Square from, Square to) {
v->mobilityRegion[BLACK][WAZIR] = black_castle;
v->soldierPromotionRank = RANK_1;
v->flyingGeneral = false;
- v->bikjangValue = VALUE_MATE;
+ v->bikjangRule = true;
+ v->materialCounting = JANGGI_MATERIAL;
v->diagonalLines = make_bitboard(SQ_D1, SQ_F1, SQ_E2, SQ_D3, SQ_F3,
SQ_D8, SQ_F8, SQ_E9, SQ_D10, SQ_F10);
v->kingPass = true;
// Traditional rules of Janggi, where bikjang is a draw
Variant* janggi_traditional_variant() {
Variant* v = janggi_variant();
- v->bikjangValue = VALUE_DRAW;
+ v->bikjangRule = true;
+ v->materialCounting = NO_MATERIAL_COUNTING;
return v;
}
// Casual rules of Janggi, where bikjang is not considered
Variant* janggi_casual_variant() {
Variant* v = janggi_variant();
- v->bikjangValue = VALUE_NONE;
+ v->bikjangRule = false;
+ v->materialCounting = JANGGI_MATERIAL;
return v;
}
#endif
Value checkmateValue = -VALUE_MATE;
bool shogiPawnDropMateIllegal = false;
bool shatarMateRule = false;
- Value bikjangValue = VALUE_NONE;
+ bool bikjangRule = false;
Value bareKingValue = VALUE_NONE;
Value extinctionValue = VALUE_NONE;
bool bareKingMove = false;
bool flagMove = false;
bool checkCounting = false;
int connectN = 0;
+ MaterialCounting materialCounting = NO_MATERIAL_COUNTING;
CountingRule countingRule = NO_COUNTING;
void add_piece(PieceType pt, char c, char c2 = ' ') {
# [PieceType]: a piece type [letters defined for pieces, e.g., p]
# [Bitboard]: list of squares [e.g., d4 e4 d5 e5]. * can be used as wildcard for files (e.g., *1 is the first rank)
# [Value]: game result for the side to move [win, loss, draw]
+# [MaterialCounting]: material couting rules for adjudication [janggi, unweighted, none]
# [CountingRule]: makruk or ASEAN counting rules [makruk, asean, none]
### Rule definition options
# checkmateValue: result in case of checkmate [Value] (default: loss)
# shogiPawnDropMateIllegal: prohibit checkmate via shogi pawn drops [bool] (default: false)
# shatarMateRule: enable shatar mating rules [bool] (default: false)
-# bikjangValue: result in case of Janggi bikjang (facing kings) for the player with more points [Value] (default: none)
+# bikjangRule: consider Janggi bikjang (facing kings) rule [bool] (default: false)
# bareKingValue: result when player only has a lone/bare king [Value] (default: none)
# extinctionValue: result when one of extinctionPieceTypes is extinct [Value] (default: none)
# bareKingMove: allow additional move by opponent after lone/bare king position [bool] (default: false)
# flagMove: black gets one more move after white captures the flag [bool] (default: false)
# checkCounting: enable check count win rule (check count is communicated via FEN, see 3check) [bool] (default: false)
# connectN: number of aligned pieces for win [int] (default: 0)
+# materialCounting: enable material counting rules [MaterialCounting] (default: none)
# countingRule: enable counting rules [CountingRule] (default: none)
################################################