This is the move_to_san() routine from SjaakII,matthewlai wrote: That is how I do it, too, but it's easy to forget checking for piece types for kings (castling) and pawns (which require special handling for promotions and always need file).
It's also easy to forget that file-disambiguation should be preferred, and that may take a while to catch, since it doesn't usually matter.
Code: Select all
const char *move_to_san(move_t move, const movelist_t *movelist, char *buffer, bool san_castle)
{
static char static_buffer[256];
char *s = buffer;
const char *gate_token = "";
const char *token = "";
const char *origin = "";
char piece = ' ';
char tp = '\0';
if (!s) s = static_buffer;
if (move == 0) {
snprintf(s, sizeof static_buffer, "(pass)");
return s;
}
int from = get_move_from(move);
int to = get_move_to(move);
int p = get_move_piece(move);
piece = piece_symbol_string[p];
if (san_castle && is_castle_move(move)) {
int f = unpack_file(to);
if (f >= div_file)
snprintf(s, sizeof static_buffer, "%s", kingside_castle);
else
snprintf(s, sizeof static_buffer, "%s", queenside_castle);
if (is_gate_move(move)) {
snprintf(s + strlen(s), 256-strlen(s), "/%c%s", piece_symbol_string[get_move_promotion_piece(move)], square_names[get_move_drop_square(move)]);
}
return s;
}
if (abs(from-to) == 1 && is_castle_move(move)) {
int from2 = get_castle_move_from2(move);
int to2 = get_castle_move_to2(move);
snprintf(s, sizeof static_buffer, "%cx%s-%s", piece, square_names[from2], square_names[to]);
return s;
}
if (is_capture_move(move)) token = "x";
if (is_drop_move(move)) token = "@";
if (is_promotion_move(move) || is_gate_move(move)) tp = piece_symbol_string[get_move_promotion_piece(move)];
if (is_gate_move(move)) gate_token = "/";
if (is_double_capture_move(move)) {
int from = get_move_from(move);
int to = get_move_to(move);
char fp = piece;
int first = 1;
int c1, c2;
uint16_t p = 0;
if (get_move_swaps(move))
first = 0;
p = get_move_pickup(move, first);
c1 = decode_pickup_square(p);
p = get_move_pickup(move, first+1);
c2 = decode_pickup_square(p);
if (c2 == to) {
snprintf(s, 256, "%c%sx%sx%s", fp, square_names[from], square_names[c1], square_names[to]);
} else {
snprintf(s, 256, "%c%sx%sx%s-%s", fp, square_names[from], square_names[c1], square_names[c2], square_names[to]);
}
return s;
}
if (piece != ' ' && is_capture_move(move) && !is_double_capture_move(move) && get_move_capture_square(move)!=get_move_to(move)) {
int from = get_move_from(move);
int to = get_move_to(move);
int cap = get_move_capture_square(move);
char fp = piece_symbol_string[get_move_piece(move)];
snprintf(s, 256, "%c%sx%s-%s", fp, "", square_names[cap], square_names[to]);
return s;
}
if (is_drop_move(move)) piece = piece_drop_string[p];
if (is_pickup_move(move)) {
piece = piece_drop_string[p];
token = "^";
to = from;
goto disambiguous;
}
if (is_drop_move(move)) goto disambiguous;
/* Slightly special case: pawn capture */
if (piece == ' ' && is_capture_move(move)) {
origin = file_names[unpack_file(from)];
} else if (movelist) {
/* The information we have now might be ambiguous - check */
int count = 0;
int n;
for (n=0; n<movelist->num_moves; n++) {
if (is_drop_move(movelist->move[n])) continue;
if (is_capture_move(movelist->move[n]) && !is_capture_move(move)) continue;
if (!is_capture_move(movelist->move[n]) && is_capture_move(move)) continue;
if (is_double_capture_move(movelist->move[n]) && !is_double_capture_move(move)) continue;
if (!is_double_capture_move(movelist->move[n]) && is_double_capture_move(move)) continue;
if (get_move_piece(move) == get_move_piece(movelist->move[n]) && to == get_move_to(movelist->move[n])) {
if (is_promotion_move(move) && is_promotion_move(movelist->move[n]))
count += tp == piece_symbol_string[get_move_promotion_piece(movelist->move[n])];
else if (!is_promotion_move(move) && !is_promotion_move(movelist->move[n])) {
if (is_gate_move(move) && is_gate_move(movelist->move[n]))
count += tp == piece_symbol_string[get_move_promotion_piece(movelist->move[n])];
else if (!is_gate_move(move) && !is_gate_move(movelist->move[n]))
count++;
}
}
}
if (count <= 1) goto disambiguous;
/* Try to disambiguate by file */
count = 0;
for (n=0; n<movelist->num_moves; n++) {
if (is_drop_move(movelist->move[n])) continue;
if (get_move_piece(move) == get_move_piece(movelist->move[n]) &&
to == get_move_to(movelist->move[n]) &&
unpack_file(from) == unpack_file(get_move_from(movelist->move[n])))
count++;
}
if (count == 1) {
origin = file_names[unpack_file(from)];
} else if (count > 1) {
/* Disambiguate by row */
origin = rank_names[unpack_rank(from)];
}
}
disambiguous:
snprintf(s, 15, "%c%s%s%s%s%c", piece, origin, token, square_names[to], gate_token, tp);
if (piece == '+') {
if (tp) tp = '+';
snprintf(s, 15, "%c%c%s%s%s%s%c", piece, piece_psymbol_string[p], origin, token, square_names[to], gate_token, tp);
}
return s;
}
EDIT:
This is the output (second column, the others are other move formats it understands) that it gives for the second position you specified:
Code: Select all
73 moves
1/ 73 Na3-b1 Nb1 a3b1 a3b1
2/ 73 Na3-c2 Nac2 a3c2 a3c2
3/ 73 Na3-c4 Nac4 a3c4 a3c4
4/ 73 Na3-b5 Nb5 a3b5 a3b5
5/ 73 Ne3-d1 Nd1 e3d1 e3d1
6/ 73 Ne3-f1 Nf1 e3f1 e3f1
7/ 73 Ne3-c2 Nec2 e3c2 e3c2
8/ 73 Ne3-c4 Nec4 e3c4 e3c4
9/ 73 Ne3-g4 Ng4 e3g4 e3g4
10/ 73 Ne3-d5 Nd5 e3d5 e3d5
11/ 73 c7xb8Q cxb8Q c7b8q c7b8q
12/ 73 c7xb8R cxb8R c7b8r c7b8r
13/ 73 c7xb8B cxb8B c7b8b c7b8b
14/ 73 c7xb8N cxb8N c7b8n c7b8n
15/ 73 f5xe6 fxe6 f5e6 f5e6
16/ 73 d4xe5 dxe5 d4e5 d4e5
17/ 73 g2-g4 g4 g2g4 g2g4
18/ 73 Nd8-e6 Ne6 d8e6 d8e6
19/ 73 Nd8xb7 Nxb7 d8b7 d8b7
20/ 73 Ba6-f1 Bf1 a6f1 a6f1
21/ 73 Ba6-e2 Be2 a6e2 a6e2
22/ 73 Ba6-d3 Bd3 a6d3 a6d3
23/ 73 Ba6-c4 Bc4 a6c4 a6c4
24/ 73 Ba6-b5 Bab5 a6b5 a6b5
25/ 73 Ba6xb7 B6xb7 a6b7 a6b7
26/ 73 Bc6-a4 Ba4 c6a4 c6a4
27/ 73 Bc6-b5 Bcb5 c6b5 c6b5
28/ 73 Bc6-d5 Bd5 c6d5 c6d5
29/ 73 Bc6xb7 Bcxb7 c6b7 c6b7
30/ 73 Bc6xd7 Bxd7 c6d7 c6d7
31/ 73 Ba8xb7 B8xb7 a8b7 a8b7
32/ 73 Rh1-f1 Rf1 h1f1 h1f1
33/ 73 Rh1-g1 Rg1 h1g1 h1g1
34/ 73 Rh1-h2 R1h2 h1h2 h1h2
35/ 73 Rh1-h3 R1h3 h1h3 h1h3
36/ 73 Re4-f4 Ref4 e4f4 e4f4
37/ 73 Re4-g4 Reg4 e4g4 e4g4
38/ 73 Re4xe5 Rxe5 e4e5 e4e5
39/ 73 Rh4-h2 R4h2 h4h2 h4h2
40/ 73 Rh4-h3 R4h3 h4h3 h4h3
41/ 73 Rh4-f4 Rhf4 h4f4 h4f4
42/ 73 Rh4-g4 Rhg4 h4g4 h4g4
43/ 73 Rh4-h5 R4h5 h4h5 h4h5
44/ 73 Rh6-h5 R6h5 h6h5 h6h5
45/ 73 Rh6xh7 R6xh7 h6h7 h6h7
46/ 73 Rf7-e7 Re7 f7e7 f7e7
47/ 73 Rf7-g7 Rg7 f7g7 f7g7
48/ 73 Rf7-f8 Rff8 f7f8 f7f8
49/ 73 Rf7xd7 Rxd7 f7d7 f7d7
50/ 73 Rf7xh7 Rfxh7 f7h7 f7h7
51/ 73 Rh8-e8 Re8 h8e8 h8e8
52/ 73 Rh8-f8 Rhf8 h8f8 h8f8
53/ 73 Rh8-g8 Rg8 h8g8 h8g8
54/ 73 Rh8xh7 R8xh7 h8h7 h8h7
55/ 73 Qe1-a1 Qa1 e1a1 e1a1
56/ 73 Qe1-b1 Qb1 e1b1 e1b1
57/ 73 Qe1-c1 Qc1 e1c1 e1c1
58/ 73 Qe1-d1 Qd1 e1d1 e1d1
59/ 73 Qe1-f1 Qf1 e1f1 e1f1
60/ 73 Qe1-g1 Qg1 e1g1 e1g1
61/ 73 Qe1-e2 Qe2 e1e2 e1e2
62/ 73 Qe1-f2 Qf2 e1f2 e1f2
63/ 73 Qe1-g3 Qg3 e1g3 e1g3
64/ 73 Kg6-g5 Kg5 g6g5 g6g5
65/ 73 Kg6-h5 Kh5 g6h5 g6h5
66/ 73 g2-g3 g3 g2g3 g2g3
67/ 73 Kg6xh7 Kxh7 g6h7 g6h7
68/ 73 d4-d5 d5 d4d5 d4d5
69/ 73 c7-c8N c8N c7c8n c7c8n
70/ 73 c7-c8B c8B c7c8b c7c8b
71/ 73 c7-c8R c8R c7c8r c7c8r
72/ 73 c7-c8Q c8Q c7c8q c7c8q
73/ 73 d2-d3 d3 d2d3 d2d3