/* * version history * 1. Created by Muffy Barkocy, March 30th, 1995. * 2. Improved painting, April 3, 1995 thanks to Arthur van Hoff * Also improved strategy. * 3. Much improved version by Ben Fry, July, 1995. * 4. Beta java version, with a few changes incorporated from Ben * Fry's version, December, 1995. * * 5. Adding a little strategy on rank_moves by Eiji Hamano, April '96. * 6. Add Computer buttan. Evry user actions pause the program, Then press * the computer buttan, the computer start it, by Eiji Hamano, * April '96. * 7. Improved painting, color, chosen_color and fliped_color on * both WRITE/BLACK by Eiji Hamano, April '96. */ import java.awt.*; import java.applet.*; /* * This program plays the game reversi, using a very simplistic * strategy. The "best" move is the one will flip the most pieces. A * better strategy can be plugged in by changing the rank_move function. * April 3: strategy improved slightly. */ public class Reversi extends Applet { /* The players. */ int user; int computer; int which_turn; /* add by Eiji Hamano */ /* The board is one square too large in each direction, for ease of searching. */ int board[][] = new int[10][10]; int score[][] = new int[10][10]; int display[][] = new int[10][10]; /* add by Eiji Hamano */ /* It is similar to board[][], but */ /* different on chosen-mode, fliped- */ /* mode. */ // graphics for the pieces you see Image black_piece, white_piece, chosen_black_piece, /* add by Eiji Hamano */ fliped_black_piece, /* add by Eiji Hamano */ chosen_white_piece, /* add by Eiji Hamano */ fliped_white_piece, /* add by Eiji Hamano */ empty_piece, okmove_piece; String message; // the button you hit when you're getting beat Image game_restart; boolean game_over; /* Constants. */ static final int BLACK = 2; static final int WHITE = 1; static final int CHOSEN_BLACK = 4; /* add by Eiji Hamano */ static final int FLIPED_BLACK = 3; /* add by Eiji Hamano */ static final int CHOSEN_WHITE = 6; /* add by Eiji Hamano */ static final int FLIPED_WHITE = 5; /* add by Eiji Hamano */ static final int EMPTY = 0; static final int SQUARE_SIZE = 37; /* * The 8x8 board is initialized with four pieces, two black and two * white, in diagonal corners of the center square. * Set constants, set board size, load images. */ public void init () { /* Leave a line on the bottom for messages. */ resize(11*SQUARE_SIZE, 11*SQUARE_SIZE); /* Set up the starting position. */ board[4][4] = BLACK; board[4][5] = WHITE; board[5][4] = WHITE; board[5][5] = BLACK; display[4][4] = CHOSEN_BLACK; display[4][5] = CHOSEN_WHITE; /* add Eiji Hamano */ display[5][4] = FLIPED_WHITE; display[5][5] = FLIPED_BLACK; /* add Eiji Hamano */ // if the user var is set to BLACK already, then the // restart button was hit, so don't bother reloading everything if ( user != BLACK ) { /* Suck in the images. */ black_piece = getImage(getCodeBase(), "http://www.yk.rim.or.jp/~hyper01/java/images/black.gif"); white_piece = getImage(getCodeBase(), "http://www.yk.rim.or.jp/~hyper01/java/images/white.gif"); empty_piece = getImage(getCodeBase(), "http://www.yk.rim.or.jp/~hyper01/java/images/empty.gif"); okmove_piece = getImage(getCodeBase(), "http://www.yk.rim.or.jp/~hyper01/java/images/okmove.gif"); game_restart = getImage(getCodeBase(), "http://www.yk.rim.or.jp/~hyper01/java/images/restart.gif"); /* Following 4 statments are added by Eiji Hamano */ chosen_black_piece = getImage(getCodeBase(), "http://www.yk.rim.or.jp/~hyper01/java/images/c_black.gif"); fliped_black_piece = getImage(getCodeBase(), "http://www.yk.rim.or.jp/~hyper01/java/images/f_black.gif"); chosen_white_piece = getImage(getCodeBase(), "http://www.yk.rim.or.jp/~hyper01/java/images/c_white.gif"); fliped_white_piece = getImage(getCodeBase(), "http://www.yk.rim.or.jp/~hyper01/java/images/f_white.gif"); } user = BLACK; computer = WHITE; message = "Your turn."; game_over = false; which_turn = user; /* First turn is user. add by Eiji Hamano */ } // user hit the reset button public void reinit () { for ( int row = 1; row < 9; row++ ) for ( int col = 1; col < 9; col++ ) { /* add { Eiji Hamano */ board[col][row] = EMPTY; display[col][row] = EMPTY; /* add by Eiji Hamano */ } /* add by Eiji Hamano */ init(); repaint(); } /* * Draw the board and the pieces. */ public void paint (Graphics g) { update(g); } public void update(Graphics g) { g.setColor(Color.black); g.fillRect(0, 0, 440, 440); /* Fill in the pieces. */ for (int row = 1; row < 9; row++) { int sy = row * SQUARE_SIZE; for (int col = 1; col < 9; col++) { int sx = col * SQUARE_SIZE; /* switch (board[col][row]) { ** deleted this line by Eiji Hamano */ switch (display[col][row]) { /* add this line by Eiji Hamano */ case WHITE: g.drawImage(white_piece, sx + 1, sy + 1, this); break; case BLACK: g.drawImage(black_piece, sx + 1, sy + 1, this); break; /* ---------------------------------------------------- * add following 4 cased by Eiji Hamano. */ case CHOSEN_WHITE: g.drawImage(chosen_white_piece, sx + 1, sy + 1, this); break; case FLIPED_WHITE: g.drawImage(fliped_white_piece, sx + 1, sy + 1, this); break; case CHOSEN_BLACK: g.drawImage(chosen_black_piece, sx + 1, sy + 1, this); break; case FLIPED_BLACK: g.drawImage(fliped_black_piece, sx + 1, sy + 1, this); break; /* ----------------------end--------------------------- */ default: g.drawImage(empty_piece, sx + 1, sy + 1, this); break; } } } /* Write the message. */ g.setColor(Color.black); g.fillRect(0, 9 * SQUARE_SIZE + 1, size().width, 2*SQUARE_SIZE); g.setColor(Color.white); /* chenged 5*SQUARE_SIZE to 4* by Eiji Hamano */ g.drawString(message, 4*SQUARE_SIZE, 10*SQUARE_SIZE-5); g.drawImage( game_restart, 1*SQUARE_SIZE, 9*SQUARE_SIZE+8, this ); /* add following 3 lines "computer buttan" by Eiji Hamano */ g.drawImage( okmove_piece, 8*SQUARE_SIZE, 9*SQUARE_SIZE+8, this ); g.drawImage( white_piece, 1*SQUARE_SIZE, 10*SQUARE_SIZE, this ); g.drawImage( black_piece, 2*SQUARE_SIZE, 10*SQUARE_SIZE, this ); } /* * In response to a mouse click, the program checks the validity of the * move. If it is valid, it then tries to make a move of its own, if it * can. If the user cannot move, the program will move again. * * The mouseUp statments were changed many for separating itself and * "computer_DOit" class, by Eiji Hamano. */ public boolean mouseUp (Event evt, int x, int y) { int col = x / SQUARE_SIZE; int row = y / SQUARE_SIZE; /* When restart buttan */ if ( col == 1 && row == 9 ) { reinit(); return true; } /* ------------------------------------------------------- * Add following clear lojic statments by Eiji Hamano. * For clear chosen/fliped to original */ for (int rowx = 1; rowx < 9; rowx++) { int sy = rowx * SQUARE_SIZE; for (int colx = 1; colx < 9; colx++) { int sx = colx * SQUARE_SIZE; switch (display[colx][rowx]) { case CHOSEN_WHITE: display[colx][rowx] = WHITE; break; case FLIPED_WHITE: display[colx][rowx] = WHITE; break; case CHOSEN_BLACK: display[colx][rowx] = BLACK; break; case FLIPED_BLACK: display[colx][rowx] = BLACK; break; } } } /* ----------------------end--------------------------- */ /* When computer buttan */ if ( col == 8 && row == 9 ) { if (which_turn == user) { /* if user turn */ message = "No, your turn."; repaint(); return true; } else { computer_DOit(); /* Do computer logic */ which_turn = user; /* next turn is "user" */ return true; } } /* Do the user move. */ if (legal_move(user, col, row)) { if (which_turn == computer) { /* if computer turn */ message = "No, please press this. ---->"; repaint(); } else { make_move(user, col, row); which_turn = computer; /* next turn is "computer" */ message = "Press computer Buttan ---->"; repaint(); } } else { /* it was not a legal move */ message = "Illegal move; try again."; repaint(); } return true; } /* * Separate the logic "mouseUP" to itself and "computer_DOit" * by Eiji Hamano */ public void computer_DOit () { boolean computer_move = true; computer_move = best_move(computer); /* See if there are more moves; if not, end the game. */ while (!has_move(user) && !game_over) { if (!computer_move) { game_over = true; end_game(); } else { computer_move = best_move(computer); } } if (!game_over) { message = "Your turn."; repaint(); } return; } /* * Put a piece in a square. * Flip all the pieces, redrawing them. */ void make_move (int color, int col, int row) { board[col][row] = color; /* ---------------------------------------------------- * add to following 6 statments by Eiji Hamano */ if (color == WHITE) { display[col][row] = CHOSEN_WHITE; } else { display[col][row] = CHOSEN_BLACK; } /* -------------------end--------------------------------- */ for (int colinc = -1; colinc < 2; colinc++) { for (int rowinc = -1; rowinc < 2; rowinc++) { flip_row(color, col, row, colinc, rowinc, true); } } } /* * See if a move will flip pieces in a particular direction, based on * the board and the color of the piece being placed. * If redraw is true, then draw the flipping pieces. * Return the number of pieces flipped. */ int flip_row (int color, int col, int row, int colinc, int rowinc, boolean redraw) { int newcol = col + colinc; int newrow = row + rowinc; int opponent = BLACK + WHITE - color; int count = 0; /* if we're not moving, or this isn't a good direction, we won't flip any */ if (((colinc == 0) && (rowinc == 0)) || (board[newcol][newrow] != opponent)) { return 0; } /* count how many will be flipped */ while (board[newcol][newrow] == opponent) { newcol += colinc; newrow += rowinc; count += 3; /* changed "count++;" to "count += 3;" by Eiji Hamano */ } /* if there isn't a matching piece, none will be flipped. */ if (board[newcol][newrow] != color) { return 0; } if (redraw) { while ((col != newcol) || (row != newrow)) { board[col][row] = color; col += colinc; row += rowinc; /* ------------------------------------------------ * add to following 6 statments by Eiji Hamano */ if (color != display[col][row]) { if (color == WHITE) { display[col][row] = FLIPED_WHITE; } else { display[col][row] = FLIPED_BLACK; } } /* -------------------end-------------------------- */ } repaint(); } return count; } /* * Rank a move by counting pieces flipped. * Make the corner more desirable, the squares around it less so. */ int rank_move (int color, int col, int row) { int count = 0; if (board[col][row] != EMPTY) { return 0; } for (int colinc = -1; colinc < 2; colinc++) { for (int rowinc = -1; rowinc < 2; rowinc++) { count += flip_row(color, col, row, colinc, rowinc, false); } } if (count > 0) { /* Make the corners most desirable */ if (((col == 1) || (col == 8)) && ((row == 1) || (row == 8))) { count = 64; } /* Make the squares next to the corner least desirable */ if ((((col == 1) || (col == 8)) && ((row == 2) || (row == 7))) || (((row == 1) || (row == 8)) && ((col == 2) || (col == 7))) || (((col == 2) || (col == 7)) && ((row == 2) || (row == 7)))) { count = 1; } } return count; } /* * Find and rank the possible moves. In this case, the rank is the * total number of pieces that would be flipped. */ void rank_moves (int color) { for (int col = 1; col < 9; col++) { for (int row = 1; row < 9; row++) { score[col][row] = rank_move(color, col, row); /* ---------------------------------------------------------------- * add logic following 8 statments by Eiji Hamano 96.04.22 */ if (score[col][row] != 0) { if ((col == 1)||(col == 8)||(row == 1)||(row == 8)) { score[col][row] += 10; } if ((col == 2)|| (col== 7)||(row == 2)||(row == 7)) { score[col][row] = 2; } } /* --------------------------------- end ------------------------- */ } } } /* * Find the move with the highest rank. */ boolean best_move (int color) { int maxcount = 0; int maxcol = 0; int maxrow = 0; rank_moves(color); for (int col = 1; col < 9; col++) { for (int row = 1; row < 9; row++) { if (maxcount < score[col][row]) { maxcol = col; maxrow = row; maxcount = score[col][row]; } } } if (maxcount > 0) { make_move(color, maxcol, maxrow); return true; } else { return false; } } /* * Determine if a move is legal. * Return true or false. */ boolean legal_move (int color, int col, int row) { if (board[col][row] != EMPTY) { return false; } for (int colinc = -1; colinc < 2; colinc++) { for (int rowinc = -1; rowinc < 2; rowinc++) { if (flip_row(color, col, row, colinc, rowinc, false) > 0) { return true; } } } return false; } boolean has_move (int color) { for (int col = 1; col < 9; col++) { for (int row = 1; row < 9; row++) { if (rank_move(color, col, row) > 0) { return true; } } } return false; } /* * Determine who won. */ void end_game () { int comp_count = 0; int user_count = 0; for (int col = 1; col < 9; col++) { for (int row = 1; row < 9; row++) { if (board[col][row] == computer) { comp_count++; } else if (board[col][row] == user) { user_count++; } } } /* Computer wins. */ if (comp_count > user_count) { message = "I win!"; } /* User wins. */ else if (user_count > comp_count) { message = "You win!"; } /* Nobody wins. */ else { message = "It's a tie!"; } repaint(); } } /* end class */