return n == NOTATION_SHOGI_HOSKING || n == NOTATION_SHOGI_HODGES || n == NOTATION_SHOGI_HODGES_NUMBER;
}
+// is there more than one file with a pair of pieces?
+inline bool multi_tandem(Bitboard b) {
+ int tandems = 0;
+ for (File f = FILE_A; f <= FILE_MAX; ++f)
+ if (more_than_one(b & file_bb(f)))
+ tandems++;
+ return tandems >= 2;
+}
+
inline std::string piece(const Position& pos, Move m, Notation n) {
Color us = pos.side_to_move();
Square from = from_sq(m);
if ((n == NOTATION_SAN || n == NOTATION_LAN) && type_of(pc) == PAWN && type_of(m) != DROP)
return "";
// Tandem pawns
- else if (n == NOTATION_XIANGQI_WXF && popcount(pos.pieces(us, pt) & file_bb(from)) > 2)
+ else if (n == NOTATION_XIANGQI_WXF && popcount(pos.pieces(us, pt) & file_bb(from)) >= 3 - multi_tandem(pos.pieces(us, pt)))
return std::to_string(popcount(forward_file_bb(us, from) & pos.pieces(us, pt)) + 1);
// Moves of promoted pieces
else if (is_shogi(n) && type_of(m) != DROP && pos.unpromoted_piece_on(from))
case NOTATION_XIANGQI_WXF:
{
if (pos.empty(s))
+ // Handle piece drops
return std::to_string(relative_rank(pos.side_to_move(), s, pos.max_rank()) + 1);
else if (pos.pieces(pos.side_to_move(), type_of(pos.piece_on(s))) & forward_file_bb(pos.side_to_move(), s))
return "-";
if (n == NOTATION_XIANGQI_WXF)
{
// Disambiguate by rank (+/-) if target square of other piece is valid
- if (popcount(pos.pieces(us, pt) & file_bb(from)) == 2)
+ if (popcount(pos.pieces(us, pt) & file_bb(from)) == 2 && !multi_tandem(pos.pieces(us, pt)))
{
Square otherFrom = lsb((pos.pieces(us, pt) & file_bb(from)) ^ from);
Square otherTo = otherFrom + Direction(to) - Direction(from);
self.assertEqual(result, "R1+1")
# skip disambiguation for elephants and advisors, but not for pieces that require it
- fen = "rnbakabnr/9/1c5c1/p1p1p1p1p/9/1NB6/P1P1P1P1P/1C1A3C1/9/RNBAK21R w - - 0 1"
+ fen = "rnbakabnr/9/1c5c1/p1p1p1p1p/4P4/1NB6/P1P1P3P/1C1A3C1/9/RNBAK4 w - - 0 1"
result = sf.get_san("xiangqi", fen, "c5e3", False, sf.NOTATION_XIANGQI_WXF)
self.assertEqual(result, "E7-5")
result = sf.get_san("xiangqi", fen, "d1e2", False, sf.NOTATION_XIANGQI_WXF)
self.assertEqual(result, "A6+5")
result = sf.get_san("xiangqi", fen, "b5c7", False, sf.NOTATION_XIANGQI_WXF)
self.assertEqual(result, "H++7")
+ result = sf.get_san("xiangqi", fen, "e6e7", False, sf.NOTATION_XIANGQI_WXF)
+ self.assertEqual(result, "P++1")
+ result = sf.get_san("xiangqi", fen, "e4e5", False, sf.NOTATION_XIANGQI_WXF)
+ self.assertEqual(result, "P-+1")
# Tandem pawns
fen = "rnbakabnr/9/1c5c1/p1p1P1p1p/4P4/9/P3P3P/1C5C1/9/RNBAKABNR w - - 0 1"
result = sf.get_san("xiangqi", fen, "e7d7", False, sf.NOTATION_XIANGQI_WXF)
self.assertEqual(result, "15=6")
+ result = sf.get_san("xiangqi", fen, "e6d6", False, sf.NOTATION_XIANGQI_WXF)
+ self.assertEqual(result, "25=6")
+ result = sf.get_san("xiangqi", fen, "e4e5", False, sf.NOTATION_XIANGQI_WXF)
+ self.assertEqual(result, "35+1")
+
+ # use tandem pawn notation for pair of tandem pawns
+ fen = "5k3/9/3P5/3P1P1P1/5P3/9/9/9/9/4K4 w - - 0 1"
+ result = sf.get_san("xiangqi", fen, "d7e7", False, sf.NOTATION_XIANGQI_WXF)
+ self.assertEqual(result, "26=5")
+ result = sf.get_san("xiangqi", fen, "f6e6", False, sf.NOTATION_XIANGQI_WXF)
+ self.assertEqual(result, "24=5")
fen = "1rb1ka2r/4a4/2ncb1nc1/p1p1p1p1p/9/2P6/P3PNP1P/2N1C2C1/9/R1BAKAB1R w - - 1 7"
result = sf.get_san("xiangqi", fen, "c3e2")