home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume11 / reve / part05 / boardstuff.c next >
C/C++ Source or Header  |  1990-11-15  |  12KB  |  509 lines

  1. /*LINTLIBRARY*/
  2.  
  3. /*  @(#)boardstuff.c 1.9 90/10/20
  4.  *
  5.  *  Various board routines used by reve.
  6.  *
  7.  *  Copyright (C) 1990 - Rich Burridge & Yves Gallot.
  8.  *  All rights reserved.
  9.  *
  10.  *  Permission is given to distribute these sources, as long as the
  11.  *  introductory messages are not removed, and no monies are exchanged.
  12.  *
  13.  *  You are forbidden from using Reve as is, or in a modified state, in
  14.  *  any tournaments, without the permission of the authors.
  15.  *
  16.  *  No responsibility is taken for any errors on inaccuracies inherent
  17.  *  either to the comments or the code of this program, but if reported
  18.  *  (see README file), then an attempt will be made to fix them.
  19.  */
  20.  
  21. #include <stdio.h>
  22. #include <ctype.h>
  23.  
  24. #ifndef SYSV
  25. #include <sys/time.h>
  26. #endif /*SYSV*/
  27.  
  28. #include "color.h"
  29. #include "reve.h"
  30. #include "extern.h"
  31.  
  32.  
  33. void
  34. animate_move(move)
  35. int move ;
  36. {
  37.   int x0, y0, x1, y1, x, y, dx, dy, ctr ;
  38.  
  39.   lock_screen(IS_ON) ;
  40.   get_xy(move, &x1, &y1) ;
  41.   dx = x1 ;
  42.   dy = y1 ;
  43.   if (x1 > y1)
  44.     {
  45.       ctr = dx / 2 ;
  46.       x = BBORDER ;
  47.       y = BBORDER ;
  48.       draw_piece(WHITE, x, CY+y, RINV) ;
  49.       while (x < x1)
  50.         {
  51. #ifndef SYSV
  52.           set_timer() ;
  53. #endif /*SYSV*/
  54.           x0 = x ;
  55.           y0 = y ;
  56.           x += move_delta ;
  57.           if ((ctr -= dy) < 0)
  58.             {
  59.               ctr += dx ;
  60.               y += move_delta ;
  61.             }
  62.           draw_piece(WHITE, x, CY+y, RINV) ;
  63.           draw_piece(WHITE, x0, CY+y0, RINV) ;
  64. #ifndef SYSV
  65.           nap_upto(1) ;
  66. #endif /*SYSV*/
  67.         }
  68.       draw_piece(WHITE, x, CY+y, RINV) ;
  69.     }
  70.   else
  71.     { 
  72.       ctr = dy / 2 ;
  73.       x = BBORDER ;
  74.       y = BBORDER ;
  75.       draw_piece(WHITE, x, CY+y, RINV) ;
  76.       while (y < y1)
  77.         {
  78. #ifndef SYSV
  79.           set_timer() ;
  80. #endif /*SYSV*/
  81.           x0 = x ;
  82.           y0 = y ;
  83.           y += move_delta ;
  84.           if ((ctr -= dx) < 0)
  85.             {
  86.               ctr += dy ;
  87.               x += move_delta ;
  88.             }
  89.           draw_piece(WHITE, x, CY+y, RINV) ;
  90.           draw_piece(WHITE, x0, CY+y0, RINV) ;
  91. #ifndef SYSV
  92.           nap_upto(1) ;
  93. #endif /*SYSV*/
  94.         }
  95.       draw_piece(WHITE, x, CY+y, RINV) ;
  96.     }
  97.   lock_screen(IS_OFF) ;
  98. }
  99.  
  100.  
  101. /*  This routine checks to see if a move can be made for this player.
  102.  *  If not, various checks are made to see if the game is finished.
  103.  *  Return value indicates if a move can be made.
  104.  */
  105.  
  106. check(player)
  107. int player ;
  108. {
  109.   if ((!count(&board, BLACK)) || (!count(&board, WHITE)) ||
  110.       ((count(&board, BLACK) + count(&board, WHITE)) == 64))
  111.     {
  112.       who_wins() ;
  113.       last_cmode = cmode ;     /* Save previous value in case of undo. */
  114.       cmode = GAME_OVER ;
  115.       message(PANEL_MES, "Game over") ;
  116.       return(FALSE) ;
  117.     }
  118.   if ((move = valid_move(&board, player)) == FALSE)
  119.     {
  120.       SPRINTF(line, "%s is forced to pass",
  121.                     (player == BLACK) ? "Black" : "White") ;
  122.       message(PANEL_MES, line) ;
  123.       set_turn(OPPONENT(player)) ;
  124.       if ((move = valid_move(&board, OPPONENT(player))) == FALSE)
  125.         {
  126.           who_wins() ;
  127.           last_cmode = cmode ;
  128.           cmode = GAME_OVER ;
  129.           message(PANEL_MES, "Game over") ;
  130.         }
  131.       return(FALSE) ;
  132.     }
  133.   return(TRUE) ;
  134. }
  135.  
  136.  
  137. void
  138. computer_move(player)
  139. int player ;
  140. {
  141.   for (;;)
  142.     if (check(player) == TRUE)
  143.       {
  144.         think(player) ;
  145.         if (check(OPPONENT(player)) == TRUE) break ;
  146.         if (cmode == GAME_OVER) break ;
  147.       }
  148.     else
  149.       { 
  150.         if (cmode != GAME_OVER) cmode = (enum cantype) ((int) cmode - 1) ;
  151.         return ;
  152.       }
  153. }
  154.  
  155.  
  156. count(board, player)    /* Count the number of player pieces on the board. */
  157. int player ;
  158. BOARD *board ;
  159. {
  160.   int i, n ;
  161.  
  162.   n = 0 ;
  163.   FOR_BOARD(i)
  164.     if (board->square[i] == player) n++ ;
  165.   return(n) ;
  166. }
  167.  
  168.  
  169. void
  170. do_move(player)
  171. int player ;
  172. {
  173.   int taken ;                /* Number of pieces flipped this go. */
  174.  
  175.   taken = formfliplist(move, player) ;
  176.   update_board_image(player) ;
  177.   SPRINTF(line, "%s took %d %s", (player == BLACK) ? "Black" : "White",
  178.                           taken, (taken  == 1)     ? "piece" : "pieces") ;
  179.   message(PANEL_MES, line) ;
  180. }
  181.  
  182.  
  183. formfliplist(move, player)
  184. int move, player ;
  185. {        
  186.   int cnt, i, n, old_cnt ;
  187.  
  188.   old_cnt = count(&board, player) ;
  189.   FOR_BOARD(i) old_board.square[i] = board.square[i] ;
  190.   old_board.moves_left = board.moves_left ;
  191.   domove(&old_board, move, &board, player) ;
  192.  
  193.   n = 63 - board.moves_left ;
  194.   FOR_BOARD(i) moves[n].square[i] = board.square[i] ;
  195.   moves[n].moves_left = board.moves_left ;
  196.   moves[n].move = move ;
  197.   moves[n].note = note ;
  198.   moves[n].player = player ;
  199.  
  200.   cnt = count(&board, player) ;
  201.   return(cnt - old_cnt - 1) ;
  202. }
  203.  
  204.  
  205. void
  206. initboard()    /* Initialise the othello board. */
  207. {
  208.   static int ivals[4]   = { 27,    28,    35,    36 } ;
  209.   static int icolors[4] = { WHITE, BLACK, BLACK, WHITE } ;
  210.   int i, j , n ;
  211.  
  212.   for (i = 0; i < 64; i++) moves[i].move = -1 ;
  213.   for (n = 0; n < 4; n++)
  214.     {
  215.       FOR_BOARD(i) moves[n].square[i] = FREE ;
  216.       for (j = 0; j <= n; j++) moves[n].square[ivals[j]] = icolors[j] ;
  217.       moves[n].player     = icolors[n] ;
  218.       moves[n].move       = ivals[n] ;
  219.       moves[n].moves_left = 63 - n ;
  220.     }
  221.  
  222.   FOR_BOARD(i) old_board.square[i] = board.square[i] = FREE ;
  223.   board.square[27] = WHITE ;
  224.   board.square[28] = BLACK ;
  225.   board.square[35] = BLACK ;
  226.   board.square[36] = WHITE ;
  227.   board.moves_left = 60 ;
  228. }
  229.  
  230.  
  231. void
  232. load_game()
  233. {
  234.  
  235. /*  Read in a game from file, and setup internal variables accordingly.
  236.  *
  237.  *  Notation in the games file is of the format:
  238.  *  1, <C-4>   -     [ remarks field ]
  239.  *  2,   -   <E-3>   [ remarks field ]
  240.  *
  241.  *  The move number is the field before the comma. This is just used as a
  242.  *  consistency check. Next is the black move or the white move (surronded
  243.  *  by '<' and '>' characters. Obviously only one piece moves per go, and
  244.  *  the '-' character is used to signify which piece doesn't move (in case
  245.  *  one player had to miss a turn.
  246.  *
  247.  *  As each position is added, the board is redisplayed, and if the game is
  248.  *  not over, the next player can commence.
  249.  */
  250.  
  251.   char buf[MAXLINE], col, *lptr, *mptr, row ;
  252.   int moveno, n ;
  253.   FILE *fp ;
  254.  
  255.   if ((fp = fopen(gamefile, "r")) == NULL)
  256.     {
  257.       SPRINTF(buf, "Couldn't open game file: %s", gamefile) ;
  258.       message(PANEL_MES, buf) ;
  259.       return ;
  260.     }
  261.  
  262.   moveno = 0 ;
  263.   initboard() ;
  264.   last_move = -1 ;
  265.   init_canvas() ;
  266.   message(NOTES_MES, "") ;
  267.   while (fgets(buf, MAXLINE, fp) != NULL)
  268.     {
  269.       if (buf[0] == '\n' || buf[0] == '#') continue ;
  270.       moveno++ ;
  271.       SSCANF(buf, "%d", &n) ;
  272.       if (n != moveno || n > 60)
  273.         {
  274.           SPRINTF(buf, "Load error: incorrect move [%d] on line %d", n, move) ;
  275.           message(PANEL_MES, buf) ;
  276.           return ;
  277.         }
  278.       lptr = (char *) index(buf, '<') ;
  279.       mptr = (char *) index(buf, '-') ;
  280.       if (lptr == NULL || mptr == NULL)
  281.         {
  282.           SPRINTF(buf, "Load error: missing < or - on line %d", move) ;
  283.           message(PANEL_MES, buf) ;
  284.           return ;
  285.         }
  286.       if (lptr < mptr) next_player = BLACK ;    /* Black move? */
  287.       else             next_player = WHITE ;
  288.       SSCANF(lptr, "<%c-%c>", &row, &col) ;
  289.       if (load_move(moveno, row, col) == 0)
  290.         {
  291.           SPRINTF(buf, "Load error: invalid move <%c-%c> on line %d",
  292.                                     row, col, move) ;
  293.           message(PANEL_MES, buf) ;
  294.           return ;
  295.         }
  296.       SPRINTF(buf, "Loaded move %d for %s",
  297.                     moveno, (next_player == BLACK) ? "black" : "white") ;
  298.       message(PANEL_MES, buf) ;
  299.     }
  300.   FCLOSE(fp) ;
  301.  
  302.   set_score() ;
  303.   set_turn(OPPONENT(next_player)) ;
  304.  
  305.   cmode = (enum cantype) (OPPONENT(next_player) + 1) ;
  306.   next_player = OPPONENT(next_player) ;
  307.   if (check(next_player) == TRUE) return ;
  308.   (void) check(OPPONENT(next_player)) ;
  309. }
  310.  
  311.  
  312. load_move(n, col, row)
  313. int n, col, row ;
  314. {
  315.   int i, taken, x, y ;
  316.  
  317.   if (row < '1' || row > '8') return(0) ;
  318.   if (isupper(col)) col = tolower(col) ;
  319.   if (col < 'a' || col > 'h') return(0) ;
  320.   move = (row - '1') * BOARD_SIZE + (col - 'a') ;
  321.   if (legal(move, next_player, &board) == FALSE) return(0) ;
  322.   taken = formfliplist(move, next_player) ;
  323.   batch(IS_ON) ;
  324.   FOR_BOARD(i)
  325.     if (board.square[i] != old_board.square[i])
  326.       {
  327.         get_xy(i, &x, &y) ;
  328.         draw_piece(next_player, x, CY+y, RSRC) ;
  329.       } 
  330.   batch(IS_OFF) ;
  331.   return(1) ;
  332. }
  333.  
  334.  
  335. #ifndef SYSV
  336. void
  337. nap_upto(n)          /* Sleep upto n microseconds from start of timer. */
  338. int n ;
  339. {
  340.   struct timeval ctp ;
  341.   struct timezone ctzp ;
  342.   long elapsed ;     /* Number of microseconds since timer started. */
  343.  
  344.   GETTIMEOFDAY(&ctp, &ctzp) ;
  345.   elapsed = ((ctp.tv_usec - tp.tv_usec) +
  346.             (ctp.tv_sec - tp.tv_sec) * 1000000L) / 1000 ;
  347.   if (elapsed > n) return ;
  348.   usleep((unsigned) (n - elapsed)) ;
  349. }
  350. #endif /*SYSV*/
  351.  
  352.  
  353. void
  354. save_game()
  355. {
  356.  
  357. /*  Save the current game status to file.
  358.  *
  359.  *  The notation in the saved games file is of the format:
  360.  *  1, <C-4>   -    [ note : 12345 ]
  361.  *  2,   -   <E-3>  [ note : 0 ]
  362.  *
  363.  *  The move number is the field before the comma. This is just used as a
  364.  *  consistency check. Next is the black move or the white move (surronded
  365.  *  by '<' and '>' characters. Obviously only one piece moves per go, and
  366.  *  the '-' character is used to signify which piece doesn't move (in case
  367.  *  one player had to miss a turn.
  368.  */
  369.  
  370.   char buf[MAXLINE] ;
  371.   int n ;
  372.   FILE *fp ;
  373.  
  374.   if ((fp = fopen(gamefile, "w")) == NULL)
  375.     {
  376.       SPRINTF(buf, "Couldn't open game file: %s", gamefile) ;
  377.       message(PANEL_MES, buf) ;
  378.       return ;
  379.     }
  380.  
  381.   for (n = 4; n < 64; n++)
  382.     {
  383.       if (moves[n].move == -1) break ;
  384.       if (moves[n].player == BLACK)
  385.         FPRINTF(fp, "%d,  <%c-%c>   -  [ note : %ld ]\n",
  386.                 n-3, (moves[n].move % 8)  + 'a',
  387.                      (moves[n].move >> 3) + '1', moves[n].note) ;
  388.       else
  389.         FPRINTF(fp, "%d,  -   <%c-%c>  [ note : %ld ]\n",
  390.                 n-3, (moves[n].move % 8)  + 'a',
  391.                      (moves[n].move >> 3) + '1', moves[n].note) ;
  392.     }
  393.   FCLOSE(fp) ;
  394.   SPRINTF(buf, "Current game saved in %s", gamefile) ;
  395.   message(PANEL_MES, buf) ;
  396. }
  397.  
  398.  
  399. void
  400. set_score()
  401. {
  402.   SPRINTF(line, "Black: %2d, White: %2d",
  403.                  count(&board, BLACK), count(&board, WHITE)) ;
  404.   message(SCORE_MES, line) ;
  405. }
  406.  
  407.  
  408. void
  409. set_turn(player)
  410. int player ;
  411. {
  412.   SPRINTF(line, "%s to move", (player == BLACK) ? "Black" : "White") ;
  413.   message(TURN_MES, line) ;
  414. }
  415.  
  416.  
  417. #ifndef SYSV
  418. void
  419. set_timer()
  420. {
  421.   struct timezone tzp ;
  422.  
  423.   GETTIMEOFDAY(&tp, &tzp) ;
  424. }
  425. #endif /*SYSV*/
  426.  
  427.  
  428. void
  429. show_suggestion()
  430. {
  431.   enum optype rop ;
  432.  
  433.   if (suggestion != -1)
  434.     {
  435.       rop = RCLR ;
  436.       color = (iscolor[(int) cur_dpyno]) ? C_LBROWN : C_WHITE ;
  437.       if (iscolor[(int) cur_dpyno]) rop = RSRC ;
  438.       draw_line(suggest_x-5, CY+suggest_y-5,
  439.                 suggest_x+5, CY+suggest_y+5, rop, color) ;
  440.       draw_line(suggest_x-5, CY+suggest_y+5,
  441.                 suggest_x+5, CY+suggest_y-5, rop, color) ;
  442.       suggestion = -1 ;
  443.     }
  444. }
  445.  
  446.  
  447. void
  448. update_board_image(player)
  449. int player ;
  450. {
  451.   int flips, i, piece, x, y ;
  452.  
  453.   show_suggestion() ;
  454.   for (flips = 0; flips < 4; flips++)
  455.     {
  456.       batch(IS_ON) ;
  457.       FOR_BOARD(i)
  458.         {
  459.           if (board.square[i] != old_board.square[i])
  460.             {
  461.               get_xy(i, &x, &y) ;
  462.               if (i == move) piece = board.square[i] ;
  463.               else
  464.                 piece = (flips % 2) ? board.square[i] : board.square[i] * -1 ;
  465.               draw_piece(piece, x, CY+y, RSRC) ;
  466.             } 
  467.         }
  468.       batch(IS_OFF) ;
  469.       PAUSE ;
  470.     }
  471.   set_score() ;
  472.   set_turn(OPPONENT(player)) ;
  473.   message(TURN_MES, line) ;
  474.   if (show_notes)
  475.     if ((player == BLACK && items[(int) BLACK_PLAYS].value == COMPUTER) ||
  476.         (player == WHITE && items[(int) WHITE_PLAYS].value == COMPUTER))
  477.       {
  478.         SPRINTF(line, "%s: <%c-%c> note : %ld",
  479.                 (player == BLACK) ? "Black" : "White",
  480.                 (move & 7) + 'a', (move >> 3) + '1', note) ;
  481.         message(NOTES_MES, line) ;
  482.       }
  483. }
  484.  
  485.  
  486. void
  487. who_wins()
  488. {
  489.   int cs, ps ;
  490.  
  491.   ps = count(&board, WHITE) ;
  492.   cs = count(&board, BLACK) ;
  493.   if (ps > cs)
  494.     {
  495.       SPRINTF(line, "White wins %d-%d", ps, cs) ;
  496.       message(SCORE_MES, line) ;
  497.     }
  498.   else if (ps == cs)
  499.     {
  500.       SPRINTF(line,"A tie %d-%d", ps, cs) ;
  501.       message(SCORE_MES, line) ;
  502.     }
  503.   else
  504.     {
  505.       SPRINTF(line, "Black wins %d-%d", cs, ps) ;
  506.       message(SCORE_MES, line) ;
  507.     }
  508. }
  509.