Sittuyin promotion disables rank based promotion
authorFabian Fichter <ianfab@users.noreply.github.com>
Fri, 10 Dec 2021 21:44:27 +0000 (22:44 +0100)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sat, 11 Dec 2021 13:18:40 +0000 (14:18 +0100)
Handle mandatory pawn promotion more naturally by removing
the promotion rank workaround for Sittuyin and instead
explicitly disable rank based promotion in case of sittuyin promotion.

src/movegen.cpp
src/pawns.cpp
src/position.cpp
src/variant.cpp
src/variants.ini
test.py

index 7d11d74..e4afd83 100644 (file)
@@ -108,8 +108,7 @@ namespace {
     constexpr Direction UpRight  = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
     constexpr Direction UpLeft   = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
 
-    Bitboard TRank8BB = pos.mandatory_pawn_promotion() ? rank_bb(relative_rank(Us, pos.promotion_rank(), pos.max_rank()))
-                                                       : zone_bb(Us, pos.promotion_rank(), pos.max_rank());
+    Bitboard TRank8BB = pos.sittuyin_promotion() ? Bitboard(0) : zone_bb(Us, pos.promotion_rank(), pos.max_rank());
     Bitboard TRank7BB = shift<Down>(TRank8BB);
     // Define squares a pawn can pass during a double step
     Bitboard  TRank3BB =  forward_ranks_bb(Us, relative_rank(Us, pos.double_step_rank_min(), pos.max_rank()))
index e8ffe05..a18f653 100644 (file)
@@ -165,11 +165,11 @@ namespace {
 
         // Passed pawns will be properly scored later in evaluation when we have
         // full attack info.
-        if (passed && is_ok(s + Up) && (r < pos.promotion_rank() || !pos.mandatory_pawn_promotion()))
+        if (passed && is_ok(s + Up) && !pos.sittuyin_promotion())
             e->passedPawns[Us] |= s;
 
         // Score this pawn
-        if ((support | phalanx) && (r < pos.promotion_rank() || !pos.mandatory_pawn_promotion()))
+        if ((support | phalanx) && !pos.sittuyin_promotion())
         {
             int v =  Connected[r] * (2 + bool(phalanx) - bool(opposed)) * (r == RANK_2 && pos.captures_to_hand() ? 3 : 1)
                    + 22 * popcount(support);
index 239d961..d5dbd67 100644 (file)
@@ -1170,7 +1170,7 @@ bool Position::pseudo_legal(const Move m) const {
   {
       // We have already handled promotion moves, so destination
       // cannot be on the 8th/1st rank.
-      if (mandatory_pawn_promotion() && rank_of(to) == relative_rank(us, promotion_rank(), max_rank()))
+      if (mandatory_pawn_promotion() && rank_of(to) == relative_rank(us, promotion_rank(), max_rank()) && !sittuyin_promotion())
           return false;
 
       if (   !(pawn_attacks_bb(us, from) & pieces(~us) & to) // Not a capture
index f6ebc5a..fba1bf7 100644 (file)
@@ -512,7 +512,6 @@ namespace {
         v->whiteDropRegion = Rank1BB | Rank2BB | Rank3BB;
         v->blackDropRegion = Rank8BB | Rank7BB | Rank6BB;
         v->sittuyinRookDrop = true;
-        v->promotionRank = RANK_1; // no regular promotions
         v->sittuyinPromotion = true;
         v->promotionLimit[FERS] = 1;
         v->immobilityIllegal = false;
index ae834c9..719653d 100644 (file)
@@ -281,10 +281,13 @@ blackFlag = d4 e4 d5 e5
 mustCapture = true
 
 # Hybrid variant of makruk and crazyhouse
-[makrukhouse:makruk]
+[makhouse:makruk]
 startFen = rnsmksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKMSNR[] w - - 0 1
 pieceDrops = true
 capturesToHand = true
+firstRankPawnDrops = true
+promotionZonePawnDrops = true
+immobilityIllegal = true
 
 # Hybrid variant of xiangqi and crazyhouse
 [xiangqihouse:xiangqi]
diff --git a/test.py b/test.py
index cb580b5..8ba1b72 100644 (file)
--- a/test.py
+++ b/test.py
@@ -71,6 +71,14 @@ startFen = rbnkbr/pppppp/6/6/PPPPPP/RBNKBR w KQkq - 0 1
 
 [passchess:chess]
 pass = true
+
+[makhouse:makruk]
+startFen = rnsmksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKMSNR[] w - - 0 1
+pieceDrops = true
+capturesToHand = true
+firstRankPawnDrops = true
+promotionZonePawnDrops = true
+immobilityIllegal = true
 """
 
 sf.load_variant_config(ini_text)
@@ -286,6 +294,11 @@ class TestPyffish(unittest.TestCase):
         result = sf.legal_moves("janggi", fen, [])
         self.assertEqual(result, ["e10e10"])
 
+        # pawn promotion of dropped pawns beyond promotion rank
+        result = sf.legal_moves("makhouse", "rnsmksnr/8/1ppP1ppp/p3p3/8/PPP1PPPP/8/RNSKMSNR[p] w - - 0 4", [])
+        self.assertIn("d6d7m", result)
+        self.assertNotIn("d6d7", result)
+
     def test_short_castling(self):
         legals = ['f5f4', 'a7a6', 'b7b6', 'c7c6', 'd7d6', 'e7e6', 'i7i6', 'j7j6', 'a7a5', 'b7b5', 'c7c5', 'e7e5', 'i7i5', 'j7j5', 'b8a6', 'b8c6', 'h6g4', 'h6i4', 'h6j5', 'h6f7', 'h6g8', 'h6i8', 'd5a2', 'd5b3', 'd5f3', 'd5c4', 'd5e4', 'd5c6', 'd5e6', 'd5f7', 'd5g8', 'j8g8', 'j8h8', 'j8i8', 'e8f7', 'c8b6', 'c8d6', 'g6g2', 'g6g3', 'g6f4', 'g6g4', 'g6h4', 'g6e5', 'g6g5', 'g6i5', 'g6a6', 'g6b6', 'g6c6', 'g6d6', 'g6e6', 'g6f6', 'g6h8', 'f8f7', 'f8g8', 'f8i8']
         moves = ['b2b4', 'f7f5', 'c2c3', 'g8d5', 'a2a4', 'h8g6', 'f2f3', 'i8h6', 'h2h3']