home *** CD-ROM | disk | FTP | other *** search
- /*LINTLIBRARY*/
-
- /* @(#)boardstuff.c 1.27 91/11/13
- *
- * Various board routines used by reve.
- *
- * Copyright (C) 1990, 1991 - Rich Burridge & Yves Gallot.
- * All rights reserved.
- *
- * Permission is granted to copy this source, for redistribution
- * in source form only, provided the news headers in "substantially
- * unaltered format" are retained, the introductory messages are not
- * removed, and no monies are exchanged.
- *
- * Permission is also granted to copy this source, without the
- * news headers, for the purposes of making an executable copy by
- * means of compilation, provided that such copy will not be used
- * for the purposes of competition in any othello tournaments, without
- * prior permission from the authors.
- *
- * No responsibility is taken for any errors on inaccuracies inherent
- * either to the comments or the code of this program, but if reported
- * (see README file), then an attempt will be made to fix them.
- */
-
- #include "reve.h"
- #include "color.h"
- #include "extern.h"
- #include <ctype.h>
-
- #ifdef X11
- #include <X11/Xos.h>
- #endif /*X11*/
-
- void
- animate_move(move)
- int move ;
- {
- int x0, y0, x1, y1, x, y, dx, dy, ctr ;
-
- lock_screen(IS_ON) ;
- get_xy(move, &x1, &y1) ;
- dx = x1 ;
- dy = y1 ;
- if (x1 > y1)
- {
- ctr = dx / 2 ;
- x = bborder ;
- y = bborder ;
- draw_piece(WHITE, x, y, RINV) ;
- while (x < x1)
- {
- #ifndef SYSV
- set_timer() ;
- #endif /*!SYSV*/
- x0 = x ;
- y0 = y ;
- x += move_delta ;
- if ((ctr -= dy) < 0)
- {
- ctr += dx ;
- y += move_delta ;
- }
- draw_piece(WHITE, x, y, RINV) ;
- draw_piece(WHITE, x0, y0, RINV) ;
- #ifndef SYSV
- nap_upto(1) ;
- #endif /*!SYSV*/
- }
- draw_piece(WHITE, x, y, RINV) ;
- }
- else
- {
- ctr = dy / 2 ;
- x = bborder ;
- y = bborder ;
- draw_piece(WHITE, x, y, RINV) ;
- while (y < y1)
- {
- #ifndef SYSV
- set_timer() ;
- #endif /*!SYSV*/
- x0 = x ;
- y0 = y ;
- y += move_delta ;
- if ((ctr -= dx) < 0)
- {
- ctr += dy ;
- x += move_delta ;
- }
- draw_piece(WHITE, x, y, RINV) ;
- draw_piece(WHITE, x0, y0, RINV) ;
- #ifndef SYSV
- nap_upto(1) ;
- #endif /*!SYSV*/
- }
- draw_piece(WHITE, x, y, RINV) ;
- }
- lock_screen(IS_OFF) ;
- }
-
-
- /* This routine checks to see if a move can be made for this player.
- * If not, various checks are made to see if the game is finished.
- * Return value indicates if a move can be made.
- */
-
- int
- check(player)
- int player ;
- {
- if ((!count(&board, BLACK)) || (!count(&board, WHITE)) ||
- ((count(&board, BLACK) + count(&board, WHITE)) == 64))
- {
- who_wins() ;
- last_cmode = cmode ; /* Save previous value in case of undo. */
- cmode = GAME_OVER ;
- message(PANEL_MES, "***GAME OVER***") ;
- return(FALSE) ;
- }
- if ((move = valid_move(&board, player)) == FALSE)
- {
- SPRINTF(line, "%s is forced to pass",
- (player == BLACK) ? bstone_name : wstone_name) ;
- message(PANEL_MES, line) ;
- set_turn(OPPONENT(player)) ;
- if ((move = valid_move(&board, OPPONENT(player))) == FALSE)
- {
- who_wins() ;
- last_cmode = cmode ;
- cmode = GAME_OVER ;
- message(PANEL_MES, "***GAME OVER***") ;
- }
- return(FALSE) ;
- }
- return(TRUE) ;
- }
-
-
- int
- count(board, player) /* Count the number of player pieces on the board. */
- BOARD *board ;
- int player ;
- {
- int i, n ;
-
- n = 0 ;
- FOR_BOARD(i)
- if (board->square[i] == player) n++ ;
- return(n) ;
- }
-
-
- void
- do_move(player)
- int player ;
- {
- int taken ; /* Number of pieces flipped this go. */
-
- taken = formfliplist(move, player) ;
- update_board_image(player, taken) ;
- }
-
-
- void
- draw_outline(move, state)
- int move ;
- enum bltype state ;
- {
- if (last_outline == -1) return ;
- draw_square(move, state, 1) ;
- }
-
-
- void
- draw_piece(piece, x, y, op) /* Draw an othello piece on the board. */
- int piece, x, y ;
- enum optype op ;
- {
- switch (piece)
- {
- case BLACK : draw_stencil(W_BOARD, x, y,
- 2 * pieceXrad, 2 * pieceYrad, op,
- B_COLOR(C_BSTONE), P_BLACK, P_BLACK) ;
- if (iscolor && op != RINV)
- draw_image(W_BOARD, x, y,
- 2 * pieceXrad, 2 * pieceYrad, P_WHITE) ;
- break ;
- case WHITE : if (iscolor)
- {
- draw_stencil(W_BOARD, x, y,
- 2 * pieceXrad, 2 * pieceYrad, op,
- C_WSTONE, P_BLACK, P_BLACK) ;
- if (op != RINV)
- draw_image(W_BOARD, x, y,
- 2 * pieceXrad, 2 * pieceYrad, P_WHITE) ;
- }
- else
- draw_stencil(W_BOARD, x, y,
- 2 * pieceXrad, 2 * pieceYrad, op,
- C_WHITE, P_BLACK, P_WHITE) ;
- }
- }
-
-
- void
- draw_rect(wtype, x1, y1, x2, y2, op, color)
- enum win_type wtype ;
- int x1, y1, x2, y2, color ;
- enum optype op ;
- {
- draw_line(wtype, x1, y1, x2, y1, op, color) ;
- draw_line(wtype, x1, y1, x1, y2, op, color) ;
- draw_line(wtype, x2, y1, x2, y2, op, color) ;
- draw_line(wtype, x1, y2, x2, y2, op, color) ;
- }
-
-
- void
- draw_square(move, state, offset)
- int move, offset ;
- enum bltype state ;
- {
- int color, x, y ;
-
- if (state == IS_ON) color = C_BLACK ;
- else color = W_COLOR(C_SQUARE) ;
-
- x = (move & 7) * cell_width + bborder ;
- y = (move >> 3) * cell_height + bborder ;
- draw_rect(W_BOARD, x + offset, y + offset,
- x + cell_width - offset, y + cell_height - offset,
- RSRC, color) ;
- }
-
-
- void
- draw_symbol(image, n, state)
- enum image_type image ;
- int n ;
- enum bltype state ;
- {
- int color, x, y ;
-
- if (state == IS_OFF) color = W_COLOR(C_SQUARE) ;
- else color = C_BLACK ;
-
- x = bborder + ((n & 7) + 1) * cell_width - cell_width / 2 ;
- x -= (SWIDTH / 2) ;
- y = bborder + ((n >> 3) + 1) * cell_height - cell_height / 2 ;
- y -= (SHEIGHT / 2) ;
-
- if (state == IS_OFF)
- color_area(W_BOARD, x, y, SWIDTH, SHEIGHT, W_COLOR(C_SQUARE)) ;
- else
- draw_stencil(W_BOARD, x, y, SWIDTH, SHEIGHT, RSRC, color, image, image) ;
- if (state == IS_ON)
- draw_image(W_BOARD, x, y, SWIDTH, SHEIGHT, image) ;
- }
-
-
- int
- formfliplist(move, player)
- int move, player ;
- {
- int cnt, i, n, old_cnt ;
-
- old_cnt = count(&board, player) ;
- FOR_BOARD(i) old_board.square[i] = board.square[i] ;
- old_board.moves_left = board.moves_left ;
- domove(&old_board, move, &board, player) ;
-
- n = 63 - board.moves_left ;
- FOR_BOARD(i) moves[n].square[i] = board.square[i] ;
- moves[n].moves_left = board.moves_left ;
- moves[n].move = move ;
- moves[n].note = note ;
- moves[n].player = player ;
- moves[n].timeleft = timeleft ;
-
- cnt = count(&board, player) ;
- return(cnt - old_cnt - 1) ;
- }
-
-
- void
- initboard() /* Initialise the othello board. */
- {
- static int ivals[4] = { 27, 28, 35, 36 } ;
- static int icolors[4] = { WHITE, BLACK, BLACK, WHITE } ;
- int i, j , n ;
-
- suggestion = -1 ;
- sstate = IS_OFF ;
- show_moves = FALSE ;
- for (i = 0; i < 64; i++) moves[i].move = -1 ;
- for (n = 0; n < 4; n++)
- {
- FOR_BOARD(i) moves[n].square[i] = FREE ;
- for (j = 0; j <= n; j++) moves[n].square[ivals[j]] = icolors[j] ;
- moves[n].player = icolors[n] ;
- moves[n].move = ivals[n] ;
- moves[n].moves_left = 63 - n ;
- }
-
- FOR_BOARD(i) old_board.square[i] = board.square[i] = FREE ;
- board.square[27] = WHITE ;
- board.square[28] = BLACK ;
- board.square[35] = BLACK ;
- board.square[36] = WHITE ;
- board.moves_left = 60 ;
- }
-
-
- void
- load_game()
- {
-
- /* Read in a game from file, and setup internal variables accordingly.
- *
- * Notation in the games file is of the format:
- * 1, <C-4> - [ remarks field ]
- * 2, - <E-3> [ remarks field ]
- *
- * The move number is the field before the comma. This is just used as a
- * consistency check. Next is the black move or the white move (surronded
- * by '<' and '>' characters. Obviously only one piece moves per go, and
- * the '-' character is used to signify which piece doesn't move (in case
- * one player had to miss a turn.
- *
- * As each position is added, the board is redisplayed, and if the game is
- * not over, the next player can commence.
- */
-
- char buf[MAXLINE], col, *lptr, *mptr, row ;
- int moveno, n ;
- FILE *fp ;
-
- if ((fp = fopen(gamefile, "r")) == NULL)
- {
- SPRINTF(buf, "Couldn't open game file: %s", gamefile) ;
- message(PANEL_MES, buf) ;
- return ;
- }
-
- moveno = 0 ;
- initboard() ;
- last_move = -1 ;
- paint_board() ;
- message(EVAL_MES, "") ;
- while (fgets(buf, MAXLINE, fp) != NULL)
- {
- if (buf[0] == '\n' || buf[0] == '#') continue ;
- moveno++ ;
- SSCANF(buf, "%d", &n) ;
- if (n != moveno || n > 60)
- {
- SPRINTF(buf, "Load error: incorrect move [%d] on line %d", n, move) ;
- message(PANEL_MES, buf) ;
- return ;
- }
- lptr = (char *) index(buf, '<') ;
- mptr = (char *) index(buf, '-') ;
- if (lptr == NULL || mptr == NULL)
- {
- SPRINTF(buf, "Load error: missing < or - on line %d", move) ;
- message(PANEL_MES, buf) ;
- return ;
- }
- if (lptr < mptr) next_player = BLACK ; /* Black move? */
- else next_player = WHITE ;
- SSCANF(lptr, "<%c-%c>", &row, &col) ;
- if (load_move(row, col) == 0)
- {
- SPRINTF(buf, "Load error: invalid move <%c-%c> on line %d",
- row, col, move) ;
- message(PANEL_MES, buf) ;
- return ;
- }
- SPRINTF(buf, "Loaded move %d for %s", moveno,
- (next_player == BLACK) ? bstone_name : wstone_name) ;
- message(PANEL_MES, buf) ;
- }
- FCLOSE(fp) ;
-
- set_score() ;
- set_turn(OPPONENT(next_player)) ;
-
- cmode = (enum cantype) (OPPONENT(next_player) + 1) ;
- next_player = OPPONENT(next_player) ;
-
- if (check(next_player) == TRUE) return ;
- cmode = (enum cantype) (OPPONENT(next_player) + 1) ;
- next_player = OPPONENT(next_player) ;
- if (check(next_player) == FALSE) return ;
-
- if ((next_player == BLACK && cmode == BLACK_START) ||
- (next_player == WHITE && cmode == WHITE_START))
- {
- opponent_move(next_player) ;
- next_player = OPPONENT(next_player) ;
- }
- }
-
-
- int
- load_move(col, row)
- int col, row ;
- {
- int i, x, y ;
-
- if (row < '1' || row > '8') return(0) ;
- if (isupper(col)) col = tolower(col) ;
- if (col < 'a' || col > 'h') return(0) ;
- move = (row - '1') * BOARD_SIZE + (col - 'a') ;
- if (legal(move, next_player, &board) == 0) return(0) ;
- (void) formfliplist(move, next_player) ;
- batch(IS_ON) ;
- if (DO_LAST) show_last(last_move, IS_OFF) ;
- if (DO_NUMBER) show_number(last_move, 59 - board.moves_left, IS_OFF) ;
- FOR_BOARD(i)
- if (board.square[i] != old_board.square[i])
- {
- get_xy(i, &x, &y) ;
- draw_piece(next_player, x, y, RSRC) ;
- }
- if (DO_LAST) show_last(move, IS_ON) ;
- if (DO_NUMBER) show_number(move, 60 - board.moves_left, IS_ON) ;
- last_move = move ;
- batch(IS_OFF) ;
- return(1) ;
- }
-
-
- #ifndef SYSV
- void
- nap_upto(n) /* Sleep upto n microseconds from start of timer. */
- int n ;
- {
- struct timeval ctp ;
- struct timezone ctzp ;
- long elapsed ; /* Number of microseconds since timer started. */
-
- GETTIMEOFDAY(&ctp, &ctzp) ;
- elapsed = ((ctp.tv_usec - tp.tv_usec) +
- (ctp.tv_sec - tp.tv_sec) * 1000000L) / 1000 ;
- if (elapsed > n) return ;
- usleep((unsigned) (n - elapsed)) ;
- }
- #endif /*!SYSV*/
-
-
- void
- opponent_move(player)
- int player ;
- {
- for (;;)
- {
- if (processing == FALSE)
- {
- if (check(player) == TRUE)
- {
- set_cursor(HOURGLASS) ;
- best_cmove = -1 ;
- message(EVAL_MES, "") ;
- move = moves[63 - board.moves_left].move ;
- reset_clock(player) ;
- #ifdef REMOTE_PLAYER
- if (isremote) write_to_sock(socketfd, move) ;
- else
- #endif /* REMOTE_PLAYER */
- write_to_reve(M_MOVE, board.square, player, level) ;
- if (opp_iconise == TRUE) close_reve() ;
- return ;
- }
- else
- {
- if (cmode != GAME_OVER)
- cmode = (enum cantype) ((int) cmode - 1) ;
- next_player = OPPONENT(next_player) ;
- return ;
- }
- }
- else
- {
- processing = FALSE ;
- update_clock(next_player, TRUE) ;
- do_opponent_move(player) ;
- reset_clock(OPPONENT(player)) ;
- if (check(OPPONENT(player)) == TRUE || cmode == GAME_OVER)
- {
- next_player = OPPONENT(next_player) ;
- if (opp_iconise == TRUE) open_reve() ;
- if (opp_bell == TRUE) beep() ;
- if (opp_raise == TRUE) raise_reve() ;
- return ;
- }
- }
- }
- }
-
-
- void
- print_game()
- {
- char buf[MAXLINE] ;
- FILE *fp ;
-
- if ((fp = popen(printcommand, "w")) == NULL)
- {
- SPRINTF(buf, "Couldn't open printer: %s", printcommand) ;
- message(PANEL_MES, buf) ;
- return ;
- }
- save_game_to(fp) ;
- PCLOSE(fp) ;
- SPRINTF(buf, "Current game printed on %s", printcommand) ;
- message(PANEL_MES, buf) ;
- }
-
-
- void
- save_game_to(fp)
- FILE *fp ;
- {
- int n ;
-
- for (n = 4; n < 64; n++)
- {
- if (moves[n].move == -1) break ;
- if (moves[n].player == BLACK)
- FPRINTF(fp, "%d, <%c-%c> - [ note : %ld ]\n",
- n-3, (moves[n].move % 8) + 'a',
- (moves[n].move >> 3) + '1', moves[n].note) ;
- else
- FPRINTF(fp, "%d, - <%c-%c> [ note : %ld ]\n",
- n-3, (moves[n].move % 8) + 'a',
- (moves[n].move >> 3) + '1', moves[n].note) ;
- }
- }
-
-
- void
- save_game()
- {
-
- /* Save the current game status to file.
- *
- * The notation in the saved games file is of the format:
- * 1, <C-4> - [ note : 12345 ]
- * 2, - <E-3> [ note : 0 ]
- *
- * The move number is the field before the comma. This is just used as a
- * consistency check. Next is the black move or the white move (surronded
- * by '<' and '>' characters. Obviously only one piece moves per go, and
- * the '-' character is used to signify which piece doesn't move (in case
- * one player had to miss a turn.
- */
-
- char buf[MAXLINE] ;
- FILE *fp ;
-
- if ((fp = fopen(gamefile, "w")) == NULL)
- {
- SPRINTF(buf, "Couldn't open game file: %s", gamefile) ;
- message(PANEL_MES, buf) ;
- return ;
- }
- save_game_to(fp) ;
- FCLOSE(fp) ;
- SPRINTF(buf, "Current game saved in %s", gamefile) ;
- message(PANEL_MES, buf) ;
- }
-
-
- void
- set_eval(player, move, note)
- int player, move ;
- long note ;
- {
- SPRINTF(line, "%s: <%c-%c> eval : %ld depth: %d",
- (player == BLACK) ? bstone_name : wstone_name,
- (move & 7) + 'a', (move >> 3) + '1', note, profmax) ;
- message(EVAL_MES, line) ;
- }
-
-
- void
- set_score()
- {
- SPRINTF(line, "Stones: %s: %2d %s: %2d",
- bstone_name, count(&board, BLACK),
- wstone_name, count(&board, WHITE)) ;
- message(SCORE_MES, line) ;
- }
-
-
- void
- set_turn(player)
- int player ;
- {
- SPRINTF(line, "%s to move", (player == BLACK) ? bstone_name : wstone_name) ;
- message(TURN_MES, line) ;
- }
-
-
- #ifndef SYSV
- void
- set_timer()
- {
- struct timezone tzp ;
-
- GETTIMEOFDAY(&tp, &tzp) ;
- }
- #endif /*!SYSV*/
-
-
- void
- show_all(state)
- enum bltype state ;
- {
- int count, i, player ;
-
- batch(IS_ON) ;
- if (state == IS_ON)
- {
- FOR_BOARD(i) s_all.square[i] = FREE ;
- FOR_BOARD(i)
- if (board.square[i] == FREE &&
- (count = legal(i, next_player, &board)) != 0)
- {
- s_all.square[i] = next_player ;
- draw_symbol(S_MOVE, i, IS_ON) ;
- show_number(i, count, IS_ON) ;
- }
- }
- else
- {
- FOR_BOARD(i)
- if (s_all.square[i] != FREE)
- {
- s_all.square[i] = FREE ;
- draw_symbol(S_MOVE, i, IS_OFF) ;
- }
- if (suggestion != -1 && sstate == IS_ON)
- {
- player = (cmode == WHITE_START) ? WHITE : BLACK ;
- do_suggest(player, suggestion, snote, IS_ON) ;
- }
- }
- batch(IS_OFF) ;
- show_moves = (int) state ;
- }
-
-
- void
- show_best(move, note)
- int move ;
- long note ;
- {
- batch(IS_ON) ;
- if (move == -1 || DO_BESTMOVE == FALSE) return ;
- if (best_cmove != -1)
- {
- draw_square(best_cmove, IS_OFF, 2) ;
- if (DO_NUMBER) show_number(best_cmove, cmove_depth, IS_OFF) ;
- }
- best_cmove = move ;
- cmove_depth = profmax ;
- draw_square(best_cmove, IS_ON, 2) ;
- if (DO_NUMBER) show_number(best_cmove, cmove_depth, IS_ON) ;
- if (SHOW_NOTES) set_eval(next_player, move, note) ;
- batch(IS_OFF) ;
- }
-
-
- void
- show_last(move, state)
- int move ;
- enum bltype state ;
- {
- if (move == -1) return ;
- if (board.moves_left < 60) draw_square(move, state, 2) ;
- }
-
-
- void
- show_number(move, val, state)
- int move, val ;
- enum bltype state ;
- {
- char num[3] ;
- int color, strw, x, y ;
-
- if (move == -1) return ;
-
- if (board.square[move] == BLACK)
- color = (state == IS_ON) ? C_WHITE : B_COLOR(C_BSTONE) ;
- else if (board.square[move] == WHITE)
- color = (state == IS_ON) ? C_BLACK : W_COLOR(C_WSTONE) ;
- else if (iscolor)
- color = (state == IS_ON) ? C_BLACK : C_SQUARE ;
- else
- color = (state == IS_ON) ? C_BLACK : C_WHITE ;
-
- x = (move & 7) * cell_width + bborder + pieceXmargin ;
- y = (move >> 3) * cell_height + bborder + pieceYmargin ;
-
- SPRINTF(num, "%2d", val) ;
- strw = get_strwidth(GFONT, num) ;
-
- x = x + ((2 * pieceXrad) - strw) / 2 ;
- if (val < 10) x -= 3 ;
- y = y + font_heights[(int) GFONT] - 1 +
- ((2 * pieceYrad) - font_heights[(int) GFONT]) / 2 ;
- draw_text(W_BOARD, x, y, GFONT, color, num) ;
- }
-
-
- void
- update_board_image(player, taken)
- int player, taken ;
- {
- update_pieces(player, taken) ;
- last_move = move ;
- if (SHOW_NOTES)
- if ((player == BLACK && items[(int) BLACK_PLAYS].value == COMPUTER) ||
- (player == WHITE && items[(int) WHITE_PLAYS].value == COMPUTER))
- set_eval(player, move, note) ;
- }
-
-
- void
- update_pieces(player, taken)
- int player, taken ;
- {
- int flips, i, piece, total_flips, x, y ;
-
- total_flips = (QUICKGAME) ? 2 : 4 ;
- if (DO_LAST) show_last(last_move, IS_OFF) ;
- if (DO_NUMBER) show_number(last_move, 59 - board.moves_left, IS_OFF) ;
-
- if (show_moves || (invalid == TRUE && SHOW_LEGAL)) show_all(IS_OFF) ;
- if (suggestion != -1) draw_symbol(S_SUGGEST, suggestion, IS_OFF) ;
- suggestion = -1 ;
- sstate = IS_OFF ;
- for (flips = 0; flips < total_flips; flips++)
- {
- batch(IS_ON) ;
- FOR_BOARD(i)
- {
- if (board.square[i] != old_board.square[i])
- {
- get_xy(i, &x, &y) ;
- if (i == move) piece = board.square[i] ;
- else
- piece = (flips % 2) ? board.square[i] : board.square[i] * -1 ;
- draw_piece(piece, x, y, RSRC) ;
- }
- }
- batch(IS_OFF) ;
- PAUSE ;
- }
- if (DO_LAST) show_last(move, IS_ON) ;
- if (DO_NUMBER) show_number(move, 60 - board.moves_left, IS_ON) ;
- set_score() ;
- set_turn(OPPONENT(player)) ;
- if (DO_LAST == FALSE && DO_NUMBER == FALSE)
- SPRINTF(line, "%s moved at <%c-%c> and took %d %s",
- (player == BLACK) ? bstone_name : wstone_name,
- (move % 8) + 'a', (move >> 3) + '1',
- taken, (taken == 1) ? "stone" : "stones") ;
- else
- SPRINTF(line, "%s took %d %s",
- (player == BLACK) ? bstone_name : wstone_name,
- taken, (taken == 1) ? "stone" : "stones") ;
- message(PANEL_MES, line) ;
- }
-
-
- void
- who_wins()
- {
- int cs, ps ;
-
- ps = count(&board, WHITE) ;
- cs = count(&board, BLACK) ;
- if (ps > cs)
- {
- SPRINTF(line, "%s wins %d-%d", wstone_name, ps, cs) ;
- message(SCORE_MES, line) ;
- }
- else if (ps == cs)
- {
- SPRINTF(line,"A tie %d-%d", ps, cs) ;
- message(SCORE_MES, line) ;
- }
- else
- {
- SPRINTF(line, "%s wins %d-%d", bstone_name, cs, ps) ;
- message(SCORE_MES, line) ;
- }
- message(TURN_MES, "") ;
- message(EVAL_MES, "") ;
- }
-