Implement correct Cambodian opening moves (#514)
authorAda Joule <ada.fulmina@gmail.com>
Sat, 17 Sep 2022 13:59:48 +0000 (20:59 +0700)
committerGitHub <noreply@github.com>
Sat, 17 Sep 2022 13:59:48 +0000 (15:59 +0200)
Article 5, Items 3 and 4
https://docs.google.com/document/d/1adppJ66vonM27UYwC-KyldXl7oZ_5Pb0/edit?usp=sharing&ouid=116281580550740302191&rtpof=true&sd=true

- The king now loses the ability to leap if an enemy rook moves into the
  same rank or file
- The ferz can no longer capture with its leap

src/movegen.cpp
src/position.cpp
test.py
tests/perft.sh

index ee9039a..b8e1d1a 100644 (file)
@@ -356,13 +356,13 @@ namespace {
         }
 
         // Special moves
-        if (pos.cambodian_moves() && pos.gates(Us))
+        if (pos.cambodian_moves() && pos.gates(Us) && Type != CAPTURES)
         {
-            if (Type != CAPTURES && Type != EVASIONS && (pos.pieces(Us, KING) & pos.gates(Us)))
+            if (Type != EVASIONS && (pos.pieces(Us, KING) & pos.gates(Us)))
             {
                 Square from = pos.square<KING>(Us);
                 Bitboard b = PseudoAttacks[WHITE][KNIGHT][from] & rank_bb(rank_of(from + (Us == WHITE ? NORTH : SOUTH)))
-                            & target & ~pos.pieces();
+                    & target & ~pos.pieces();
                 while (b)
                     moveList = make_move_and_gating<SPECIAL>(pos, moveList, Us, from, pop_lsb(b));
             }
@@ -372,7 +372,7 @@ namespace {
             {
                 Square from = pop_lsb(b);
                 Square to = from + 2 * (Us == WHITE ? NORTH : SOUTH);
-                if (is_ok(to) && (target & to))
+                if (is_ok(to) && (target & to & ~pos.pieces()))
                     moveList = make_move_and_gating<SPECIAL>(pos, moveList, Us, from, to);
             }
         }
index 966766e..1135563 100644 (file)
@@ -911,14 +911,6 @@ Bitboard Position::attackers_to(Square s, Bitboard occupied, Color c, Bitboard j
               b |= attacks_bb(~c, move_pt, s, occupied) & pieces(c, pt);
       }
 
-  // Consider special move of neang in cambodian chess
-  if (cambodian_moves())
-  {
-      Square fers_sq = s + 2 * (c == WHITE ? SOUTH : NORTH);
-      if (is_ok(fers_sq))
-          b |= pieces(c, FERS) & gates(c) & fers_sq;
-  }
-
   // Janggi palace moves
   if (diagonal_lines() & s)
   {
@@ -1772,6 +1764,10 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
           st->gatesBB[us] = 0;
   }
 
+  // Remove king leaping right when aimed by a rook
+  if (cambodian_moves() && type_of(pc) == ROOK && (square<KING>(them) & gates(them) & attacks_bb<ROOK>(to)))
+      st->gatesBB[them] ^= square<KING>(them);
+
   // Remove the blast pieces
   if (captured && blast_on_capture())
   {
diff --git a/test.py b/test.py
index 8ea4620..f56635d 100644 (file)
--- a/test.py
+++ b/test.py
@@ -12,6 +12,7 @@ CAPA = "rnabqkbcnr/pppppppppp/10/10/10/10/PPPPPPPPPP/RNABQKBCNR w KQkq - 0 1"
 CAPAHOUSE = "rnabqkbcnr/pppppppppp/10/10/10/10/PPPPPPPPPP/RNABQKBCNR[] w KQkq - 0 1"
 SITTUYIN = "8/8/4pppp/pppp4/4PPPP/PPPP4/8/8[KFRRSSNNkfrrssnn] w - - 0 1"
 MAKRUK = "rnsmksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKMSNR w - - 0 1"
+CAMBODIAN = "rnsmksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKMSNR w DEde - 0 1"
 SHOGI = "lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL[-] w - - 0 1"
 SHOGI_SFEN = "lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1"
 SEIRAWAN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[EHeh] w KQBCDFGkqbcdfg - 0 1"
@@ -289,6 +290,13 @@ class TestPyffish(unittest.TestCase):
         result = sf.legal_moves("shogun", SHOGUN, ["c2c4", "b8c6", "b2b4", "b7b5", "c4b5", "c6b8"])
         self.assertIn("b5b6+", result)
 
+        # Cambodian queen cannot capture with its leap
+        # Cambodian king cannot leap to escape check
+        result = sf.legal_moves("cambodian", CAMBODIAN, ["b1d2", "g8e7", "d2e4", "d6d5", "e4d6"])
+        self.assertNotIn("d8d6", result)
+        self.assertNotIn("e8g7", result)
+        self.assertNotIn("e8c7", result)
+
         # In Janggi stalemate position pass move (in place king move) is possible
         fen = "4k4/c7R/9/3R1R3/9/9/9/9/9/3K5 b - - 0 1"
         result = sf.legal_moves("janggi", fen, [])
@@ -522,6 +530,22 @@ class TestPyffish(unittest.TestCase):
         result = sf.get_fen("asean", fen, moves, False, False, False)
         self.assertEqual(result, "3QQ3/8/4K3/3Q4/1k6/8/8/8 b - - 0 1")
 
+        # Cambodian king loses its leap ability when it is "aimed" by a rook
+        fen = "rnsmk1nr/4s3/pppppppp/8/8/PPPPPPPP/R7/1NSKMSNR w DEde - 2 2"
+        moves = ["a2e2"]
+        result = sf.get_fen("cambodian", fen, moves, False, False, True)
+        self.assertEqual(result, "rnsmk1nr/4s3/pppppppp/8/8/PPPPPPPP/4R3/1NSKMSNR b DEd - 3 2")
+
+        fen = "1nsmksnr/r7/pppppppp/8/8/PPPPPPPP/2SN4/R2KMSNR b DEde - 3 2"
+        moves = ["a7d7"]
+        result = sf.get_fen("cambodian", fen, moves, False, False, True)
+        self.assertEqual(result, "1nsmksnr/3r4/pppppppp/8/8/PPPPPPPP/2SN4/R2KMSNR w Ede - 4 3")
+
+        fen = "rnsmksnr/8/1ppppppp/8/8/1PPPPPPP/8/RNSKMSNR w DEde - 0 1"
+        moves = ["a1a8"]
+        result = sf.get_fen("cambodian", fen, moves, False, False, True)
+        self.assertEqual(result, "Rnsmksnr/8/1ppppppp/8/8/1PPPPPPP/8/1NSKMSNR b DEd - 0 1")
+
     def test_get_san(self):
         fen = "4k3/8/3R4/8/1R3R2/8/3R4/4K3 w - - 0 1"
         result = sf.get_san("chess", fen, "b4d4")
index 9f00fa7..a34d052 100755 (executable)
@@ -40,9 +40,9 @@ if [[ $1 == "all" || $1 == "variant" ]]; then
   expect perft.exp losalamos "fen 6/2P3/6/1K1k2/6/6 w - - 0 1" 6 187431 > /dev/null
   # fairy
   expect perft.exp makruk startpos 4 273026 > /dev/null
-  expect perft.exp cambodian startpos 4 361793 > /dev/null
+  expect perft.exp cambodian startpos 4 361719 > /dev/null
   expect perft.exp cambodian "fen r1s1ks1r/3nm3/pppNpppp/3n4/5P2/PPPPPNPP/8/R1SKMS1R b DEe 0 0 5" 2 72 > /dev/null
-  expect perft.exp karouk "fen rn1mksnr/3s4/pppppppp/8/4N3/PPPPPPPP/8/R1SKMSNR b DEde - 3 2" 4 358535 > /dev/null
+  expect perft.exp karouk "fen rn1mksnr/3s4/pppppppp/8/4N3/PPPPPPPP/8/R1SKMSNR b DEde - 3 2" 4 358460 > /dev/null
   expect perft.exp makpong "fen 3mk3/r3s1R1/1psppnp1/p1pn4/1P2NP2/P1PPP1P1/4NS2/R1SKM3 w - - 0 1" 4 593103 > /dev/null
   expect perft.exp asean startpos 4 273026 > /dev/null
   expect perft.exp ai-wok startpos 4 485045 > /dev/null