home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR2 / CBUFF09.ZIP / SRC.ZIP / CBGAME.C < prev    next >
C/C++ Source or Header  |  1993-11-16  |  12KB  |  511 lines

  1. /*  $Id: cbgame.c,v 1.1.1.1 1993/06/21 11:11:59 anjo Exp $
  2.  *  
  3.  *  File    cbgame.c
  4.  *  Part of    ChessBase utilities file format (CBUFF)
  5.  *  Author    Anjo Anjewierden, anjo@swi.psy.uva.nl
  6.  *  Purpose    Internal representation of a ChessBase game
  7.  *  Works with    GNU CC 2.4.5
  8.  *  
  9.  *  Notice    Copyright (c) 1993  Anjo Anjewierden
  10.  *  
  11.  *  History    09/06/93  (Created)
  12.  *          31/10/93  (Last modified)
  13.  */ 
  14.  
  15.  
  16. /*------------------------------------------------------------
  17.  *  Directives
  18.  *------------------------------------------------------------*/
  19.  
  20. #include "cbuff.h"
  21.  
  22.  
  23. /*------------------------------------------------------------
  24.  *  Definitions
  25.  *------------------------------------------------------------*/
  26.  
  27. static bool    extractVariationsCbGame(CbGame cg, Game game);
  28.  
  29.  
  30. /*------------------------------------------------------------
  31.  *  Initialisation
  32.  *------------------------------------------------------------*/
  33.  
  34. CbGame
  35. newCbGame()
  36. { CbGame cg;
  37.  
  38.   cg = alloc(sizeof(struct cbgame));
  39.   cg->header = newCbHeader();
  40.   cg->text = NULL;
  41.   cg->moves = NULL;
  42.   cg->comments = NULL;
  43.   cg->position = NULL;
  44.   cg->textLength = 0;
  45.   cg->movesLength = 0;
  46.   cg->commentLength = 0;
  47.  
  48.   return cg;
  49. }
  50.  
  51.  
  52. void
  53. freeCbGame(CbGame cg)
  54. { if (cg->text)
  55.     unalloc(cg->text);
  56.   if (cg->moves)
  57.     unalloc(cg->moves);
  58.   if (cg->comments)
  59.     unalloc(cg->comments);
  60.   freeCbHeader(cg->header);
  61.   unalloc(cg);
  62. }
  63.  
  64.  
  65. void
  66. resetCbGame(CbGame cg)
  67. { if (cg->text)
  68.     unalloc(cg->text);
  69.   if (cg->moves)
  70.     unalloc(cg->moves);
  71.   if (cg->comments)
  72.     unalloc(cg->comments);
  73.   resetCbHeader(cg->header);
  74.   cg->text = NULL;
  75.   cg->moves = NULL;
  76.   cg->comments = NULL;
  77.   cg->textLength = 0;
  78.   cg->movesLength = 0;
  79.   cg->commentLength = 0;
  80. }
  81.  
  82.  
  83. /*------------------------------------------------------------
  84.  *  Reading
  85.  *------------------------------------------------------------*/
  86.  
  87. long
  88. readCbGame(CbGame cg, CBase cb, long no)
  89. { long pos;                /* Position in file */
  90.   unsigned char h[14];            /* Undecoded game header */
  91.   CbHeader ch = cg->header;        /* Game header */
  92.   long rawBytes = 0;
  93.  
  94.   resetCbGame(cg);
  95.   environmentError(cb, NULL, no);
  96.   if (no < 1 || no > getNoGamesCBase(cb))
  97.   { setError(ERR_GAME_NUMBER_OUT_OF_RANGE);
  98.     return (long) NULL;
  99.   }
  100.  
  101.   pos = getIndexGameCBase(cb, no);
  102.   if (fseek(cb->cbf, pos, 0))
  103.   { setError(ERR_CANNOT_SEEK);
  104.     return (long) NULL;
  105.   }
  106.  
  107.   if (fread(h,1,14,cb->cbf) != 14)
  108.   { setError(ERR_CANNOT_READ_HEADER);
  109.     return (long) NULL;
  110.   }
  111.   rawBytes += 14;
  112.   
  113.   initCbHeader(ch, h);
  114.   if (foundError())
  115.     return (long) NULL;
  116.  
  117.   cg->textLength = playersLengthCbHeader(ch) + sourceLengthCbHeader(ch);
  118.   cg->movesLength = movesLengthCbHeader(ch);
  119.   cg->commentLength = commentLengthCbHeader(ch);
  120.  
  121.   cg->text = alloc(cg->textLength);
  122.   cg->moves = alloc(cg->movesLength);
  123.   cg->comments = alloc(cg->commentLength);
  124.  
  125.   if (fread(cg->text,1,cg->textLength,cb->cbf) != cg->textLength)
  126.   { setError(ERR_CANNOT_READ_TEXT);
  127.     return (long) NULL;
  128.   }
  129.   rawBytes += cg->textLength;
  130.  
  131.   if (fread(cg->moves,1,cg->movesLength,cb->cbf) != cg->movesLength)
  132.   { setError(ERR_CANNOT_READ_MOVES);
  133.     return (long) NULL;
  134.   }
  135.   rawBytes += cg->movesLength;
  136.  
  137.   if (fread(cg->comments,1,cg->commentLength,cb->cbf) != cg->commentLength)
  138.   { setError(ERR_CANNOT_READ_COMMENTS);
  139.     return (long) NULL;
  140.   }
  141.   rawBytes += cg->commentLength;
  142.  
  143.   if (!fullGameCbHeaderP(ch))
  144.   { unsigned char nextMove;
  145.     unsigned char board[32];
  146.     int file, rank;
  147.  
  148.     if (fread(board,1,32,cb->cbf) != 32)
  149.     { setError(ERR_CANNOT_READ_POSITION);
  150.       return (long) NULL;
  151.     }
  152.     rawBytes += 32;
  153.     if (fread(&nextMove,1,1,cb->cbf) != 1)
  154.     { setError(ERR_CANNOT_READ_MOVE_NUMBER);
  155.       return (long) NULL;
  156.     }
  157.     rawBytes += 1;
  158.  
  159.     cg->nextMove = ((short) nextMove) + 1;
  160.  
  161.     for (rank=0; rank<8; rank++)
  162.     { for (file=0; file<8; file+=2)
  163.       { unsigned char b = board[rank*4+file/2];
  164.  
  165.     cg->board[makeSquare(file,rank)] = (Piece) (b >> 4);
  166.     cg->board[makeSquare(file+1,rank)] = (Piece) (b & 0xf);
  167.       }
  168.     }
  169.   }
  170.  
  171.   { unsigned char k;
  172.     int i;
  173.     int l = cg->textLength;
  174.  
  175.     k = 3*l;
  176.     for (i=l-1; i>=0; i--)
  177.     { cg->text[i] ^= k;
  178.       k *= 3;
  179.     }
  180.   }
  181.  
  182.   { unsigned char k;
  183.     int i;
  184.     int l = cg->movesLength;
  185.  
  186.     k = 7*(l+1);
  187.     for (i=l-1; i>0; i--)
  188.     { k *= 7;
  189.       cg->moves[i] ^= k;
  190.     }
  191.   }
  192.  
  193.   return rawBytes;
  194. }
  195.  
  196.  
  197. /*------------------------------------------------------------
  198.  *  Counting
  199.  *------------------------------------------------------------*/
  200.  
  201. long
  202. countCbGame(CbGame cg, CBase cb, long no)
  203. { long pos;                /* Position in file */
  204.   unsigned char h[14];            /* Undecoded game header */
  205.   CbHeader ch = cg->header;        /* Game header */
  206.   long rawBytes = 0;
  207.  
  208.   resetCbGame(cg);
  209.   environmentError(cb, NULL, no);
  210.   if (no < 1 || no > getNoGamesCBase(cb))
  211.   { setError(ERR_GAME_NUMBER_OUT_OF_RANGE);
  212.     return (long) NULL;
  213.   }
  214.  
  215.   pos = getIndexGameCBase(cb, no);
  216.   if (fseek(cb->cbf, pos, 0))
  217.   { setError(ERR_CANNOT_SEEK);
  218.     return (long) NULL;
  219.   }
  220.  
  221.   if (fread(h,1,14,cb->cbf) != 14)
  222.   { setError(ERR_CANNOT_READ_HEADER);
  223.     return (long) NULL;
  224.   }
  225.   rawBytes += 14;
  226.   
  227.   initCbHeader(ch, h);
  228.   if (foundError())
  229.     return (long) NULL;
  230.  
  231.   cg->textLength = playersLengthCbHeader(ch) + sourceLengthCbHeader(ch);
  232.   cg->movesLength = movesLengthCbHeader(ch);
  233.   cg->commentLength = commentLengthCbHeader(ch);
  234.  
  235.   rawBytes += cg->textLength;
  236.   rawBytes += cg->movesLength;
  237.   rawBytes += cg->commentLength;
  238.  
  239.   if (!fullGameCbHeaderP(ch))
  240.   { rawBytes += 32;
  241.     rawBytes += 1;
  242.   }
  243.  
  244.   return rawBytes;
  245. }
  246.  
  247.  
  248. bool
  249. extractHeaderCbGame(CbGame cg, Game game)
  250. { unsigned int slen;
  251.   unsigned int plen;
  252.   CbHeader ch = cg->header;
  253.  
  254.   game->year = yearCbHeader(ch);
  255.  
  256.   switch(ch->result)
  257.   { case 0:    game->result = BLACK_WINS;  break;
  258.     case 1:    game->result = DRAW;  break;
  259.     case 2:    game->result = WHITE_WINS;  break;
  260.     case 3:    game->result = NO_RESULT;  break;
  261.     case 7:    game->result = WHITE_WINNING;  break;
  262.     case 11:    game->result = WHITE_ADVANTAGE;  break;
  263.     case 15:    game->result = WHITE_BETTER;  break;
  264.     case 19:    game->result = EQUALITY;  break;
  265.     case 23:    game->result = UNCLEAR;  break;
  266.     case 27:    game->result = BLACK_BETTER;  break;
  267.     case 31:    game->result = BLACK_ADVANTAGE;  break;
  268.     case 35:    game->result = BLACK_WINNING;  break;
  269.     case 39:    game->result = COMPENSATION;  break;
  270.     case 43:    game->result = COMPENSATION;  break;
  271.     case 47:    game->result = WITH_COUNTERPLAY;  break;
  272.     case 51:    game->result = WITH_INITIATIVE;  break;
  273.     case 55:    game->result = WITH_ATTACK;  break;
  274.     case 59:    game->result = TIME_TROUBLE;  break;
  275.     case 63:    game->result = ONLY_MOVE;  break;
  276.     default:    setError(ERR_ILLEGAL_RESULT);
  277.             game->result = NO_RESULT;
  278.   }
  279.  
  280.   plen = playersLengthCbHeader(ch);
  281.   slen = sourceLengthCbHeader(ch);
  282.  
  283.   game->eloWhite = whiteEloCbHeader(ch);
  284.   game->eloBlack = blackEloCbHeader(ch);
  285.  
  286.   game->moves = movesCbHeader(ch);
  287.   game->plies = game->moves * 2;
  288.   strcpy(game->eco, ecoCbHeader(ch));
  289.  
  290.   game->flags |= (flags2bit6CbHeader(ch) ? GAME_FLAGS2_BIT6 : 0);
  291.   game->flags |= (deletedCbHeaderP(ch) ? GAME_DELETED : 0);
  292.   game->flags |= (markedCbHeaderP(ch) ? GAME_MARKED : 0);
  293.  
  294.   strncpy(game->players, cg->text, plen);
  295.   game->players[plen] = '\0';
  296.  
  297.   strncpy(game->source, &cg->text[plen], slen);
  298.   game->source[slen] = '\0';
  299.  
  300.   if (!fullGameCbHeaderP(ch))
  301.   { Position p;
  302.  
  303.     p = game->position = newPosition();
  304.     memcpy(p->board, cg->board, sizeof(Piece) * 64);
  305.     p->nextMove = cg->nextMove;
  306.     p->toMove = (ch->flags1 & COLOUR_TO_MOVE_MASK ? BLACK : WHITE);
  307.     p->enPassant = ch->flags2 & EN_PASSANT_MASK;
  308.     p->castling = 0;
  309.     if (ch->flags1 & WHITE_CASTLE_LONG_MASK)
  310.       p->castling |= WHITE_LONG;
  311.     if (ch->flags1 & WHITE_CASTLE_SHORT_MASK)
  312.       p->castling |= WHITE_SHORT;
  313.     if (ch->flags1 & BLACK_CASTLE_LONG_MASK)
  314.       p->castling |= BLACK_LONG;
  315.     if (ch->flags1 & BLACK_CASTLE_SHORT_MASK)
  316.       p->castling |= BLACK_SHORT;
  317.   } else
  318.     game->flags |= GAME_INITIAL_POSITION;
  319.  
  320.   return TRUE;
  321. }
  322.  
  323.  
  324. bool
  325. extractMovesCbGame(CbGame cg, Game game)
  326. { int plies = cg->movesLength;
  327.   unsigned char *comments;
  328.   Position pos;
  329.   Move move;
  330.   int i;
  331.   int n;
  332.  
  333.   if (containsVariationsGameP(game))
  334.     return extractVariationsCbGame(cg, game);
  335.  
  336.   comments = cg->comments;
  337.   pos = newPosition();
  338.  
  339.   for (i=0; i<plies; i++)
  340.   { if (cg->moves[i] == START_VARIATION || cg->moves[i] == END_VARIATION)
  341.     { setError(ERR_VARIATION_SEEN);
  342.       freePosition(pos);
  343.       return FALSE;
  344.     }
  345.  
  346.     if (i == 0)
  347.       move = game->firstMove = newMove();
  348.     else
  349.       move = move->next = newMove();
  350.  
  351.     n = cg->moves[i] & 0x7f;
  352.     if (!getMovePosition(pos,n,move))
  353.     { setError(ERR_CANNOT_INTERPRET_MOVE);
  354.       freePosition(pos);
  355.       return FALSE;
  356.     }
  357.     doMovePosition(pos, move);
  358.     if (cg->moves[i] & 0x80)        /* Comment */
  359.       comments = commentMove(move, comments);
  360.     if (foundError())
  361.       return FALSE;
  362.   }
  363.  
  364.   game->plies = plies;
  365.   if (game->moves != (plies+1)/2)
  366.   { setError(ERR_MOVE_COUNT_INCORRECT);
  367.     freePosition(pos);
  368.     return FALSE;
  369.   }
  370.  
  371.   freePosition(pos);
  372.   
  373.   return TRUE;
  374. }
  375.  
  376.  
  377. /*  The code below is a bit "hairy".
  378.  */
  379.  
  380. #define MAX_LEVELS    (MAX_LEVEL_NESTING*2)
  381.  
  382. static bool
  383. extractVariationsCbGame(CbGame cg, Game game)
  384. { int l;
  385.   int i;
  386.   int j;
  387.   int v;
  388.   int n;
  389.   unsigned char *comments;
  390.   Position pos;
  391.   Position variations[MAX_LEVELS];    /* Positions at given level */
  392.   Move currentMoves[MAX_LEVELS];    /* Current move at given level */
  393.  
  394.   v = 0;    /* Depth of variation */
  395.   j = 0;    /* Moves seen */
  396.   l = 0;    /* Plies seen */
  397.   comments = cg->comments;
  398.  
  399.   for (i=0; i<MAX_LEVELS; i++)
  400.   { variations[i] = newPosition();
  401.     currentMoves[i] = NULL;
  402.   }
  403.  
  404.   for (i=0; i<cg->movesLength; i++)
  405.   { Move move;
  406.  
  407.     if (cg->moves[i] == START_VARIATION)
  408.     { v += 2;
  409.       copyPosition(variations[v], variations[v-1]);
  410.       currentMoves[v] = NULL;
  411.       continue;
  412.     }
  413.  
  414.     if (   cg->moves[i] == END_VARIATION
  415.     && (i+1) < cg->movesLength
  416.     && cg->moves[i+1] == START_VARIATION)
  417.     { copyPosition(variations[v], variations[v-1]);
  418.       i++;
  419.       currentMoves[v] = NULL;
  420.       continue;
  421.     }
  422.  
  423.     if (cg->moves[i] == END_VARIATION)
  424.     { v -= 2;
  425.       continue;
  426.     }
  427.  
  428.     if ((i+1) < cg->movesLength && cg->moves[i+1] == START_VARIATION)
  429.     { copyPosition(variations[v+1], variations[v]);
  430.       currentMoves[v+1] = NULL;
  431.     }
  432.  
  433.     pos = variations[v];
  434.     move = currentMoves[v];
  435.  
  436.     if (v == 0)
  437.     { if (move == NULL)
  438.           move = game->firstMove = newMove();
  439.       else
  440.     move = move->next = newMove();
  441.     } else
  442.     { if (move == NULL)
  443.       { Move alternative;
  444.  
  445.     move = newMove();
  446.     alternative = currentMoves[v-2];
  447.         while (alternative->alternative)
  448.       alternative = alternative->alternative;
  449.     alternative->alternative = move;
  450.       } else
  451.         move = move->next = newMove();
  452.     }
  453.  
  454.     currentMoves[v] = move;
  455.  
  456.     { if (pos->toMove == WHITE && v == 0)
  457.     j++;
  458.       n = cg->moves[i] & 0x7f;
  459.       if (!getMovePosition(pos,n,move) /* || (l>=m) */)
  460.       { setError(ERR_CANNOT_INTERPRET_MOVE);
  461.     goto errorFound;
  462.       }
  463.       doMovePosition(pos, move);
  464.       if (cg->moves[i] & 0x80)        /* Comment */
  465.     comments = commentMove(move, comments);
  466.       if (v == 0)
  467.     l++;
  468.       if (foundError())
  469.     goto errorFound;
  470.     }
  471.   }
  472.  
  473.   for (i=0; i<MAX_LEVELS; i++)
  474.     freePosition(variations[i]);
  475.  
  476.   game->plies = l;
  477.   if (game->moves != j)
  478.   { setError(ERR_MOVE_COUNT_INCORRECT);
  479.     return FALSE;
  480.   }
  481.   
  482.   return TRUE;
  483.  
  484. errorFound:
  485.   for (i=0; i<MAX_LEVELS; i++)
  486.     freePosition(variations[i]);
  487.   return FALSE;
  488. }
  489.  
  490.  
  491. /*------------------------------------------------------------
  492.  *  Debugging
  493.  *------------------------------------------------------------*/
  494.  
  495. void
  496. dumpCommentsCbGame(CbGame cg, FILE *fd)
  497. { unsigned char *s;
  498.   int i;
  499.  
  500.   if (cg->commentLength == 0)
  501.     return;
  502.  
  503.   fprintf(fd, "Comments (%x; %d):", (int) cg->comments, cg->commentLength);
  504.   for (i=0, s=cg->comments; i<cg->commentLength; i++, s++)
  505.   { if (*s == 0xff)
  506.       fprintf(fd, "\n");
  507.     fprintf(fd, "%03o ", *s);
  508.   }
  509.   fprintf(fd, "\n");
  510. }
  511.