/* * TicTacToe.java * * Created: February 26, 2005 * By: Stan Sclaroff, Boston University Dept. of Computer Science * Description: Interactive tic-tac-toe game class for program assignment 5. * * Human is "X" and computer player is "O". Human goes first. * * The human clicks the to place an "X" on the board * The computer then picks its next move and it is marked with an "O" * * If at any point in the game there is a winner or draw, a message is * printed on the console and the game is over. * * To restart the game, the human can click * */ package program5; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.Timer; /** * * @author Stan */ public class TicTacToe extends JFrame implements MouseListener{ // Constants for marking the Tic Tac Toe board public static final int HUMAN_PLAYER = 1; public static final int COMPUTER_PLAYER = 2; public static final int EMPTY = 0; // tic-tac-toe game state variables private boolean humanTurn = true; private boolean gameOver = false; // Tic-Tac-Toe board private int[][] board = new int[3][3]; // instance variables related to graphical display of the board private int cellSize; private int x0, y0; // Create a new instance of TicTacToe board public TicTacToe() { // initialize the board to be empty initializeBoard(); // set up the window setBackground( Color.black ); setSize(new Dimension(190,210)); setDefaultCloseOperation(this.EXIT_ON_CLOSE); setVisible(true); setResizable(false); cellSize = getContentPane().getHeight()/3; x0 = getWidth() - getContentPane().getWidth(); y0 = getHeight() - getContentPane().getHeight(); // paint the contents of the window repaint(); // register the mouse event listener addMouseListener( this ); } // MOUSE LISTENERS (mouse event handlers) public void mouseEntered( MouseEvent e ) { // called when the pointer enters the frame's rectangular area } public void mouseExited( MouseEvent e ) { // called when the pointer leaves the frame's rectangular area } public void mouseClicked( MouseEvent e ) { // called after a press and release of a mouse button // with no motion in between // (If the user presses, drags, and then releases, there will be // no click event generated.) processMouse(e); } public void mousePressed( MouseEvent e ) { // called after a button is pressed down } public void mouseReleased( MouseEvent e ) { // called after a button is released } // Helper method that processes a mouse click // clears the board, and restarts the game // // convey's the human's next move // After human's move, check to see if there's a winner or draw // If not, then the computer gets to move // And then check to see if there's a winner or draw // continue until game is over. // // is unused in this application private void processMouse(MouseEvent e){ int mx = e.getX(), my = e.getY(); switch(e.getButton()){ case MouseEvent.BUTTON1: if(gameOver) break; if(humanTurn){ // Let human take a turn int[] m = humanMove(mx,my); if(board[m[0]][m[1]]==EMPTY){ // make sure it's a valid move board[m[0]][m[1]] = HUMAN_PLAYER; humanTurn = false; repaint(); if(isDraw()){ System.out.println("Game ends in a draw."); gameOver = true; } else if(gameWinner() == HUMAN_PLAYER){ System.out.println("Human wins!"); gameOver = true; } } else // if not valid move, then the human must try again System.out.println("Invalid move. Please try again."); } if(!humanTurn && !gameOver){ // Let the computer take a turn int[] m = MyPlayer.selectMove(copyBoard(), COMPUTER_PLAYER); if(m[0]!=-1 && board[m[0]][m[1]]==EMPTY) // make sure it's valid move board[m[0]][m[1]]=COMPUTER_PLAYER; else System.out.println("Computer chose invalid move. Lose turn."); humanTurn = true; repaint(); if(isDraw()){ System.out.println("Game ends in a draw."); gameOver = true; } else if(gameWinner() == COMPUTER_PLAYER){ System.out.println("Computer wins!"); gameOver = true; } } if(gameOver) System.out.println("Press third mouse button to play again."); break; case MouseEvent.BUTTON3: // prepare to start another game. initializeBoard(); gameOver = false; humanTurn = true; repaint(); break; case MouseEvent.BUTTON2: default: // do nothing break; } } // Helper method to convert mouse click into // corresponding position on the tic-tac-toe board. private int[] humanMove(int mx, int my){ int[] move = new int[2]; move[0] = (my-y0) / cellSize; move[1] = (mx-x0) / cellSize; if(move[0] > 2) move[0] = 2; else if (move[0] < 0) move[0] = 0; if(move[1] > 2) move[1] = 2; else if(move[1] < 0) move[1]=0; return move; } // Draw the board, including grid lines and X's and O's // HUMAN_PLAYER is "X" and COMPUTER_PLAYER is "O" public void paint( Graphics g ) { // get the window width and height int h = this.getHeight(), w = this.getWidth(); int xPos,yPos; // clear the window g.setColor( Color.black ); g.fillRect(0,0,w,h); // draw the vertical grid lines g.setColor( Color.gray ); g.drawLine(x0+cellSize,y0,x0+cellSize,y0+cellSize*3); g.drawLine(x0+cellSize*2,y0,x0+cellSize*2,y0+cellSize*3); // draw the horizontal grid lines g.drawLine(x0,y0+cellSize,x0+cellSize*3,y0+cellSize); g.drawLine(x0,y0+cellSize*2,x0+cellSize*3,y0+cellSize*2); // Set the font and color for the marks on board g.setFont(new Font("TimeRoman",Font.BOLD,(int)(cellSize*1.25))); g.setColor(Color.green); // draw any marks on board for(int i=0;i<3;++i){ yPos = y0 + i*cellSize; for(int j=0;j<3;++j){ xPos = x0 + j*cellSize; if(board[i][j]==HUMAN_PLAYER) g.drawString("X", xPos+5, yPos+cellSize-3); else if(board[i][j]==COMPUTER_PLAYER) g.drawString("O", xPos+5, yPos+cellSize-3); } } } // Helper method to determine if one of the players has three in a row // If yes, then that player is the winner and return the player ID // otherise, there is no winner and return -1 private int gameWinner(){ // check rows and columns for(int i=0;i<3;++i) if(board[i][0]!=EMPTY && board[i][0]==board[i][1]&&board[i][0]==board[i][2]) return board[i][0]; else if(board[0][i]!=EMPTY && board[0][i]==board[1][i]&&board[0][i]==board[2][i]) return board[0][i]; // check diagonals if(board[0][0]!=EMPTY && board[0][0]==board[1][1] && board[0][0]==board[2][2]) return board[0][0]; if(board[0][2]!=EMPTY && board[0][2]==board[1][1] && board[0][2]==board[2][0]) return board[0][2]; // No winner return -1; } // Helper method determine if the game has ended in a draw private boolean isDraw(){ // If there is a winner, then not a draw if(gameWinner() != -1) return false; // If there are no empty spots left, and no winner for(int i=0;i<3;++i) for(int j=0;j<3;++j) if(board[i][j]==EMPTY) return false; // All spots are full. It is a draw. return true; } // Helper method to create a copy of the tic-tac-toe board private int[][] copyBoard(){ int[][] c = new int[3][3]; for(int i=0;i<3;++i) for(int j=0;j<3;++j) c[i][j] = board[i][j]; return c; } // Helper method to initialize the tic-tac-toe board to EMPTY private void initializeBoard(){ for(int i=0; i<3; ++i) for(int j=0; j<3; ++j) board[i][j]=EMPTY; } }