const std::map<Direction, int> GrasshopperDirectionsH { {EAST, 1}, {WEST, 1} };
const std::map<Direction, int> GrasshopperDirectionsD { {NORTH_EAST, 1}, {SOUTH_EAST, 1}, {SOUTH_WEST, 1}, {NORTH_WEST, 1} };
- enum MovementType { RIDER, HOPPER, LAME_LEAPER, UNLIMITED_RIDER };
+ enum MovementType { RIDER, HOPPER, LAME_LEAPER, HOPPER_RANGE };
template <MovementType MT>
#ifdef PRECOMPUTED_MAGICS
if (MT != HOPPER || hurdle)
{
attack |= s;
- if (limit && MT != UNLIMITED_RIDER && ++count >= limit)
+ // For hoppers we consider limit == 1 as a grasshopper,
+ // but limit > 1 as a limited distance hopper
+ if (limit && !(MT == HOPPER_RANGE && limit == 1) && ++count >= limit)
break;
}
leaper |= safe_destination(s, c == WHITE ? d : -d);
}
pseudo |= sliding_attack<RIDER>(pi->slider[initial][modality], s, 0, c);
- pseudo |= sliding_attack<UNLIMITED_RIDER>(pi->hopper[initial][modality], s, 0, c);
+ pseudo |= sliding_attack<HOPPER_RANGE>(pi->hopper[initial][modality], s, 0, c);
}
}
}
// apply to the 64 or 32 bits word to get the index.
Magic& m = magics[s];
// The mask for hoppers is unlimited distance, even if the hopper is limited distance (e.g., grasshopper)
- m.mask = (MT == LAME_LEAPER ? lame_leaper_path(directions, s) : sliding_attack<MT == HOPPER ? UNLIMITED_RIDER : MT>(directions, s, 0)) & ~edges;
+ m.mask = (MT == LAME_LEAPER ? lame_leaper_path(directions, s) : sliding_attack<MT == HOPPER ? HOPPER_RANGE : MT>(directions, s, 0)) & ~edges;
#ifdef LARGEBOARDS
m.shift = 128 - popcount(m.mask);
#else
customPiece1 = a:pR
customPiece2 = c:mBcpB
customPiece3 = i:pB
-customPiece4 = w:mRpRFAcpR
-customPiece5 = f:mBpBWDcpB
+customPiece4 = w:mRpRmFpB2
+customPiece5 = f:mBpBmWpR2
promotedPieceType = u:w a:w c:f i:f
startFen = lnsgkgsnl/1rci1uab1/p1p1p1p1p/9/9/9/P1P1P1P1P/1BAU1ICR1/LNSGKGSNL[-] w 0 1
customPiece3 = c:hlN
customPiece4 = d:hrN
startFen = 7/7/7/3A3/7/7/7 w - - 0 1
+
+[cannonshogi:shogi]
+dropNoDoubled = -
+shogiPawnDropMateIllegal = false
+soldier = p
+cannon = u
+customPiece1 = a:pR
+customPiece2 = c:mBcpB
+customPiece3 = i:pB
+customPiece4 = w:mRpRmFpB2
+customPiece5 = f:mBpBmWpR2
+promotedPieceType = u:w a:w c:f i:f
+startFen = lnsgkgsnl/1rci1uab1/p1p1p1p1p/9/9/9/P1P1P1P1P/1BAU1ICR1/LNSGKGSNL[-] w 0 1
"""
sf.load_variant_config(ini_text)
result = sf.legal_moves("shogun", SHOGUN, ["c2c4", "b8c6", "b2b4", "b7b5", "c4b5", "c6b8"])
self.assertIn("b5b6+", result)
+ # In Cannon Shogi the FGC and FSC can also move one square diagonally and, besides,
+ # move or capture two squares diagonally, by leaping an adjacent piece.
+ fen = "lnsg1gsnl/1rc1kuab1/p1+A1p1p1p/3P5/6i2/6P2/P1P1P3P/1B1U1ICR1/LNSGKGSNL[] w - - 1 3"
+ result = sf.legal_moves("cannonshogi", fen, [])
+ # mF
+ self.assertIn("c7b6", result)
+ self.assertIn("c7d8", result)
+ self.assertNotIn("c7d6", result)
+ self.assertNotIn("c7b8", result)
+ # pB2
+ self.assertIn("c7a9", result)
+ self.assertIn("c7e5", result)
+ self.assertNotIn("c7a5", result)
+ self.assertNotIn("c7e9", result)
+ # verify distance limited to 2
+ self.assertNotIn("c7f4", result)
+ self.assertNotIn("c7g3", 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"])