/* * Copyright (C) 1999,2001 Robert Wilhelm * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include "chess_position.h" #include "chess_notation.h" static char piece_to_ascii_t[]= {' ','N','B','R','Q','K'}; static int norm_piece (Piece piece); static void file_to_ascii (char **move, Square square) { *(*move)++ = square - square / 10 * 10 + 96; /* a - h */ } static void rank_to_ascii (char **move, Square square) { *(*move)++ = square / 10 + 47 ; /* 1 - 8 */ } void square_to_ascii(char **move, Square square) { file_to_ascii (move, square); rank_to_ascii (move, square); } static int same_rank (Square square, Square square2) { char *s1; char *s2; char same1; char same2; s1 = &same1; s2 = &same2; rank_to_ascii (&s1, square); rank_to_ascii (&s2, square2); if (same1 == same2) return 1; return 0; } static int same_file (Square square, Square square2) { char *s1; char *s2; char same1; char same2; s1 = &same1; s2 = &same2; file_to_ascii (&s1, square); file_to_ascii (&s2, square2); if (same1 == same2) return 1; return 0; } static void delete_x (char *str) { char *p = strchr (str, 'x'); if (p) while ((*p = *(p+1))) p++; } static void delete_plus (char *str) { char *p = strchr (str, '+'); if (p) while ((*p = *(p+1))) p++; } static void delete_ep (char *str) { char *p = strstr (str, "ep"); if (p) while ((*p = *(p+2))) p++; } static void delete_equal (char *str) { char *p = strstr (str, "="); if (p) while ((*p = *(p+1))) p++; } static void delete_hash (char *str) { char *p = strstr (str, "#"); if (p) while ((*p = *(p+1))) p++; } char * move_to_ascii (char *p, Square from, Square to) { Square a; file_to_ascii (&p, from); rank_to_ascii (&p, from); if (to & 128) { /* promotion */ a = to; if (from > E4) a = (a & 7) + A8; /* white */ else a = (a & 7) + A1; /* black */ *p++ = a - a / 10 * 10 + 96; /* a - h */ *p++ = a / 10 + 47 ; /* 1 - 8 */ *p++ = '='; *p++ = piece_to_ascii_t[((to >> 3) & 7)-1]; } else { file_to_ascii (&p, to); rank_to_ascii (&p, to); } *p = '\0'; return p; } int ascii_to_piece (char p) { if (p == 'q') return WQ-WP; if (p == 'r') return WR-WP; if (p == 'b') return WB-WP; if (p == 'n') return WN-WP; if (p == 'Q') return WQ-WP; if (p == 'R') return WR-WP; if (p == 'B') return WB-WP; if (p == 'N') return WN-WP; g_assert_not_reached (); return -1; } char piece_to_ascii (int piece) { static char piece_to_ascii_full[]= {'P','N','B','R','Q','K'}; int i; if(piece == EMPTY) return(' '); i = norm_piece (piece); if(WPIECE(piece)) return piece_to_ascii_full[i]; else return tolower(piece_to_ascii_full[i]); g_assert_not_reached (); return -1; } void ascii_to_move (Position *pos, char *p, Square *from, Square *to) { delete_x (p); if (*p == 'o') { /* Castling */ if (!strcmp (p, "o-o-o")) { if (position_get_color_to_move (pos) == WHITE) { *from = E1; *to = C1; } else { *from = E8; *to = C8; } } else { if (position_get_color_to_move (pos) == WHITE) { *from = E1; *to = G1; } else { *from = E8; *to = G8; } } return; } *from = (*p - 'a' + 1) + (*(p + 1) - '1' + 2 ) * 10; p += 2; *to = (*p - 'a' + 1) + (*(p + 1) - '1' + 2 ) * 10; p += 2; if (*p == 'q' || *p == 'r' || *p == 'b' || *p =='n' || *p =='Q' || *p =='R' || *p == 'B' || *p == 'N' ) { /* Promotion */ if (*to < A2) *to = 128 + *to - A1 + (ascii_to_piece (*p) + 1) * 8; else if (*to > A7) *to = 128 + *to - A8 + (ascii_to_piece (*p) + 1) * 8; else g_assert_not_reached (); } } int san_to_move (Position *pos, char *str, Square *from, Square *to) { Square zugliste[AB_ZUGL]; Square *ap, *aq; gshort anz, anz_n, anz_s; gshort i; gchar *p; gchar liste[100][10]; delete_x(str); delete_plus(str); delete_ep(str); delete_equal(str); delete_hash(str); ap = zugliste + AB_ZUG_S; anz = position_legal_move (pos, &ap, &anz_s, &anz_n); for (aq = ap, i = 0; i < anz; i++, aq += 2) { p = liste[i]; piece_move_to_ascii (p, pos->square[*aq], *aq, *(aq + 1)); if (*p == ' ') { /* pawn move */ /* e.g. e2e4 */ p++; if (!strcmp (p, str)) { *from = *aq; *to = *(aq+1); return 0; } /* e.g. ed5 */ p[1]=p[2]; p[2]=p[3]; p[3]=p[4]; p[4]=p[5]; /* not e.g. bb3 */ if (p[0] != p[1]) if (!strcmp(p,str)) { *from = *aq; *to = *(aq+1); return 0; } /* e.g. d5 */ p++; if (!strcmp(p,str)) { *from = *aq; *to = *(aq+1); return 0; } } else { /* no pawn move */ char tmp; /* e.g. Ng1f3 */ if (!strcmp (p, str)) { *from = *aq; *to = *(aq+1); return 0; } /* Ngf3 */ tmp =p[2]; p[2]=p[3]; p[3]=p[4]; p[4]=p[5]; if (!strcmp(p,str)) { *from = *aq; *to = *(aq+1); return 0; } /* N1f3 */ p[1]=tmp; if (!strcmp(p,str)) { *from = *aq; *to = *(aq+1); return 0; } /* Nf3 */ p[1]=p[2]; p[2]=p[3]; p[3]=p[4]; if (!strcmp(p,str)) { *from = *aq; *to = *(aq+1); return 0; } } } return 1; } static int norm_piece (Piece piece) { if (WPIECE (piece)) return piece - WP; if (BPIECE (piece)) return piece - BP; return piece; } void piece_move_to_ascii (char *p, Piece piece, Square from, Square to) { int i; if ((piece == WK || piece == BK) && abs (from - to) == 2) { if (to % 10 == 3) { strcpy (p,"O-O-O"); return; } if (to % 10 == 7) { strcpy (p,"O-O"); return; } g_assert_not_reached (); } i = norm_piece (piece); *p++ = piece_to_ascii_t[i]; move_to_ascii (p, from, to); } char * move_to_san (Position *pos, Square from, Square to) { Square checksquare, checkto; Piece piece, promote; int norm, desrank, desfile, inc; int i, tempdesfile, tempdesrank; char *san; char *temp; const int jump[]={ 8, 12,19, 21,-8,-12,-19,-21}; san = g_new0 (char, 12); temp = san; desrank = desfile = promote = 0; /* Handle Promotion */ if (to & 128) { promote = ((to >> 3) & 7)-1; if ( from > E4) { to = (to & 7) + A8; piece = WP; } else { to = (to & 7) + A1; piece = BP; } } else { piece = pos->square[to]; } /* Check if we have to designate the rank or file */ switch (piece) { case WQ: case BQ: /* Check like rooks and bishops */ case WR: case BR: /* Check for other rooks/queens */ i = 0; while (1) { tempdesfile = tempdesrank = 0; if (i == 0) { checksquare = 20 + (to % 10); checkto = 90 + (to % 10); if (from / 10 > to / 10 ) checkto = to - 10; else if (from / 10 < to /10) checksquare = to + 10; inc = 10; } else if (i == 1) { checksquare = 10 * (to / 10) + 1; checkto = 10 * (to / 10) + 8; if (from % 10 > to % 10) checkto = to - 1; else if (from % 10 < to % 10) checksquare = to + 1; inc = 1; } else { break; } while (checksquare <= checkto) { if (pos->square[checksquare] == piece && checksquare != to) { if (same_rank(from, checksquare)) tempdesfile = 1; else if (same_file(from, checksquare)) desrank = 1; else tempdesfile = 1; } else if (pos->square[checksquare] != EMPTY && checksquare < to) { tempdesfile = tempdesrank = 0; /* A piece is in the way */ } else if (pos->square[checksquare] != EMPTY && checksquare > to) { break; /* A piece is in the way */ } checksquare += inc; } i++; if (tempdesfile == 1) desfile = 1; if (tempdesrank == 1) desrank = 1; } if (piece == WR || piece == BR) break; case WB: case BB: /* Check for other bishops/queens */ i = 0; while (1) { tempdesfile = tempdesrank = 0; if (i == 0) { checksquare = to - (((to % 10) - 1) * 11); checkto = to + ((9 - (to / 10)) * 11); if (from % 10 > to % 10 && from / 10 > to / 10) checkto = to - 11; else if (from % 10 < to % 10 && from / 10 < to / 10) checksquare = to + 11; inc = 11; } else if (i == 1) { checksquare = to - ((8 - (to % 10)) * 9); checkto = to + ((9 - (to / 10)) * 9); if (from % 10 > to % 10 && from / 10 < to / 10) checksquare = to + 9; else if (from % 10 < to % 10 && from / 10 > to / 10) checkto = to - 9; inc = 9; } else { break; } while (checksquare <= checkto) { if (pos->square[checksquare] == piece && checksquare != to) { if (same_rank(from, checksquare)) tempdesfile = 1; else if (same_file(from, checksquare)) desrank = 1; else tempdesfile = 1; } else if (pos->square[checksquare] != EMPTY && checksquare < to) { tempdesfile = tempdesrank = 0; /* A piece is in the way */ } else if (pos->square[checksquare] != EMPTY && checksquare > to) { break; /* A piece is in the way */ } checksquare += inc; } i++; if (tempdesfile == 1) desfile = 1; if (tempdesrank == 1) desrank = 1; } break; case WN: case BN: /* Check for other knights */ for (i=0;i<8;i++) { if (pos->square[to+jump[i]] == piece && to+jump[i] >= 0) { if (same_rank(from, to+jump[i])) desfile = 1; else if (same_file(from, to+jump[i])) desrank = 1; else desfile = 1; } } break; } /* Handle Castling */ if ((piece == WK || piece == BK) && abs(from-to) == 2) { if (to % 10 == 3) strcpy(temp,"O-O-O"); if (to % 10 == 7) strcpy(temp,"O-O"); } else { /* The piece letter */ norm = norm_piece(piece); if (norm > 0) *temp++ = piece_to_ascii_t[norm]; /* The rank/file designators */ if (desfile) file_to_ascii(&temp, from); if (desrank) rank_to_ascii(&temp, from); /* If there was a capture */ if (position_last_piece_captured (pos) != EMPTY) { if (piece == WP || piece == BP) file_to_ascii (&temp, from); *temp++ = 'x'; } /* Destination square */ square_to_ascii (&temp, to); /* If there was promotion */ if (promote) { *temp++ = '='; norm = norm_piece(promote); *temp++ = piece_to_ascii_t[norm]; } *temp = '\0'; } temp = san; san = g_strdup (temp); g_free (temp); return san; }