"Fossies" - the Fresh Open Source Software Archive

Member "gnuchess-6.2.9/src/frontend/epd.cc" (27 Jun 2021, 11472 Bytes) of package /linux/privat/gnuchess-6.2.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "epd.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.2.8_vs_6.2.9.

    1 /* epd.c
    2 
    3    GNU Chess frontend
    4 
    5    Copyright (C) 2001-2021 Free Software Foundation, Inc.
    6 
    7    GNU Chess is based on the two research programs
    8    Cobalt by Chua Kong-Sian and Gazebo by Stuart Cracraft.
    9 
   10    This program is free software: you can redistribute it and/or modify
   11    it under the terms of the GNU General Public License as published by
   12    the Free Software Foundation, either version 3 of the License, or
   13    (at your option) any later version.
   14 
   15    This program is distributed in the hope that it will be useful,
   16    but WITHOUT ANY WARRANTY; without even the implied warranty of
   17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18    GNU General Public License for more details.
   19 
   20    You should have received a copy of the GNU General Public License
   21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   22 
   23    Contact Info:
   24      bug-gnu-chess@gnu.org
   25      cracraft@ai.mit.edu, cracraft@stanfordalumni.org, cracraft@earthlink.net
   26 */
   27 
   28 #include <stdio.h>
   29 #include <string.h>
   30 #include <ctype.h>
   31 #include "common.h"
   32 
   33 #define EPDCLOSE 1
   34 
   35 /* A line read from an EPD file, used in solve.c */
   36 char epd_line[MAXSTR]="";
   37 
   38 short ReadEPDFile (const char *file, short op)
   39 /****************************************************************************
   40  *
   41  *  Reads in an EPD file.  The first call will read the first EPD line,
   42  *  the second call will read the 2nd line and so on.   To improve
   43  *  performance, the file is never closed.  Closing of the file happens
   44  *  only on 2 conditions:  (i) A ReadEPDFile failed because there is no
   45  *  more lines to read.  (ii) A called to ReadEPDFile to explicitly
   46  *  request that the file is closed (op = EPDCLOSE);
   47  *  If op == 2, then we work silently.
   48  *  Comment lines are stripped off. Comment mark is '#'.
   49  *
   50  ****************************************************************************/
   51 {
   52    static FILE *fp = NULL;
   53    char line[MAXSTR];
   54 
   55    /*  If first time through, must open file  */
   56    if (fp == NULL)
   57    {
   58       fp = fopen (file, "r");
   59       if (fp == NULL)
   60       {
   61          printf ("Error opening file %s\n", file);
   62          return (false);
   63       }
   64    }
   65 
   66    /*  Is this a close request? */
   67    if (op == EPDCLOSE)
   68    {
   69       fclose (fp);
   70       fp = NULL;
   71       return (false);
   72    }
   73 
   74 next_line:
   75    /*  Okay, we read in an EPD entry  */
   76    if ( fgets (line, MAXSTR-1, fp) == NULL ) {
   77       /* Do nothing - just avoid compilation warning - further refactoring is tricky. */
   78    }
   79    strcpy( epd_line, line );
   80    if (!feof(fp))
   81    {
   82       /* Skip comment lines */
   83       unsigned int i=0;
   84       for (i = 0; i < strlen( line ); ++i) {
   85          if ( isblank( line[i] ) ) {
   86             continue;
   87          }
   88          if ( line[i] == '#' ) {
   89             goto next_line;
   90          } else {
   91             break;
   92          }
   93       }
   94       int ret = ParseEPD (line);
   95 
   96       /* For now just ignore malformed lines */
   97       if (ret != EPD_SUCCESS) goto next_line;
   98       if (op != 2)
   99          printf ("\n%s : Best move = %s\n", id, solution);
  100       return (true);
  101    }
  102    /* finished, must close file */
  103    else
  104    {
  105       fclose (fp);
  106       fp = NULL;
  107       return (false);
  108    }
  109 }
  110 
  111 /*
  112  * Returns EPD_SUCCESS on success, EPD_ERROR on error. We try to be
  113  * quite tough on the format. However, as of yet no legality checking
  114  * is done and the board is not reset on error, this should be done by
  115  * the caller.
  116  */
  117 
  118 int ParseEPD (char *p)
  119 /**************************************************************************
  120  *
  121  *  Parses an EPD input line.  A few global variables are updated e.g.
  122  *  current board, side to move, en passant, castling status, etc.
  123  *
  124  **************************************************************************/
  125 {
  126    int r, c, sq;
  127    char *str_p;
  128 
  129    r = 56;
  130    c = 0;
  131    memset (&board, 0, sizeof (board));
  132 
  133    while (p && *p != ' ')
  134    {
  135      sq = r + c;
  136      switch (*p)
  137      {
  138         case 'P' :  SETBIT (board.b[white][pawn], sq);
  139             SETBIT (board.blockerr90, r90[sq]);
  140             SETBIT (board.blockerr45, r45[sq]);
  141             SETBIT (board.blockerr315, r315[sq]);
  142             board.material[white] += ValueP;
  143             break;
  144         case 'N' :  SETBIT (board.b[white][knight], sq);
  145             SETBIT (board.blockerr90, r90[sq]);
  146             SETBIT (board.blockerr45, r45[sq]);
  147             SETBIT (board.blockerr315, r315[sq]);
  148             board.material[white] += ValueN;
  149             break;
  150         case 'B' :  SETBIT (board.b[white][bishop], sq);
  151             SETBIT (board.blockerr90, r90[sq]);
  152             SETBIT (board.blockerr45, r45[sq]);
  153             SETBIT (board.blockerr315, r315[sq]);
  154             board.material[white] += ValueB;
  155             break;
  156         case 'R' :  SETBIT (board.b[white][rook], sq);
  157             SETBIT (board.blockerr90, r90[sq]);
  158             SETBIT (board.blockerr45, r45[sq]);
  159             SETBIT (board.blockerr315, r315[sq]);
  160             board.material[white] += ValueR;
  161             break;
  162         case 'Q' :  SETBIT (board.b[white][queen], sq);
  163             SETBIT (board.blockerr90, r90[sq]);
  164             SETBIT (board.blockerr45, r45[sq]);
  165             SETBIT (board.blockerr315, r315[sq]);
  166             board.material[white] += ValueQ;
  167             break;
  168         case 'K' :  SETBIT (board.b[white][king], sq);
  169             SETBIT (board.blockerr90, r90[sq]);
  170             SETBIT (board.blockerr45, r45[sq]);
  171             SETBIT (board.blockerr315, r315[sq]);
  172             break;
  173         case 'p' :  SETBIT (board.b[black][pawn], sq);
  174             SETBIT (board.blockerr90, r90[sq]);
  175             SETBIT (board.blockerr45, r45[sq]);
  176             SETBIT (board.blockerr315, r315[sq]);
  177             board.material[black] += ValueP;
  178             break;
  179         case 'n' :  SETBIT (board.b[black][knight], sq);
  180             SETBIT (board.blockerr90, r90[sq]);
  181             SETBIT (board.blockerr45, r45[sq]);
  182             SETBIT (board.blockerr315, r315[sq]);
  183             board.material[black] += ValueN;
  184             break;
  185         case 'b' :  SETBIT (board.b[black][bishop], sq);
  186             SETBIT (board.blockerr90, r90[sq]);
  187             SETBIT (board.blockerr45, r45[sq]);
  188             SETBIT (board.blockerr315, r315[sq]);
  189             board.material[black] += ValueB;
  190             break;
  191         case 'r' :  SETBIT (board.b[black][rook], sq);
  192             SETBIT (board.blockerr90, r90[sq]);
  193             SETBIT (board.blockerr45, r45[sq]);
  194             SETBIT (board.blockerr315, r315[sq]);
  195             board.material[black] += ValueR;
  196             break;
  197         case 'q' :  SETBIT (board.b[black][queen], sq);
  198             SETBIT (board.blockerr90, r90[sq]);
  199             SETBIT (board.blockerr45, r45[sq]);
  200             SETBIT (board.blockerr315, r315[sq]);
  201                     board.material[black] += ValueQ;
  202             break;
  203         case 'k' :  SETBIT (board.b[black][king], sq);
  204             SETBIT (board.blockerr90, r90[sq]);
  205             SETBIT (board.blockerr45, r45[sq]);
  206             SETBIT (board.blockerr315, r315[sq]);
  207             break;
  208         case '/' :  r -= 8;
  209             c = -1;
  210             break;
  211         default  :  break;
  212      }
  213      if (isdigit (*p))
  214         c += (*p - '0');
  215      else
  216         c++;
  217 
  218      /*
  219       * Special case, a trailing "/" is accepted on the
  220       * end of the board settings.
  221       */
  222 
  223      if (r == -8 && p[1] == ' ')
  224          r = 0;
  225 
  226      if (r < 0 || c > 8) return EPD_ERROR;
  227      if (c == 8 && p[1] != '/' && p[1] != ' ') return EPD_ERROR;
  228      p++;
  229    }
  230 
  231    board.pmaterial[white] = board.material[white] -
  232                 nbits(board.b[white][pawn]) * ValueP;
  233    board.pmaterial[black] = board.material[black] -
  234                 nbits(board.b[black][pawn]) * ValueP;
  235    board.king[white] = leadz (board.b[white][king]);
  236    board.king[black] = leadz (board.b[black][king]);
  237    UpdateFriends ();
  238    UpdateCBoard ();
  239    UpdateMvboard ();
  240 
  241    /*  Get side to move  */
  242    if (!++p) return EPD_ERROR;
  243    if      (*p == 'w') board.side = white;
  244    else if (*p == 'b') board.side = black;
  245    else return EPD_ERROR;
  246 
  247    /* Isn't this one cute? */
  248    if (!++p || *p != ' ' || !++p) return EPD_ERROR;
  249 
  250    /*  Castling status  */
  251    while (p && *p != ' ') {
  252       if      (*p == 'K') board.flag |= WKINGCASTLE;
  253       else if (*p == 'Q') board.flag |= WQUEENCASTLE;
  254       else if (*p == 'k') board.flag |= BKINGCASTLE;
  255       else if (*p == 'q') board.flag |= BQUEENCASTLE;
  256       else if (*p == '-') { p++; break; }
  257       else return EPD_ERROR;
  258       p++;
  259    }
  260    if (!p || *p != ' ' || !++p) return EPD_ERROR;
  261 
  262    /*
  263     * En passant square, can only be '-' or [a-h][36]
  264     * In fact, one could add more sanity checks here.
  265     */
  266    if (*p != '-') {
  267       if (!p[1] || *p < 'a' || *p > 'h' ||
  268       !(p[1] == '3' || p[1] == '6')) return EPD_ERROR;
  269       board.ep = (*p - 'a') + (p[1] - '1')*8;
  270       p++;
  271    } else {
  272       board.ep = -1;
  273    }
  274 
  275    solution[0] = '\0';
  276    id[0] = '\0';
  277 
  278    if (!++p) return EPD_SUCCESS;
  279 
  280    /* The opcodes are optional, so we should not generate errors here */
  281 
  282    /*  Read in best move; "bm" operator */
  283    str_p = strstr(p, "bm");
  284    if (str_p) sscanf (str_p, "bm %63[^;];", solution);
  285 
  286    /*  Read in the description; "id" operator */
  287    str_p = strstr(p, "id");
  288    if (str_p) sscanf (p, "id %31[^;];", id);
  289 
  290    phase = PHASE;
  291 
  292    return EPD_SUCCESS;
  293 }
  294 
  295 
  296 void LoadEPD (char *p)
  297 /**************************************************************************
  298  *
  299  *  This routine reads in the next or the Nth position in the file.
  300  *
  301  **************************************************************************/
  302 {
  303    char file[MAXSTR];
  304    int N = 1;
  305 
  306    sscanf (p, "%127s %d ", file, &N);
  307    if (strcmp (file, "next") == 0)
  308    {
  309       ReadEPDFile (file, 0);
  310    }
  311    else
  312    {
  313       ReadEPDFile (file, 1);
  314       while (--N)
  315       {
  316          if (ReadEPDFile (file, 2) == false)
  317          {
  318         printf ("File position exceeded\n");
  319         return;
  320          }
  321       }
  322       ReadEPDFile (file, 0);
  323    }
  324    ShowBoard ();
  325    NewPosition ();
  326 }
  327 
  328 
  329 void EPD2str (char *pos)
  330 /**************************************************************************
  331  *
  332  *  This routine writes the current position in EPD format into a string.
  333  *
  334  **************************************************************************/
  335 {
  336    int r, c, sq, k;
  337    char c1;
  338 
  339    for (r = A8; r >= A1; r -= 8)
  340    {
  341       k = 0;
  342       for (c = 0; c < 8; c++)
  343       {
  344          sq = r + c;
  345          if (cboard[sq] == empty)
  346             k++;
  347          else
  348          {
  349             if (k)
  350                sprintf(pos + strlen(pos), "%1d", k);
  351             k = 0;
  352             c1 = notation[cboard[sq]];
  353             if (BitPosArray[sq] & board.friends[black])
  354                c1 = tolower (c1);
  355             sprintf(pos + strlen(pos), "%c", c1);
  356          }
  357       }
  358       if (k)
  359          sprintf(pos + strlen(pos), "%1d", k);
  360       if (r > A1)
  361          sprintf(pos + strlen(pos), "/");
  362    }
  363 
  364    /* Print other stuff */
  365    sprintf(pos + strlen(pos), (board.side == white ? " w " : " b "));
  366 
  367    if (board.flag & WKINGCASTLE)
  368       sprintf(pos + strlen(pos), "K");
  369    if (board.flag & WQUEENCASTLE)
  370       sprintf(pos + strlen(pos), "Q");
  371    if (board.flag & BKINGCASTLE)
  372       sprintf(pos + strlen(pos), "k");
  373    if (board.flag & BQUEENCASTLE)
  374       sprintf(pos + strlen(pos), "q");
  375    if (!(board.flag & (WCASTLE | BCASTLE)))
  376       sprintf(pos + strlen(pos), "-");
  377 
  378    sprintf(pos + strlen(pos), " %s", (board.ep > -1 ? algbr[board.ep] : "-"));
  379    sprintf(pos + strlen(pos), " bm 1; id 1;");
  380 }
  381 
  382 
  383 void SaveEPD (char *p)
  384 /**************************************************************************
  385  *
  386  *  This routine appends the current position in EPD format into a file.
  387  *
  388  **************************************************************************/
  389 {
  390    char file[MAXSTR];
  391    FILE *fp;
  392    char pos[MAXSTR] = "";
  393 
  394    EPD2str(pos);
  395    sscanf (p, "%s ", file);
  396    fp = fopen (file, "a");
  397    fprintf(fp, "%s\n", pos);
  398    fclose (fp);
  399 }