home *** CD-ROM | disk | FTP | other *** search
/ Informática Multimedia: Special Games / INFESPGAMES.mdf / os2 / backgam / source / fibsboar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-25  |  20.6 KB  |  919 lines

  1. /*
  2.  * fibsboard.c
  3.  * Copyright (c)1993 by Andreas Schneider. All rights reserved.
  4.  *
  5.  * This routine may be used in clients for my FIBS backgammon server
  6.  * as long as the source of such a program is available free of charge.
  7.  * NO WARRANTY:
  8.  * Those routines are not supposed to do anything useful!
  9.  *
  10.  * History:
  11.  *
  12.  * V 1.000 - May 24, 1993
  13.  * First release. Quick hack based on the routines of the server.
  14.  *
  15.  * V 1.001 - May 24, 1993
  16.  * Added boardstyle 4
  17.  *
  18.  * V 1.002 - May 24, 1993
  19.  * All lines have fixed length now.
  20.  *
  21.  * V 1.003 - May 24, 1993
  22.  * Added rotine board_diff
  23.  * 
  24.  * V 1.004 - May 25, 1993
  25.  * Fixed a couple of bugs
  26.  *
  27.  */
  28.  
  29. /* #defining DEBUG produces lots of output */
  30. /*#define DEBUG*/
  31.  
  32. /*
  33.  * if STAND_ALONE is #defined this file compiles into a filter that
  34.  * converts rawboard lines into ASCII boards and leaves other lines
  35.  * unchanged (might be handy for use with pipes)
  36.  */
  37.  
  38. /* #defining BLANK_LINE prints an extra blank line below the board */
  39. /*#define BLANK_LINE*/
  40.  
  41. /*#define STAND_ALONE*/
  42.  
  43. #include <string.h>
  44. #include <stdlib.h>
  45. #include <stdio.h>              /* could be omitted if DEBUG and STAND_ALONE are not #defined */
  46.  
  47. #ifndef Export
  48. #define Export
  49. #endif
  50.  
  51. #ifndef Prototype
  52. #define Prototype extern
  53. #endif
  54.  
  55. #ifndef Local
  56. #define Local static
  57. #endif
  58.  
  59. #ifndef min
  60. #define min(A,B)  ((A) < (B)? (A) : (B))
  61. #endif
  62.  
  63. #ifndef YES
  64. #define YES 1
  65. #endif
  66.  
  67. #ifndef NO
  68. #define NO 0
  69. #endif
  70.  
  71. /* For use with telnet SIMPLE_NEW_LINES should not be #defined.
  72.  * The telnet protocol needs both \r and \n to be sent.
  73.  */
  74.  
  75. #define SIMPLE_NEW_LINES
  76.  
  77. #ifdef SIMPLE_NEW_LINES
  78. #define NEW_LINE "\n"
  79. #else
  80. #define NEW_LINE "\r\n"
  81. #endif
  82.  
  83. #ifndef LINE_LIMIT
  84. #define LINE_LIMIT 79
  85. #endif
  86.  
  87. #define UPPER_HALF 1
  88. #define LOWER_HALF 0
  89. #define COLOR_O 1
  90. #define COLOR_X -1
  91. #define UNLIMITED 9999
  92.  
  93. /* nifty #define's for easy debugging */
  94.  
  95. #ifdef DEBUG
  96. #ifdef __STDC__
  97. #define get_int(var) \
  98.   do { \
  99.      if (!get_number(& var )) \
  100.      { \
  101.        fputs("Shriek! " #var "not read\n",stderr); \
  102.        return NO; \
  103.      } \
  104.      else \
  105.        fprintf(stderr,#var " set to %i\n", var ); \
  106.   } while (0)
  107. #endif /* __STDC__ */
  108. #endif
  109.  
  110. #ifndef get_int
  111. #define get_int(var) \
  112.   do { \
  113.     if (!get_number(& var )) \
  114.       return NO; \
  115.   } while (0)
  116. #endif
  117.  
  118. /* Prototypes: */
  119.  
  120. #ifdef __STDC__
  121.  
  122. Prototype int do_board (char *);
  123. Prototype char *board_diff (int *, int *);
  124. Local void fill_line (char *, int);
  125. Local void top_lines (void);
  126. Local void bottom_lines (void);
  127. Local void middle_line (void);
  128. Local void line_5_pos (int);
  129. Local void line_1to4_pos (int, int);
  130. Local void six_pos_up (int, int);
  131. Local void six_pos_down (int, int);
  132. Local void draw_bar (int, int);
  133. Local void one_line (int, int, int, int);
  134. Local int decode_board (void);
  135. Local int get_number (int *);
  136. Local void init_board (void);
  137.  
  138. #endif
  139.  
  140. /* Variables that can be read from extern routines: */
  141. /* The style variable can be set to 1 or 2 by extern routines for different style */
  142. Export int style = 4;
  143.  
  144. /* the board_buffer contains the board in ASCII representation */
  145. Export char board_buffer[2048];
  146.  
  147. /* Local variables set by scanning rawboard output */
  148. Local char player_name[128];
  149. Local char opponent_name[128];
  150. Local int match_length;
  151. Local int player_got;
  152. Local int opponent_got;
  153. Local int board[26];
  154. Local int turn;
  155. Local int die1;
  156. Local int die2;
  157. Local int opponent_die1;
  158. Local int opponent_die2;
  159. Local int cube;
  160. Local int player_may_double;
  161. Local int opponent_may_double;
  162. Local int was_doubled;
  163. Local int color;
  164. Local int direction;
  165. Local int home;
  166. Local int bar;
  167. Local int player_on_home;
  168. Local int opponent_on_home;
  169. Local int player_on_bar;
  170. Local int opponent_on_bar;
  171. Local int can_move;
  172. Local int forced_move;
  173. Local int did_crawford;
  174. Local int max_redoubles;
  175.  
  176. /* Other variables used by routines in this file */
  177. Local char buf[128];
  178. Local char cur_line[256];
  179. Local char spaces[128];
  180. Local char old_board_buffer[2048];
  181. Local char *old_board_ptr;
  182. Local int old_board_line;
  183. Local int old_board_col;
  184. Local char difference[2048];
  185.  
  186. /* appends lots of spaces to string and limits to LINE_LIMIT chars.
  187.  * if newline == YES then NEW_LINE is added. After filling the line
  188.  * it is appended to board_buffer.
  189.  */
  190. void
  191. fill_line (string, newline)
  192.      char *string;
  193.      int newline;
  194. {
  195.   strcat (string, spaces);
  196.   string[LINE_LIMIT - 1] = 0;
  197.   if (newline)
  198.     strcat (string, NEW_LINE);
  199.   strcat (board_buffer, string);
  200. }
  201.  
  202. void
  203. top_lines ()
  204. {
  205.   if (color == COLOR_O)
  206.   {
  207.     switch (style)
  208.     {
  209.       default:                 /* style 4 is default */
  210.       case 1:
  211.       case 4:
  212.         strcpy (cur_line, "   +13-14-15-16-17-18-------19-20-21-22-23-24-+ X: ");
  213.         break;
  214.       case 2:
  215.         strcpy (cur_line, "    13 14 15 16 17 18       19 20 21 22 23 24");
  216.         fill_line (cur_line, YES);
  217.         strcpy (cur_line, "   +------------------------------------------+ X: ");
  218.         break;
  219.     }
  220.   }
  221.   else
  222.   {
  223.     switch (style)
  224.     {
  225.       default:
  226.       case 1:
  227.       case 4:
  228.         strcpy (cur_line, "   +-1--2--3--4--5--6--------7--8--9-10-11-12-+ O: ");
  229.         break;
  230.       case 2:
  231.         strcpy (cur_line, "     1  2  3  4  5  6        7  8  9 10 11 12");
  232.         fill_line (cur_line, YES);
  233.         strcpy (cur_line, "   +------------------------------------------+ O: ");
  234.         break;
  235.     }
  236.   }
  237.   strcpy (buf, opponent_name);
  238.   /* limit name to 15 chars */
  239.   buf[15] = 0;
  240.   strcat (cur_line, buf);
  241.   sprintf (buf, " - score: %i", opponent_got);
  242.   strcat (cur_line, buf);
  243.   fill_line (cur_line, YES);
  244. }
  245.  
  246. void
  247. bottom_lines ()
  248. {
  249.   /* draw bottom of the board */
  250.   switch (style)
  251.   {
  252.     default:
  253.     case 1:
  254.     case 4:
  255.       if (color == COLOR_O)
  256.         strcpy (cur_line, "   +12-11-10--9--8--7--------6--5--4--3--2--1-+ O: ");
  257.       else
  258.         strcpy (cur_line, "   +24-23-22-21-20-19-------18-17-16-15-14-13-+ X: ");
  259.       break;
  260.     case 2:
  261.       strcpy (cur_line, "   +------------------------------------------+ ");
  262.       strcat (cur_line, (color == COLOR_O) ? "O: " : "X: ");
  263.       break;
  264.   }
  265.   /* now inform about score */
  266.   strcpy (buf, player_name);
  267.   /* limit name to 15 chars */
  268.   buf[15] = 0;
  269.   strcat (cur_line, buf);
  270.   sprintf (buf, " - score: %i", player_got);
  271.   strcat (cur_line, buf);
  272.   /* for style 2 we also need the numbers below the board */
  273.   if (style == 2)
  274.   {
  275.     fill_line (cur_line, YES);
  276.     if (color == COLOR_O)
  277.       strcpy (cur_line, "    12 11 10  9  8  7        6  5  4  3  2  1");
  278.     else
  279.       strcpy (cur_line, "    24 23 22 21 20 19       18 17 16 15 14 13");
  280.   }
  281.   /* this routine does not append a NEW_LINE */
  282.   fill_line (cur_line, NO);
  283. }
  284.  
  285. void
  286. middle_line ()
  287. {
  288.   /* that's easy :-) */
  289.   if (color == COLOR_O)
  290.   {
  291.     strcpy (cur_line, "  v|                  |BAR|                   |");
  292.   }
  293.   else
  294.   {
  295.     strcpy (cur_line, "   |                  |BAR|                   |v");
  296.   }
  297.   if (match_length == UNLIMITED)
  298.     sprintf (buf, "    unlimited match");
  299.   else
  300.     sprintf (buf, "    %i-point match", match_length);
  301.   strcat (cur_line, buf);
  302.   if (player_may_double && opponent_may_double)
  303.   {
  304.     sprintf (buf, " - Cube: %i", cube);
  305.     strcat (cur_line, buf);
  306.   }
  307.   fill_line (cur_line, YES);
  308. }
  309.  
  310. /* If there are more than 5 pieces on a position
  311.  * this routine will write the number of pieces on
  312.  * this position instead of X or O
  313.  */
  314. void
  315. line_5_pos (pos)
  316.      int pos;
  317. {
  318.   if (board[pos] == 5)
  319.   {
  320.     strcat (cur_line, " O ");
  321.   }
  322.   else if (board[pos] == -5)
  323.   {
  324.     strcat (cur_line, " X ");
  325.   }
  326.   else if (abs (board[pos]) > 5)
  327.   {
  328.     strcpy (buf, "");
  329.     sprintf (buf, "%2i ", abs (board[pos]));
  330.     strcat (cur_line, buf);
  331.   }
  332.   else
  333.     /* less than 5 of any kind */
  334.   {
  335.     strcat (cur_line, "   ");
  336.   }
  337. }
  338.  
  339. /* This routine knows how to write 'X' or 'O' or ' ' */
  340.  
  341. void
  342. line_1to4_pos (line, pos)
  343.      int line;
  344.      int pos;
  345. {
  346.   if (board[pos] >= line)
  347.   {
  348.     strcat (cur_line, " O ");
  349.   }
  350.   else if (board[pos] <= -line)
  351.   {
  352.     strcat (cur_line, " X ");
  353.   }
  354.   else
  355.   {
  356.     strcat (cur_line, "   ");
  357.   }
  358. }
  359.  
  360. /* This routine writes half a line of the board with increasing numbers */
  361.  
  362. void
  363. six_pos_up (line, from_pos)
  364.      int line;
  365.      int from_pos;
  366. {
  367.   int pos;
  368.  
  369.   for (pos = from_pos; pos < from_pos + 6; pos++)
  370.   {
  371.     if (line == 5)
  372.     {
  373.       line_5_pos (pos);
  374.     }
  375.     else
  376.     {
  377.       line_1to4_pos (line, pos);
  378.     }
  379.   }
  380. }
  381.  
  382. /* similar routine with decreasing numbers */
  383.  
  384. void
  385. six_pos_down (line, from_pos)
  386.      int line;
  387.      int from_pos;
  388. {
  389.   int pos;
  390.  
  391.   for (pos = from_pos; pos > from_pos - 6; pos--)
  392.   {
  393.     if (line == 5)
  394.     {
  395.       line_5_pos (pos);
  396.     }
  397.     else
  398.     {
  399.       line_1to4_pos (line, pos);
  400.     }
  401.   }
  402. }
  403.  
  404. /* write the center of the board */
  405.  
  406. void
  407. draw_bar (line, half)
  408.      int line;
  409.      int half;
  410. {
  411.   if (line <= 4 && half == UPPER_HALF)
  412.   {
  413.     /* draw opponents pieces on bar */
  414.     if (opponent_on_bar < line)
  415.     {
  416.       /* no need to show a piece on that line */
  417.       strcat (cur_line, "|   | ");
  418.     }
  419.     else
  420.     {
  421.       /* there are enough pieces on the bar */
  422.       if (color == COLOR_O)
  423.         /* opponent has X */
  424.         strcat (cur_line, "| X | ");
  425.       else
  426.         /* opponent has O */
  427.         strcat (cur_line, "| O | ");
  428.     }
  429.   }
  430.   else if (line == 5 && half == UPPER_HALF)
  431.   {
  432.     if (opponent_on_bar <= 4)
  433.       strcat (cur_line, "|   | ");
  434.     else if (opponent_on_bar == 5)
  435.     {
  436.       if (color == COLOR_O)
  437.         /* opponent has X */
  438.         strcat (cur_line, "| X | ");
  439.       else
  440.         /* opponent has O */
  441.         strcat (cur_line, "| O | ");
  442.     }
  443.     else
  444.     {
  445.       /* opponent has more than 5 pieces on bar - write the number */
  446.       strcpy (buf, "");
  447.       sprintf (buf, "|%2i | ", abs (opponent_on_bar));
  448.       strcat (cur_line, buf);
  449.     }
  450.   }
  451.   else if (line == 5 && half == LOWER_HALF)
  452.   {
  453.     if (player_on_bar <= 4)
  454.       strcat (cur_line, "|   | ");
  455.     else if (player_on_bar == 5)
  456.     {
  457.       if (color == COLOR_O)
  458.         strcat (cur_line, "| O | ");
  459.       else
  460.         strcat (cur_line, "| X | ");
  461.     }
  462.     else
  463.     {
  464.       /* user has more than 5 pieces on bar */
  465.       strcpy (buf, "");
  466.       sprintf (buf, "|%2i | ", abs (player_on_bar));
  467.       strcat (cur_line, buf);
  468.     }
  469.   }
  470.   else
  471.   {
  472.     /* line<4 && half==LOWER_HALF: draw own pieces on bar */
  473.     if (player_on_bar < line)
  474.     {
  475.       /* not enough pieces on bar */
  476.       strcat (cur_line, "|   | ");
  477.     }
  478.     else
  479.     {
  480.       /* enough pieces - draw one */
  481.       if (color == COLOR_X)
  482.         strcat (cur_line, "| X | ");
  483.       else
  484.         strcat (cur_line, "| O | ");
  485.     }
  486.   }
  487. }
  488.  
  489. /* write one line of the board */
  490.  
  491. void
  492. one_line (line, from_pos, to_pos, half)
  493.      int line;
  494.      int from_pos;
  495.      int to_pos;
  496.      int half;
  497. {
  498.   strcpy (cur_line, "   |");
  499.   if (from_pos < to_pos)
  500.   {
  501.     /* count upwards - first six first */
  502.     six_pos_up (line, from_pos);
  503.     /* now do the bar */
  504.     draw_bar (line, half);
  505.     /* now the next six */
  506.     six_pos_up (line, from_pos + 6);
  507.   }
  508.   else
  509.   {
  510.     /* count downwards  */
  511.     six_pos_down (line, from_pos);
  512.     /* the bar: */
  513.     draw_bar (line, half);
  514.     /* the rest */
  515.     six_pos_down (line, from_pos - 6);
  516.   }
  517.   /* line must end. That's how: */
  518.   if (line == 2 && style == 4)
  519.   {
  520.     sprintf (buf, "|    BAR: %i  OFF: %i",
  521.              (half == UPPER_HALF) ? opponent_on_bar : player_on_bar,
  522.              (half == UPPER_HALF) ? opponent_on_home : player_on_home);
  523.     strcat (cur_line, buf);
  524.   }
  525.   else if (line == 3 && style == 4)
  526.   {
  527.     if (half == UPPER_HALF && opponent_may_double && !player_may_double)
  528.     {
  529.       sprintf (buf, "|    Cube: %i", cube);
  530.       strcat (cur_line, buf);
  531.     }
  532.     else if (half == LOWER_HALF && player_may_double && !opponent_may_double)
  533.     {
  534.       sprintf (buf, "|    Cube: %i", cube);
  535.       strcat (cur_line, buf);
  536.     }
  537.     else
  538.       strcat (cur_line, "|");
  539.   }
  540.   else if (line == 4 && style == 4)
  541.   {
  542.     if (half == UPPER_HALF && die1 == 0 && opponent_die1 != 0)
  543.     {
  544.       sprintf (buf, "|    rolled %i %i", opponent_die1, opponent_die2);
  545.       strcat (cur_line, buf);
  546.     }
  547.     else if (half == LOWER_HALF && die1 != 0)
  548.     {
  549.       sprintf (buf, "|    rolled %i %i", die1, die2);
  550.       strcat (cur_line, buf);
  551.     }
  552.     else
  553.       strcat (cur_line, "|");
  554.   }
  555.   else if (line == 5 && half == LOWER_HALF && match_length == UNLIMITED)
  556.   {
  557.     /* here goes information about possible redoubles */
  558.     strcat (cur_line, "|    ");
  559.     switch (max_redoubles)
  560.     {
  561.       case 0:
  562.         strcpy (buf, "No redoubles");
  563.         break;
  564.       case 1:
  565.         strcpy (buf, "1 redouble");
  566.         break;
  567.       case UNLIMITED:
  568.         strcpy (buf, "Unlimited redoubles");
  569.         break;
  570.       default:
  571.         sprintf (buf, "%i redoubles", max_redoubles);
  572.         break;
  573.     }
  574.     strcat (cur_line, buf);
  575.   }
  576.   else
  577.     strcat (cur_line, "|");
  578.   fill_line (cur_line, YES);
  579. }
  580.  
  581. /* get one more integer number from rawboard string
  582.  * The routine returns NO (0) if no more numbers available
  583.  */
  584.  
  585. int
  586. get_number (int_var)
  587.      int *int_var;
  588. {
  589.   char *token;
  590.  
  591.   token = strtok (NULL, ":");
  592.   if (!token)
  593.     return NO;
  594.   *int_var = atoi (token);
  595.   return YES;
  596. }
  597.  
  598. void
  599. init_board ()
  600. {
  601.   int pos;
  602.  
  603.   strcpy (player_name, "noboby");
  604.   strcpy (opponent_name, "nobody");
  605.   match_length = 0;
  606.   player_got = 0;
  607.   opponent_got = 0;
  608.   for (pos = 0; pos < 26; pos++)
  609.     board[pos] = 0;
  610.   turn = 0;
  611.   die1 = 0;
  612.   die2 = 0;
  613.   opponent_die1 = 0;
  614.   opponent_die2 = 0;
  615.   cube = 1;
  616.   player_may_double = YES;
  617.   opponent_may_double = YES;
  618.   was_doubled = NO;
  619.   color = COLOR_O;
  620.   direction = 1;
  621.   home = 25;
  622.   bar = 0;
  623.   player_on_home = 0;
  624.   opponent_on_home = 0;
  625.   can_move = 0;
  626.   forced_move = 0;
  627.   did_crawford = NO;
  628.   max_redoubles = NO;
  629. }
  630.  
  631. /* get all the integer numbers from the rawboard string.
  632.  * The routine returns NO if an error occurs.
  633.  * Note that get_int is a macro that does 'return NO' if
  634.  * get_number fails!
  635.  */
  636.  
  637. int
  638. decode_board ()
  639. {
  640.   int pos;
  641.  
  642.   get_int (match_length);
  643.   get_int (player_got);
  644.   get_int (opponent_got);
  645.   for (pos = 0; pos < 26; pos++)
  646.     get_int (board[pos]);
  647.   get_int (turn);
  648.   get_int (die1);
  649.   get_int (die2);
  650.   get_int (opponent_die1);
  651.   get_int (opponent_die2);
  652.   get_int (cube);
  653.   get_int (player_may_double);
  654.   get_int (opponent_may_double);
  655.   get_int (was_doubled);
  656.   get_int (color);
  657.   get_int (direction);
  658.   get_int (home);
  659.   get_int (bar);
  660.   get_int (player_on_home);
  661.   get_int (opponent_on_home);
  662.   get_int (player_on_bar);
  663.   get_int (opponent_on_bar);
  664.   get_int (can_move);
  665.   get_int (forced_move);
  666.   get_int (did_crawford);
  667.   get_int (max_redoubles);
  668.   return YES;
  669. }
  670.  
  671. /*
  672.  * do_board is the main routine that can be called by extern routines.
  673.  * It's argument is the rawboard line received from the backgammon
  674.  * server. If something goes wrong do_board returns NO (0), otherwise
  675.  * it returns YES (1). The board is stored in board_buffer. This
  676.  * variable contains all the lines of the board separated by the
  677.  * NEW_LINE string ("\r\n" or "\n"). The last line is not terminated
  678.  * by NEW_LINE. board_buffer is one string terminated by \0.
  679.  * If input==NULL the routine is used to initialize variables. The board
  680.  * that is produced in this case should be written by the client if the
  681.  * routine board_diff is used to update the board.
  682.  */
  683.  
  684. int
  685. do_board (input)
  686.      char *input;
  687. {
  688.   int line;
  689.   int count;
  690.   char copy_of_input[255];
  691.   char *token;
  692.  
  693.   for (count = 0; count < 127; count++)
  694.     spaces[count] = ' ';
  695.   spaces[count] = 0;
  696.   if (!input)
  697.   {
  698.     /* build an empty board */
  699.     init_board ();
  700.     strcpy (old_board_buffer, "");
  701.     old_board_ptr = old_board_buffer;
  702.     old_board_col = old_board_line = 1;
  703.   }
  704.   else
  705.   {
  706.     if (strstr (input, "board:") != input)
  707.       /* Oops! This is not a rawbord line! */
  708.       return NO;
  709.     /* extract board information from input */
  710.     strcpy (copy_of_input, input);
  711.     /* strtok will work on that copy (strtok destroys the string it scans) */
  712.     /* skip the 'board:' at the beginning of the line: */
  713.     token = strtok (copy_of_input, ":");
  714.     /* next line is player's name.. */
  715.     token = strtok (NULL, ":");
  716.     if (!token)
  717.       return NO;
  718.     else
  719.       strcpy (player_name, token);
  720.     /* .. followed by opponent's name */
  721.     token = strtok (NULL, ":");
  722.     if (!token)
  723.       return NO;
  724.     else
  725.       strcpy (opponent_name, token);
  726.     /* The following arguments are integers and scanned in decode_board */
  727.     if (!decode_board ())
  728.       return NO;
  729.     /* make a copy of the previous board */
  730.     strcpy (old_board_buffer, board_buffer);
  731.     old_board_ptr = old_board_buffer;
  732.     old_board_col = old_board_line = 1;
  733.   }
  734.   /* Fun starts here: */
  735.   /* clean board_buffer */
  736.   strcpy (board_buffer, "");
  737.   if (color == COLOR_O)
  738.   {
  739.     /* build board for O */
  740.     top_lines ();
  741.     for (line = 1; line <= 5; line++)
  742.       one_line (line, 13, 24, UPPER_HALF);
  743.     middle_line ();
  744.     for (line = 5; line >= 1; line--)
  745.       one_line (line, 12, 1, LOWER_HALF);
  746.     bottom_lines ();
  747.   }
  748.   else
  749.   {
  750.     /* build board for X */
  751.     top_lines ();
  752.     for (line = 1; line <= 5; line++)
  753.       one_line (line, 1, 12, UPPER_HALF);
  754.     middle_line ();
  755.     for (line = 5; line >= 1; line--)
  756.       one_line (line, 24, 13, LOWER_HALF);
  757.     bottom_lines ();
  758.   }
  759.   if (style != 4)
  760.   {
  761.     /* append the NEW_LINE that bottom_lines left out */
  762.     strcat (board_buffer, NEW_LINE);
  763. #ifdef BLANK_LINE
  764.     strcat (board_buffer, NEW_LINE);
  765. #endif
  766.     /* Show some more information below the board: */
  767.     sprintf
  768.       (buf, "   BAR: O-%i X-%i   OFF: O-%i X-%i   Cube: %i",
  769.        (color == COLOR_O) ? player_on_bar : opponent_on_bar,
  770.        (color == COLOR_X) ? player_on_bar : opponent_on_bar,
  771.        (color == COLOR_O) ? player_on_home : opponent_on_home,
  772.        (color == COLOR_X) ? player_on_home : opponent_on_home,
  773.        cube
  774.       );
  775.     strcpy (cur_line, buf);
  776.     /* show who owns the cube */
  777.     if (player_may_double == NO && opponent_may_double == YES)
  778.     {
  779.       /* owned by opponent */
  780.       sprintf (buf, " (owned by %s)", opponent_name);
  781.       strcat (cur_line, buf);
  782.     }
  783.     else if (player_may_double == YES && opponent_may_double == NO)
  784.     {
  785.       /* owned by player */
  786.       sprintf (buf, " (owned by %s)", player_name);
  787.       strcat (cur_line, buf);
  788.     }
  789.     if (die1 != 0)
  790.     {
  791.       sprintf (buf, "  %s rolled %i %i.", player_name, die1, die2);
  792.       strcat (cur_line, buf);
  793.     }
  794.     else if (opponent_die1 != 0)
  795.     {
  796.       sprintf (buf, "  %s rolled %i %i.",
  797.                opponent_name,
  798.                opponent_die1,
  799.                opponent_die2);
  800.       strcat (cur_line, buf);
  801.     }
  802.     fill_line(cur_line,NO);
  803.   }
  804.   if (!input)
  805.   {
  806.      strcpy(old_board_buffer,board_buffer);
  807.      old_board_ptr = old_board_buffer;
  808.      old_board_col = old_board_line = 1;
  809.   }
  810.   if (strlen(old_board_buffer)!=strlen(board_buffer))
  811.     fprintf(stderr,"!=");
  812.   return YES;
  813. }
  814.  
  815. /*
  816.  * This routine can be called after do_board. It compares the current
  817.  * board with the previous one. It sets x and y coordinates to the
  818.  * position where a change occured and return a pointer to a nul-terminated
  819.  * string representing the new text or NULL if no more changes can be found.
  820.  */
  821. char *
  822. board_diff (x, y)
  823.      int *x;
  824.      int *y;
  825. {
  826.   char *difference_ptr = difference;
  827.  
  828.   /* search for next difference */
  829.   /* first skip everything that's equal */
  830.   while (*old_board_ptr && *old_board_ptr == board_buffer[old_board_ptr - old_board_buffer])
  831.   {
  832.     if (*old_board_ptr == '\n')
  833.     {
  834.       old_board_line++;
  835.       old_board_col = 1;
  836.     }
  837.     else if (*old_board_ptr != '\r')
  838.       old_board_col++;
  839.     old_board_ptr++;
  840.   }
  841.   if (*old_board_ptr)
  842.   {
  843.     /* not 0 - we've found a difference */
  844.     /* set returned screen position */
  845.     *x = old_board_col;
  846.     *y = old_board_line;
  847.     /* now copy the difference to the string 'difference' */
  848.     *difference_ptr = 0;
  849.     while (*old_board_ptr && *old_board_ptr != board_buffer[old_board_ptr - old_board_buffer])
  850.     {
  851.       /* while the 2 boards differ */
  852.       *(difference_ptr++) = board_buffer[old_board_ptr - old_board_buffer];
  853.       if (*old_board_ptr == '\n')
  854.       {
  855.         old_board_line++;
  856.         old_board_col = 1;
  857.       }
  858.       else if (*old_board_ptr != '\r')
  859.         old_board_col++;
  860.       old_board_ptr++;
  861.     }
  862.     /* end of difference */
  863.     *difference_ptr = 0;
  864.     return difference;
  865.   }
  866.   /* no difference found - first while got to end of board_buffer */
  867.   return NULL;
  868. }
  869.  
  870. #ifdef STAND_ALONE
  871.  
  872. void
  873. usage (name)
  874.      char *name;
  875. {
  876.   fprintf (stderr, "usage: %s [optional_filename]\n", name);
  877. }
  878.  
  879. int
  880. main (argc, argv)
  881.      int argc;
  882.      char **argv;
  883. {
  884.   FILE *file;
  885.   char line[2048];
  886.   int x,
  887.     y;
  888.   char *diff;
  889.  
  890.   switch (argc)
  891.   {
  892.     case 1:
  893.       /* no argument */
  894.       file = stdin;
  895.       break;
  896.     case 2:
  897.       if ((file = fopen (argv[1], "r")) == NULL)
  898.       {
  899.         fprintf (stderr, "can't open file '%s'\n", argv[1]);
  900.         usage (argv[0]);
  901.         return 1;
  902.       }
  903.       break;
  904.     default:
  905.       usage (argv[0]);
  906.       return 1;
  907.       break;
  908.   }
  909.   while (fgets (line, sizeof line, file) == line)
  910.   {
  911.     if (do_board (line))
  912.       puts (board_buffer);
  913.     else
  914.       fputs (line, stdout);
  915.   }
  916.   return 0;
  917. }
  918. #endif
  919.