Separate bikjang and material counting
authorFabian Fichter <ianfab@users.noreply.github.com>
Fri, 15 May 2020 15:27:42 +0000 (17:27 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Fri, 15 May 2020 15:27:42 +0000 (17:27 +0200)
Closes #115.

src/parser.cpp
src/position.cpp
src/position.h
src/types.h
src/variant.cpp
src/variant.h
src/variants.ini

index 0bfd656..f814862 100644 (file)
@@ -75,6 +75,13 @@ namespace {
         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
@@ -107,6 +114,7 @@ template <class T> void VariantParser<DoCheck>::parse_attribute(const std::strin
                                   : 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();
@@ -267,7 +275,7 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
     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);
@@ -292,6 +300,7 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
     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)
index c74f933..ac0d71e 100644 (file)
@@ -499,7 +499,7 @@ void Position::set_check_info(StateInfo* si) const {
       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;
 }
 
 
@@ -1961,21 +1961,12 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
           }
       }
   }
-  // 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
index 28d4aaa..4254f14 100644 (file)
@@ -164,6 +164,7 @@ public:
   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
@@ -256,6 +257,7 @@ public:
   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;
@@ -718,6 +720,11 @@ inline CheckCount Position::checks_remaining(Color c) 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;
@@ -1081,6 +1088,30 @@ inline bool Position::bikjang() const {
   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]++;
index a17be28..31a97ae 100644 (file)
@@ -274,6 +274,10 @@ enum CheckCount : int {
   CHECKS_0 = 0, CHECKS_NB = 11
 };
 
+enum MaterialCounting {
+  NO_MATERIAL_COUNTING, JANGGI_MATERIAL, UNWEIGHTED_MATERIAL
+};
+
 enum CountingRule {
   NO_COUNTING, MAKRUK_COUNTING, ASEAN_COUNTING
 };
@@ -700,7 +704,7 @@ inline bool is_gating(Move m) {
 }
 
 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) {
index 8e0b517..621cfe0 100644 (file)
@@ -872,7 +872,8 @@ namespace {
         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;
@@ -883,13 +884,15 @@ namespace {
     // 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
index dfcf556..d9191f7 100644 (file)
@@ -103,7 +103,7 @@ struct Variant {
   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;
@@ -116,6 +116,7 @@ struct Variant {
   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 = ' ') {
index 815e140..99448e6 100644 (file)
@@ -93,6 +93,7 @@
 # [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)
 
 ################################################