Back to index

gcompris  8.2.2
chess_notation.c
Go to the documentation of this file.
00001 /* 
00002  * Copyright (C) 1999,2001 Robert Wilhelm
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 2 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
00017  */
00018 
00019 #include <stdlib.h>
00020 #include <string.h>
00021 #include <ctype.h>
00022 #include "chess_position.h"
00023 #include "chess_notation.h"
00024 
00025 static char piece_to_ascii_t[]= {' ','N','B','R','Q','K'};
00026 
00027 static int norm_piece (Piece piece);
00028 
00029 static void
00030 file_to_ascii (char **move, Square square)
00031 {
00032        *(*move)++ = square - square / 10 * 10 + 96;     /* a - h */
00033 }
00034 
00035 static void
00036 rank_to_ascii (char **move, Square square)
00037 {
00038        *(*move)++ = square / 10 + 47 ;                  /* 1 - 8 */
00039 }
00040 
00041 void
00042 square_to_ascii(char **move, Square square)
00043 {
00044        file_to_ascii (move, square);
00045        rank_to_ascii (move, square);
00046 }
00047 
00048 
00049 static int
00050 same_rank (Square square, Square square2)
00051 {
00052        char *s1;
00053        char *s2;
00054        char same1;
00055        char same2;
00056 
00057        s1 = &same1;
00058        s2 = &same2;
00059        rank_to_ascii (&s1, square);
00060        rank_to_ascii (&s2, square2);
00061 
00062        if (same1 == same2)
00063               return 1;
00064 
00065        return 0;
00066 }
00067 
00068 static int
00069 same_file (Square square, Square square2)
00070 {
00071        char *s1;
00072        char *s2;
00073        char same1;
00074        char same2;
00075 
00076        s1 = &same1;
00077        s2 = &same2;
00078        file_to_ascii (&s1, square);
00079        file_to_ascii (&s2, square2);
00080        if (same1 == same2)
00081               return 1;
00082 
00083        return 0;
00084 }
00085 
00086 
00087 static void 
00088 delete_x (char *str)
00089 {
00090        char *p = strchr (str, 'x');
00091 
00092        if (p)
00093               while ((*p = *(p+1)))
00094                      p++;
00095 }
00096 
00097 static void 
00098 delete_plus (char *str)
00099 {
00100        char *p = strchr (str, '+');
00101 
00102        if (p)
00103               while ((*p = *(p+1)))
00104                      p++;
00105 }
00106 
00107 static void 
00108 delete_ep (char *str)
00109 {
00110        char *p = strstr (str, "ep");
00111 
00112        if (p)
00113               while ((*p = *(p+2)))
00114                      p++;
00115 }
00116 
00117 static void 
00118 delete_equal (char *str)
00119 {
00120        char *p = strstr (str, "=");
00121 
00122        if (p)
00123               while ((*p = *(p+1)))
00124                      p++;
00125 }
00126 
00127 static void 
00128 delete_hash (char *str)
00129 {
00130        char *p = strstr (str, "#");
00131 
00132        if (p)
00133               while ((*p = *(p+1)))
00134                      p++;
00135 }
00136 
00137 char *
00138 move_to_ascii (char *p, Square from, Square to)
00139 {
00140        Square a;
00141 
00142        file_to_ascii (&p, from);
00143        rank_to_ascii (&p, from);
00144 
00145        if (to & 128) {
00146                 /* promotion */
00147               a = to;
00148 
00149               if (from > E4) 
00150                      a = (a & 7) + A8; /* white */
00151               else
00152                      a = (a & 7) + A1; /* black */
00153 
00154               *p++    = a - a / 10 * 10 + 96;     /*  a - h       */
00155               *p++    = a / 10 + 47 ;             /*  1 - 8       */
00156               *p++    = '=';
00157               *p++ = piece_to_ascii_t[((to >> 3) & 7)-1];
00158        } else {
00159               file_to_ascii (&p, to);
00160               rank_to_ascii (&p, to);
00161        }
00162 
00163        *p = '\0';
00164 
00165        return p;
00166 }
00167 
00168 int
00169 ascii_to_piece (char p)
00170 {
00171        if (p == 'q')
00172               return WQ-WP;
00173        if (p == 'r')
00174               return WR-WP;
00175        if (p == 'b')
00176               return WB-WP;
00177        if (p == 'n')
00178               return WN-WP;
00179        if (p == 'Q')
00180               return WQ-WP;
00181        if (p == 'R')
00182               return WR-WP;
00183        if (p == 'B')
00184               return WB-WP;
00185        if (p == 'N')
00186               return WN-WP;
00187 
00188        g_assert_not_reached ();
00189 
00190        return -1;
00191 }
00192 
00193 char
00194 piece_to_ascii (int piece)
00195 {
00196   static char piece_to_ascii_full[]= {'P','N','B','R','Q','K'};
00197   int i;
00198 
00199   if(piece == EMPTY)
00200     return(' ');
00201 
00202   i = norm_piece (piece);
00203 
00204   if(WPIECE(piece))
00205     return piece_to_ascii_full[i];
00206   else
00207     return tolower(piece_to_ascii_full[i]);
00208 
00209   g_assert_not_reached ();
00210   
00211   return -1;
00212 }
00213 
00214 void
00215 ascii_to_move (Position *pos, char *p, Square *from, Square *to)
00216 {
00217        delete_x (p);
00218 
00219        if (*p == 'o') {
00220               /* Castling */
00221               if (!strcmp (p, "o-o-o")) {
00222                      if (position_get_color_to_move (pos) == WHITE) {
00223                             *from = E1;
00224                             *to   = C1;
00225                      } else {
00226                             *from = E8;
00227                             *to   = C8;
00228                      }
00229               } else {
00230                      if (position_get_color_to_move (pos) == WHITE) {
00231                             *from = E1;
00232                             *to   = G1;
00233                      } else {
00234                             *from = E8;
00235                             *to   = G8;
00236                      }
00237               }
00238               return;
00239        }
00240 
00241        *from = (*p - 'a' + 1) + (*(p + 1) - '1' + 2 ) * 10;
00242        p += 2;
00243        *to = (*p - 'a' + 1) + (*(p + 1) - '1' + 2 ) * 10;
00244        p += 2;
00245        
00246        if (*p == 'q' || *p == 'r' || *p == 'b' || *p =='n' ||
00247            *p =='Q' || *p =='R' || *p == 'B' || *p == 'N' ) { 
00248                 /* Promotion */
00249               if (*to < A2)
00250                      *to = 128 +  *to - A1 + (ascii_to_piece (*p) + 1) * 8;
00251               else if (*to > A7)
00252                      *to = 128 +  *to - A8 + (ascii_to_piece (*p) + 1) * 8;
00253               else
00254                      g_assert_not_reached ();
00255        }
00256 }
00257 
00258 int 
00259 san_to_move (Position *pos, char *str, Square *from, Square *to)
00260 {
00261        Square zugliste[AB_ZUGL];
00262        Square *ap, *aq;
00263        gshort anz, anz_n, anz_s;
00264        gshort i;
00265        gchar *p;
00266        gchar liste[100][10];
00267 
00268        delete_x(str);
00269        delete_plus(str);
00270        delete_ep(str);
00271        delete_equal(str);
00272        delete_hash(str);
00273 
00274        ap =  zugliste + AB_ZUG_S;
00275        anz = position_legal_move (pos, &ap, &anz_s, &anz_n);
00276 
00277        for (aq = ap, i = 0; i < anz; i++, aq += 2) {
00278               p = liste[i];
00279               piece_move_to_ascii (p, pos->square[*aq], *aq, *(aq + 1));
00280 
00281               if (*p == ' ') {
00282                         /* pawn move */
00283 
00284                         /* e.g. e2e4 */
00285                      p++;
00286                      if (!strcmp (p, str)) {
00287                             *from = *aq;
00288                             *to   = *(aq+1);
00289                             return 0;
00290                      }
00291 
00292                         /* e.g. ed5 */                  
00293                      p[1]=p[2];  
00294                      p[2]=p[3];
00295                      p[3]=p[4];
00296                      p[4]=p[5];
00297 
00298                         /* not e.g. bb3 */
00299                      if (p[0] != p[1])   
00300                             if (!strcmp(p,str)) {
00301                                    *from = *aq;
00302                                    *to   = *(aq+1);
00303                                    return 0;
00304                             }
00305 
00306                         /* e.g. d5 */
00307                      p++;
00308                      if (!strcmp(p,str)) {
00309                             *from = *aq;
00310                             *to   = *(aq+1);
00311                             return 0;
00312                      }
00313 
00314               } else {
00315                      /* no pawn move */
00316                      char  tmp;
00317 
00318                         /* e.g. Ng1f3 */
00319                      if (!strcmp (p, str)) {
00320                             *from = *aq;
00321                             *to   = *(aq+1);
00322                             return 0;
00323                      }
00324 
00325                         /* Ngf3 */
00326                      tmp =p[2];
00327                      p[2]=p[3];        
00328                      p[3]=p[4];
00329                      p[4]=p[5];
00330 
00331                      if (!strcmp(p,str)) {
00332                             *from = *aq;
00333                             *to   = *(aq+1);
00334                             return 0;
00335                      }
00336 
00337                      /* N1f3 */
00338                      p[1]=tmp;
00339 
00340                      if (!strcmp(p,str)) {
00341                             *from = *aq;
00342                             *to   = *(aq+1);
00343                             return 0;
00344                      }
00345 
00346                      /* Nf3 */
00347                      p[1]=p[2];
00348                      p[2]=p[3];
00349                      p[3]=p[4];
00350 
00351                      if (!strcmp(p,str)) {
00352                             *from = *aq;
00353                             *to   = *(aq+1);
00354                             return 0;
00355                      }
00356               }
00357        }
00358 
00359        return 1;
00360 }
00361 
00362 static int
00363 norm_piece (Piece piece)
00364 {
00365        if (WPIECE (piece))
00366               return piece - WP;
00367        if (BPIECE (piece))
00368               return piece - BP;
00369 
00370        return piece;
00371 }
00372 
00373 void
00374 piece_move_to_ascii (char *p, Piece piece, Square from, Square to)
00375 {
00376        int i;
00377 
00378         if ((piece == WK || piece == BK) && abs (from - to) == 2) {
00379               if (to % 10 == 3) {
00380                      strcpy (p,"O-O-O");
00381                      return;
00382               }
00383               if (to % 10 == 7) {
00384                      strcpy (p,"O-O");
00385                      return;
00386               }
00387               g_assert_not_reached ();
00388        }
00389 
00390         i = norm_piece (piece);
00391         *p++ = piece_to_ascii_t[i];
00392         move_to_ascii (p, from, to);
00393 }
00394 
00395 char *
00396 move_to_san (Position *pos, Square from, Square to)
00397 {
00398        Square checksquare, checkto;
00399        Piece piece, promote;
00400        int norm, desrank, desfile, inc;
00401        int i, tempdesfile, tempdesrank;
00402        char *san;
00403        char *temp;
00404        const int jump[]={ 8, 12,19, 21,-8,-12,-19,-21};
00405 
00406        san = g_new0 (char, 12);
00407        temp = san;
00408 
00409        desrank = desfile = promote = 0;
00410 
00411        /* Handle Promotion */
00412        if (to & 128) {
00413               promote = ((to >> 3) & 7)-1;
00414               if ( from > E4) {
00415                      to = (to & 7) + A8;
00416                      piece = WP;
00417               } else {
00418                      to = (to & 7) + A1;
00419                      piece = BP;
00420               }
00421        } else {
00422               piece = pos->square[to];
00423        }
00424 
00425        /* Check if we have to designate the rank or file */
00426        switch (piece) {
00427        case WQ:
00428        case BQ:
00429               /* Check like rooks and bishops */
00430        case WR:
00431        case BR:
00432               /* Check for other rooks/queens */
00433               i = 0;
00434               while (1) {
00435                      tempdesfile = tempdesrank = 0;
00436                      if (i == 0) {
00437                             checksquare = 20 + (to % 10);
00438                             checkto =  90 + (to % 10);
00439                             if (from / 10 > to / 10 )
00440                                    checkto = to - 10;
00441                             else if (from / 10 < to /10)
00442                                    checksquare = to + 10;
00443                             inc = 10;
00444                      } else if (i == 1) {
00445                             checksquare = 10 * (to / 10) + 1;
00446                             checkto =  10 * (to / 10) + 8;
00447                             if (from % 10 > to % 10)
00448                                    checkto = to - 1;
00449                             else if (from % 10 < to % 10)
00450                                    checksquare = to + 1;
00451                             inc = 1;
00452                      } else {
00453                             break;
00454                      }
00455 
00456                      while (checksquare <= checkto) {
00457                             if (pos->square[checksquare] == piece && checksquare != to) {
00458                                    if (same_rank(from, checksquare))
00459                                           tempdesfile = 1;
00460                                    else if (same_file(from, checksquare))
00461                                           desrank = 1;
00462                                    else 
00463                                           tempdesfile = 1;
00464                             } else if (pos->square[checksquare] != EMPTY && checksquare < to) {
00465                                    tempdesfile = tempdesrank = 0;     /* A piece is in the way */
00466                             } else if (pos->square[checksquare] != EMPTY && checksquare > to) {
00467                                    break;               /* A piece is in the way */
00468                             }
00469                             checksquare += inc;
00470                      }
00471                      i++;
00472                      if (tempdesfile == 1) desfile = 1;
00473                      if (tempdesrank == 1) desrank = 1;
00474               }
00475               if (piece == WR || piece == BR) break;
00476        case WB:
00477        case BB:
00478               /* Check for other bishops/queens */
00479               i = 0;
00480               while (1) {
00481                      tempdesfile = tempdesrank = 0;
00482                      if (i == 0) {
00483                             checksquare = to - (((to % 10) - 1) * 11);
00484                             checkto =  to + ((9 - (to / 10)) * 11);
00485                             if (from % 10 > to % 10  && from / 10 > to / 10)
00486                                    checkto = to - 11;
00487                             else if (from % 10 < to % 10 && from / 10 < to / 10)
00488                                    checksquare = to + 11;
00489                             inc = 11;
00490                      } else if (i == 1) {
00491                             checksquare = to - ((8 - (to % 10)) * 9);
00492                             checkto =  to + ((9 - (to / 10)) * 9);
00493                             if (from % 10 > to % 10 && from / 10 < to / 10)
00494                                    checksquare = to + 9;
00495                             else if (from % 10 < to % 10  && from / 10 > to / 10)
00496                                    checkto = to - 9;
00497                             inc = 9;
00498                      } else {
00499                             break;
00500                      }
00501 
00502                      while (checksquare <= checkto) {
00503                             if (pos->square[checksquare] == piece && checksquare != to) {
00504                                    if (same_rank(from, checksquare))
00505                                           tempdesfile = 1;
00506                                    else if (same_file(from, checksquare))
00507                                           desrank = 1;
00508                                    else 
00509                                           tempdesfile = 1;
00510                             } else if (pos->square[checksquare] != EMPTY && checksquare < to) {
00511                                    tempdesfile = tempdesrank = 0;     /* A piece is in the way */
00512                             } else if (pos->square[checksquare] != EMPTY && checksquare > to) {
00513                                    break;               /* A piece is in the way */
00514                             }
00515                             checksquare += inc;
00516                      }
00517                      i++;
00518                      if (tempdesfile == 1) desfile = 1;
00519                      if (tempdesrank == 1) desrank = 1;
00520               }
00521               break;
00522        case WN:
00523        case BN:
00524               /* Check for other knights */
00525               for (i=0;i<8;i++) {
00526                      if (pos->square[to+jump[i]] == piece && to+jump[i] >= 0) {
00527                             if (same_rank(from, to+jump[i]))
00528                                    desfile = 1;
00529                             else if (same_file(from, to+jump[i]))
00530                                    desrank = 1;
00531                             else 
00532                                    desfile = 1;
00533                      }
00534               }
00535               break;                      
00536 
00537        }
00538 
00539        /* Handle Castling */
00540        if ((piece == WK || piece == BK) && abs(from-to) == 2) {
00541               if (to % 10 == 3)
00542                      strcpy(temp,"O-O-O");
00543               if (to % 10 == 7)
00544                      strcpy(temp,"O-O");
00545        } else {
00546               /* The piece letter */
00547                norm = norm_piece(piece);
00548               if (norm > 0)
00549                       *temp++ = piece_to_ascii_t[norm];
00550 
00551               /* The rank/file designators */
00552               if (desfile)
00553                      file_to_ascii(&temp, from);
00554               if (desrank)
00555                      rank_to_ascii(&temp, from);
00556 
00557               /* If there was a capture */
00558               if (position_last_piece_captured (pos) != EMPTY) {
00559                      if (piece == WP || piece == BP)
00560                             file_to_ascii (&temp, from);
00561                      *temp++ = 'x';
00562               }
00563 
00564               /* Destination square */
00565                square_to_ascii (&temp, to);
00566 
00567               /* If there was promotion */
00568               if (promote) {
00569                      *temp++ = '=';
00570                      norm = norm_piece(promote);
00571                      *temp++ = piece_to_ascii_t[norm];
00572               }
00573 
00574               *temp = '\0';
00575        }
00576 
00577        temp = san;
00578        san = g_strdup (temp);
00579        g_free (temp);
00580        return san;
00581 }