Skip to content

Commit 5809b28

Browse files
committed
Add variant specific notation to Tori Shogi
1 parent 9880b5e commit 5809b28

2 files changed

Lines changed: 98 additions & 10 deletions

File tree

src/apiutil.h

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ inline std::string piece_to_shogi_japanese_char(PieceType pt, bool promoted) {
179179
}
180180
}
181181

182+
inline bool is_dobutsu_variant(const Variant* v) {
183+
return v && (v->pieceTypes & piece_set(WAZIR));
184+
}
185+
182186
// Dobutsu shogi animal names (hiragana)
183187
inline std::string piece_to_dobutsu_kanji(PieceType pt, bool promoted) {
184188
if (promoted) {
@@ -204,6 +208,55 @@ inline std::string piece_to_dobutsu_kanji(PieceType pt, bool promoted) {
204208
}
205209
}
206210

211+
inline bool is_torishogi_variant(const Variant* v) {
212+
return v
213+
&& v->variantTemplate == "shogi"
214+
&& v->maxFile == FILE_G
215+
&& v->maxRank == RANK_7
216+
&& v->pieceToChar[make_piece(WHITE, SHOGI_PAWN)] == 'S'
217+
&& v->pieceToChar[make_piece(WHITE, KING)] == 'K'
218+
&& v->pieceToChar[make_piece(WHITE, CUSTOM_PIECE_1)] == 'F'
219+
&& v->pieceToChar[make_piece(WHITE, CUSTOM_PIECE_2)] == 'C'
220+
&& v->pieceToChar[make_piece(WHITE, CUSTOM_PIECE_3)] == 'L'
221+
&& v->pieceToChar[make_piece(WHITE, CUSTOM_PIECE_4)] == 'R'
222+
&& v->pieceToChar[make_piece(WHITE, CUSTOM_PIECE_5)] == 'P'
223+
&& v->pieceToChar[make_piece(WHITE, CUSTOM_PIECE_6)] == 'G'
224+
&& v->pieceToChar[make_piece(WHITE, CUSTOM_PIECE_7)] == 'E';
225+
}
226+
227+
inline std::string piece_to_torishogi_kanji(PieceType pt, bool promoted) {
228+
if (promoted) {
229+
switch (pt) {
230+
case CUSTOM_PIECE_1:
231+
case CUSTOM_PIECE_7: return "\u9d70"; // 鵰 (eagle)
232+
case SHOGI_PAWN:
233+
case CUSTOM_PIECE_6: return "\u9d08"; // 鴈 (goose)
234+
default: return "?";
235+
}
236+
} else {
237+
switch (pt) {
238+
case KING: return "\u9d6c"; // 鵬 (phoenix)
239+
case CUSTOM_PIECE_1: return "\u9df9"; // 鷹 (falcon)
240+
case CUSTOM_PIECE_2: return "\u9db4"; // 鶴 (crane)
241+
case CUSTOM_PIECE_3:
242+
case CUSTOM_PIECE_4: return "\u9d89"; // 鶉 (quail)
243+
case CUSTOM_PIECE_5: return "\u96c9"; // 雉 (pheasant)
244+
case SHOGI_PAWN: return "\u71d5"; // 燕 (swallow)
245+
case CUSTOM_PIECE_6: return "\u9d08"; // 鴈 (goose)
246+
case CUSTOM_PIECE_7: return "\u9d70"; // 鵰 (eagle)
247+
default: return "?";
248+
}
249+
}
250+
}
251+
252+
inline std::string piece_to_shogi_family_japanese_char(const Variant* v, PieceType pt, bool promoted) {
253+
if (is_torishogi_variant(v))
254+
return piece_to_torishogi_kanji(pt, promoted);
255+
if (is_dobutsu_variant(v))
256+
return piece_to_dobutsu_kanji(pt, promoted);
257+
return piece_to_shogi_japanese_char(pt, promoted);
258+
}
259+
207260
inline std::string piece_to_janggi_korean_char(Piece pc, Color c) {
208261
switch (type_of(pc)) {
209262
case KING: return c == WHITE ? "\u5c07" : "\u5e2b"; // 將 (Han) / 帥 (Cho)
@@ -231,8 +284,7 @@ inline std::string piece(const Position& pos, Move m, Notation n) {
231284
// Japanese Shogi notation: kanji pieces
232285
else if (n == NOTATION_SHOGI_JAPANESE)
233286
{
234-
// Detect dobutsu by checking if WAZIR is in the variant's piece types
235-
bool isDobutsu = pos.variant()->pieceTypes & piece_set(WAZIR);
287+
const Variant* variant = pos.variant();
236288
// For pieceDemotion variants (e.g. kyotoshogi), pieces swap between paired types
237289
// on promotion/demotion. Show the piece's identity after the move.
238290
// For promoted pieces (non-drop)
@@ -251,11 +303,10 @@ inline std::string piece(const Position& pos, Move m, Notation n) {
251303
case SHOGI_KNIGHT: return "\u91d1"; // 金 (gold)
252304
case SHOGI_PAWN: return "\u98db"; // 飛 (rook)
253305
case SILVER: return "\u89d2"; // 角 (bishop)
254-
default: return piece_to_shogi_japanese_char(pt, false);
306+
default: return piece_to_shogi_family_japanese_char(variant, pt, false);
255307
}
256308
}
257-
return isDobutsu ? piece_to_dobutsu_kanji(origPt, true)
258-
: piece_to_shogi_japanese_char(origPt, true);
309+
return piece_to_shogi_family_japanese_char(variant, origPt, true);
259310
}
260311
// For promoted drops
261312
else if (type_of(m) == DROP && dropped_piece_type(m) != in_hand_piece_type(m))
@@ -269,12 +320,11 @@ inline std::string piece(const Position& pos, Move m, Notation n) {
269320
case SHOGI_KNIGHT: return "\u91d1"; // 金 (gold)
270321
case SHOGI_PAWN: return "\u98db"; // 飛 (rook)
271322
case SILVER: return "\u89d2"; // 角 (bishop)
272-
default: return piece_to_shogi_japanese_char(pt, false);
323+
default: return piece_to_shogi_family_japanese_char(variant, pt, false);
273324
}
274325
}
275326
PieceType inHand = in_hand_piece_type(m);
276-
return isDobutsu ? piece_to_dobutsu_kanji(inHand, true)
277-
: piece_to_shogi_japanese_char(inHand, true);
327+
return piece_to_shogi_family_japanese_char(variant, inHand, true);
278328
}
279329
// For unpromoted pieces
280330
else
@@ -295,8 +345,7 @@ inline std::string piece(const Position& pos, Move m, Notation n) {
295345
default: break;
296346
}
297347
}
298-
return isDobutsu ? piece_to_dobutsu_kanji(pt, promotedOnBoard)
299-
: piece_to_shogi_japanese_char(pt, promotedOnBoard);
348+
return piece_to_shogi_family_japanese_char(variant, pt, promotedOnBoard);
300349
}
301350
}
302351
// Moves of promoted pieces

tests/js/test.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ before(() => {
33
return new Promise((resolve) => {
44
pgnDir = __dirname + '/../pgn/';
55
srcDir = __dirname + '/../../src/';
6+
// Node 24 exposes fetch globally, but the generated loader passes a plain
7+
// filesystem path to it for the local wasm file. Force the Node FS path.
8+
global.fetch = undefined;
69
ffish = require('./ffish.js');
710
WHITE = true;
811
BLACK = false;
@@ -300,6 +303,42 @@ describe('board.sanMove(ffish.Notation)', function () {
300303
chai.expect(shogiBoard.sanMove("g7g6", ffish.Notation.SHOGI_JAPANESE, "d9e8")).to.equal("\uff13\u56db\u6b69"); // 3四歩
301304
shogiBoard.delete();
302305

306+
const toriBoard = new ffish.Board("torishogi");
307+
chai.expect(toriBoard.sanMove("a3a4", ffish.Notation.SHOGI_JAPANESE)).to.equal("\uff17\u56db\u71d5"); // 7四燕
308+
toriBoard.delete();
309+
310+
const toriPhoenixBoard = new ffish.Board("torishogi", "3k3/7/7/7/7/7/3K3[-] w 0 1");
311+
chai.expect(toriPhoenixBoard.sanMove("d1d2", ffish.Notation.SHOGI_JAPANESE)).to.equal("\uff14\u516d\u9d6c"); // 4六鵬
312+
toriPhoenixBoard.delete();
313+
314+
const toriBirdBoard = new ffish.Board("torishogi", "3k3/7/7/7/3C3/7/3K3[-] w 0 1");
315+
chai.expect(toriBirdBoard.sanMove("d3d4", ffish.Notation.SHOGI_JAPANESE)).to.equal("\uff14\u56db\u9db4"); // 4四鶴
316+
toriBirdBoard.delete();
317+
318+
const toriQuailBoard = new ffish.Board("torishogi", "3k3/7/7/7/3L3/7/3K3[-] w 0 1");
319+
chai.expect(toriQuailBoard.sanMove("d3d4", ffish.Notation.SHOGI_JAPANESE)).to.equal("\uff14\u56db\u9d89"); // 4四鶉
320+
toriQuailBoard.delete();
321+
322+
const toriPheasantBoard = new ffish.Board("torishogi", "3k3/7/7/7/3P3/7/3K3[-] w 0 1");
323+
chai.expect(toriPheasantBoard.sanMove("d3c2", ffish.Notation.SHOGI_JAPANESE)).to.equal("\uff15\u516d\u96c9"); // 5六雉
324+
toriPheasantBoard.delete();
325+
326+
const toriPromotionBoard = new ffish.Board("torishogi", "3k3/7/3S3/7/7/7/3K3[-] w 0 1");
327+
chai.expect(toriPromotionBoard.sanMove("d5d6+", ffish.Notation.SHOGI_JAPANESE)).to.equal("\uff14\u4e8c\u71d5\u6210"); // 4二燕成
328+
toriPromotionBoard.delete();
329+
330+
const toriPromotedBoard = new ffish.Board("torishogi", "3k3/7/7/7/3+S3/7/3K3[-] w 0 1");
331+
chai.expect(toriPromotedBoard.sanMove("d3b5", ffish.Notation.SHOGI_JAPANESE)).to.equal("\uff16\u4e09\u9d08"); // 6三鴈
332+
toriPromotedBoard.delete();
333+
334+
const toriFalconPromotionBoard = new ffish.Board("torishogi", "3k3/7/3F3/7/7/7/3K3[-] w 0 1");
335+
chai.expect(toriFalconPromotionBoard.sanMove("d5d6+", ffish.Notation.SHOGI_JAPANESE)).to.equal("\uff14\u4e8c\u9df9\u6210"); // 4二鷹成
336+
toriFalconPromotionBoard.delete();
337+
338+
const toriEagleBoard = new ffish.Board("torishogi", "3k3/7/7/7/3+F3/7/3K3[-] w 0 1");
339+
chai.expect(toriEagleBoard.sanMove("d3d4", ffish.Notation.SHOGI_JAPANESE)).to.equal("\uff14\u56db\u9d70"); // 4四鵰
340+
toriEagleBoard.delete();
341+
303342
board.delete();
304343
});
305344
});

0 commit comments

Comments
 (0)