Fix #7: Checkmate evaluation for shatar and shogi
authorFabian Fichter <ianfab@users.noreply.github.com>
Sun, 16 Sep 2018 21:52:52 +0000 (23:52 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sun, 16 Sep 2018 21:52:52 +0000 (23:52 +0200)
Evaluate illegal checkmates as losing.

src/position.cpp
src/position.h
src/search.cpp
src/types.h
src/variant.cpp
src/variant.h

index 9cc14b8..4e07e75 100644 (file)
@@ -444,6 +444,7 @@ void Position::set_check_info(StateInfo* si) const {
   for (PieceType pt = PAWN; pt < KING; ++pt)
       si->checkSquares[pt] = ksq != SQ_NONE ? attacks_from(~sideToMove, pt, ksq) : 0;
   si->checkSquares[KING]   = 0;
+  si->shak = si->checkersBB & (byTypeBB[KNIGHT] | byTypeBB[ROOK] | byTypeBB[BERS]);
 }
 
 
index 680a1f1..25ee85c 100644 (file)
@@ -59,6 +59,7 @@ struct StateInfo {
   Bitboard   pinners[COLOR_NB];
   Bitboard   checkSquares[PIECE_TYPE_NB];
   bool       capturedpromoted;
+  bool       shak;
 };
 
 /// A list to keep track of the position states along the setup moves (from the
@@ -368,34 +369,54 @@ inline bool Position::immobility_illegal() const {
 
 inline Value Position::stalemate_value(int ply) const {
   assert(var != nullptr);
-  Value v = var->stalemateValue;
-  return  v ==  VALUE_MATE ? mate_in(ply)
-        : v == -VALUE_MATE ? mated_in(ply)
-        : v;
+  return convert_mate_value(var->stalemateValue, ply);
 }
 
 inline Value Position::checkmate_value(int ply) const {
   assert(var != nullptr);
-  Value v = var->checkmateValue;
-  return  v ==  VALUE_MATE ? mate_in(ply)
-        : v == -VALUE_MATE ? mated_in(ply)
-        : v;
+  // Check for illegal mate by shogi pawn drop
+  if (    var->shogiPawnDropMateIllegal
+      && !(checkers() & ~pieces(SHOGI_PAWN))
+      && !st->capturedPiece
+      &&  st->pliesFromNull > 0
+      && (st->materialKey != st->previous->materialKey))
+  {
+      return mate_in(ply);
+  }
+  // Check for shatar mate rule
+  if (var->shatarMateRule)
+  {
+      // Mate by knight is illegal
+      if (!(checkers() & ~pieces(KNIGHT)))
+          return mate_in(ply);
+
+      StateInfo* stp = st;
+      while (stp->checkersBB)
+      {
+          // Return mate score if there is at least one shak in series of checks
+          if (stp->shak)
+              return convert_mate_value(var->checkmateValue, ply);
+
+          if (stp->pliesFromNull < 2)
+              break;
+
+          stp = stp->previous->previous;
+      }
+      // Niol
+      return VALUE_DRAW;
+  }
+  // Return mate value
+  return convert_mate_value(var->checkmateValue, ply);
 }
 
 inline Value Position::bare_king_value(int ply) const {
   assert(var != nullptr);
-  Value v = var->bareKingValue;
-  return  v ==  VALUE_MATE ? mate_in(ply)
-        : v == -VALUE_MATE ? mated_in(ply)
-        : v;
+  return convert_mate_value(var->bareKingValue, ply);
 }
 
 inline Value Position::extinction_value(int ply) const {
   assert(var != nullptr);
-  Value v = var->extinctionValue;
-  return  v ==  VALUE_MATE ? mate_in(ply)
-        : v == -VALUE_MATE ? mated_in(ply)
-        : v;
+  return convert_mate_value(var->extinctionValue, ply);
 }
 
 inline bool Position::bare_king_move() const {
index dd15427..d2646cc 100644 (file)
@@ -1401,7 +1401,7 @@ moves_loop: // When in check, search starts from here
     // All legal moves have been searched. A special case: If we're in check
     // and no legal moves were found, it is checkmate.
     if (inCheck && bestValue == -VALUE_INFINITE)
-        return mated_in(ss->ply); // Plies to mate from the root
+        return pos.checkmate_value(ss->ply); // Plies to mate from the root
 
     tte->save(posKey, value_to_tt(bestValue, ss->ply),
               PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER,
index 25834b7..3e2633c 100644 (file)
@@ -418,6 +418,12 @@ constexpr Value mated_in(int ply) {
   return -VALUE_MATE + ply;
 }
 
+constexpr Value convert_mate_value(Value v, int ply) {
+  return  v ==  VALUE_MATE ? mate_in(ply)
+        : v == -VALUE_MATE ? mated_in(ply)
+        : v;
+}
+
 constexpr Square make_square(File f, Rank r) {
   return Square((r << 3) + f);
 }
index 8da201a..79cdf38 100644 (file)
@@ -267,6 +267,7 @@ void VariantMap::init() {
         v->promotedPieceType[ROOK]             = DRAGON;
         v->mandatoryPiecePromotion = true;
         v->immobilityIllegal = true;
+        v->shogiPawnDropMateIllegal = true;
         return v;
     } ();
     const Variant* judkinsshogi = [&]{
@@ -296,6 +297,7 @@ void VariantMap::init() {
         v->promotedPieceType[BISHOP]       = HORSE;
         v->promotedPieceType[ROOK]         = DRAGON;
         v->immobilityIllegal = true;
+        v->shogiPawnDropMateIllegal = true;
         return v;
     } ();
     const Variant* minishogi = [&]{
@@ -323,6 +325,7 @@ void VariantMap::init() {
         v->promotedPieceType[BISHOP]     = HORSE;
         v->promotedPieceType[ROOK]       = DRAGON;
         v->immobilityIllegal = true;
+        v->shogiPawnDropMateIllegal = true;
         return v;
     } ();
     const Variant* losalamos = [&]{
@@ -363,8 +366,8 @@ void VariantMap::init() {
         v->endgameEval = true;
         v->doubleStep = false;
         v->castling = false;
-        v->bareKingValue = VALUE_DRAW;
-        // TODO: illegal checkmates
+        v->bareKingValue = VALUE_DRAW; // Robado
+        v->shatarMateRule = true;
         return v;
     } ();
     const Variant* clobber = [&]{
index a52196a..baf9d66 100644 (file)
@@ -57,6 +57,8 @@ struct Variant {
   // game end
   Value stalemateValue = VALUE_DRAW;
   Value checkmateValue = -VALUE_MATE;
+  bool shogiPawnDropMateIllegal = false;
+  bool shatarMateRule = false;
   Value bareKingValue = VALUE_NONE;
   Value extinctionValue = VALUE_NONE;
   bool bareKingMove = false;