18. Binary I-O

 
[Page 550 ( continued )]

16.7. (Optional) Case Study: TicTacToe

You have learned about objects, classes, arrays, class inheritance, GUI, event-driven programming, and applets from the many examples in this chapter and the preceding chapters. Now it is time to put what you have learned to work in developing comprehensive projects. In this section, you will develop a Java applet with which to play the popular game of TicTacToe.

In a game of TicTacToe, two players take turns marking an available cell in a 3 x 3 grid with their respective tokens (either X or O). When one player has placed three tokens in a horizontal, vertical, or diagonal row on the grid, the game is over and that player has won. A draw (no winner) occurs when all the cells on the grid have been filled with tokens and neither player has achieved a win. Figure 16.10 shows two representative sample runs of the example.

Figure 16.10. Two players play a TicTacToe game.


All the examples you have seen so far show simple behaviors that are easy to model with classes. The behavior of the TicTacToe game is somewhat more complex. To create classes that model the behavior, you need to study and understand the game.

Assume that all the cells are initially empty, and that the first player takes the X token, and the second player takes the O token. To mark a cell, the player points the mouse to the cell and clicks it. If the cell is empty, the token (X or O) is displayed. If the cell is already filled, the player's action is ignored.

From the preceding description, it is obvious that a cell is a GUI object that handles the mouse-click event and displays tokens. Such an object could be either a button or a panel. Drawing on panels is more flexible than on buttons , because the token (X or O) can be drawn on a panel in any size , but on a button it can only be displayed as a text label. Therefore, a panel should be used to model a cell. How do you know the state of the cell (empty, X, or O)? You use a property named token of char type in the Cell class. The Cell class is responsible for drawing the token when an empty cell is clicked. So you need to write the code for listening to the MouseEvent and for painting the shapes for tokens X and O. The Cell class can be defined as shown in Figure 16.11.


[Page 551]
Figure 16.11. The Cell class paints the token on a cell.

The TicTacToe board consists of nine cells, declared using new Cell[3][3] . To determine which player's turn it is, you can introduce a variable named whoseTurn of char type. whoseTurn is initially X, then changes to O, and subsequently changes between X and O whenever a new cell is occupied. When the game is over, set whoseTurn to ' ' .

How do you know whether the game is over, whether there is a winner, and who the winner, if any, is? You can create a method named isWon(char token) to check whether a specified token has won and a method named isFull() to check whether all the cells are occupied.

Clearly, two classes emerge from the foregoing analysis. One is the Cell class, which handles operations for a single cell; and the other is the TicTacToe class, which plays the whole game and deals with all the cells. The relationship between these two classes is shown in Figure 16.12.

Figure 16.12. The TicTacToe class contains nine cells.

Since the Cell class is only to support the TicTacToe class, it can be defined as an inner class in TicTacToe . The complete program is given in Listing 16.7.


[Page 552]
Listing 16.7. TicTacToe.java
(This item is displayed on pages 552 - 554 in the print version)
 1   import   java.awt.*; 2   import   java.awt.event.*; 3   import   javax.swing.*; 4   import   javax.swing.border.LineBorder; 5 6   public class    TicTacToe   extends   JApplet  { 7  // Indicate which player has a turn, initially it is the X player  8   private char   whoseTurn =   'X'   ; 9 10  // Create and initialize cells  11   private   Cell[][] cells =   new   Cell[   3   ][   3   ]; 12 13  // Create and initialize a status label  14   private   JLabel jlblStatus =   new   JLabel(   "X's turn to play"   ); 15 16  /** Initialize UI */  17    public   TicTacToe()  { 18  // Panel p to hold cells  19 JPanel p =   new   JPanel(   new   GridLayout(   3   ,   3   ,     ,     )); 20   for   (   int   i =     ; i <   3   ; i++) 21   for   (   int   j =     ; j <   3   ; j++) 22 p.add(cells[i][j] =   new   Cell()); 23 24  // Set line borders on the cells panel and the status label  25 p.setBorder(   new   LineBorder(Color.red,   1   )); 26 jlblStatus.setBorder(   new   LineBorder(Color.yellow,   1   )); 27 28  // Place the panel and the label to the applet  29 add(p, BorderLayout.CENTER); 30 add(jlblStatus, BorderLayout.SOUTH); 31 } 32 33  /** Determine if the cells are all occupied */  34    public boolean   isFull()  { 35   for   (   int   i =     ; i <   3   ; i++) 36   for   (   int   j =     ; j <   3   ; j++) 37   if   (cells[i][j].getToken() ==   ' '   ) 38   return false   ; 39 40   return true   ; 41 } 42 43  /** Determine if the player with the specified token wins */  44    public boolean   isWon(   char   token)  { 45   for   (   int   i =     ; i <   3   ; i++) 46   if   ((cells[i][     ].getToken() == token) 47 && (cells[i][   1   ].getToken() == token) 48 && (cells[i][   2   ].getToken() == token)) { 49   return true   ; 50 } 51 52   for   (   int   j =     ; j <   3   ; j++) 53   if   ((cells[     ][j].getToken() == token) 54 && (cells[   1   ][j].getToken() == token) 55 && (cells[   2   ][j].getToken() == token)) { 56   return true   ; 57 } 58 

[Page 553]
 59   if   ((cells[     ][     ].getToken() == token) 60 && (cells[   1   ][   1   ].getToken() == token) 61 && (cells[   2   ][   2   ].getToken() == token)) { 62   return true   ; 63 } 64 65   if   ((cells[     ][   2   ].getToken() == token) 66 && (cells[   1   ][   1   ].getToken() == token) 67 && (cells[   2   ][     ].getToken() == token)) { 68   return true   ; 69 } 70 71   return false   ; 72 } 73 74  // An inner class for a cell  75   public class    Cell   extends   JPanel  { 76  // Token used for this cell  77   private char   token =   ' '   ; 78 79   public   Cell() { 80 setBorder(   new   LineBorder(Color.black,   1   ));  // Set cell's border  81  addMouseListener(   new   MouseListener());   // Register listener  82 } 83 84  /** Return token */  85   public char   getToken() { 86   return   token; 87 } 88 89  /** Set a new token */  90   public void   setToken(   char   c) { 91 token = c; 92 repaint(); 93 } 94 95  /** Paint the cell */  96    protected voi   d paintComponent(Graphics g)  { 97   super   .paintComponent(g); 98 99   if   (token ==   'X'   ) { 100 g.drawLine(   10   ,   10   , getWidth() -   10   , getHeight() -   10   ); 101 g.drawLine(getWidth() -   10   ,   10   ,   10   , getHeight() -   10   ); 102 } 103   else if   (token ==   'O'   ) { 104 g.drawOval(   10   ,   10   , getWidth() -   20   , getHeight() -   20   ); 105 } 106 } 107 108    private class   MouseListener   extends   MouseAdapter {  109  /** Handle mouse click on a cell */  110    public void   mouseClicked(MouseEvent e)  { 111  // If cell is empty and game is not over  112   if   (token ==   ' '   && whoseTurn !=   ' '   ) { 113 setToken(whoseTurn);  // Set token in the cell  114 115  // Check game status  116   if   (isWon(whoseTurn)) { 117 jlblStatus.setText(whoseTurn +   " won! The game is over"   ); 118 whoseTurn =   ' '   ;  // Game is over  

[Page 554]
 119 } 120   else if   (isFull()) { 121 jlblStatus.setText(   "Draw! The game is over"   ); 122 whoseTurn =   ' '   ;  // Game is over  123 } 124   else   { 125 whoseTurn = (whoseTurn ==   'X'   ) ?   'O'   :   'X'   ; 126 jlblStatus.setText(whoseTurn +   "'s turn"   ); 127 } 128 } 129 } 130 } 131 } 132 } 

The TicTacToe class initializes the user interface with nine cells placed in a panel of GridLayout (lines 19 “22). A label named jlblStatus is used to show the status of the game (line 14). The variable whoseTurn (line 8) is used to track the next type of token to be placed in a cell. The methods isFull (lines 34 “41) and isWon (lines 44 “72) are for checking the status of the game.

Since Cell is an inner class in TicTacToe , the variable ( whoseTurn ) and methods ( isFull and isWon ) defined in TicTacToe can be referenced from the Cell class. The inner class makes programs simple and concise . If Cell were not declared as an inner class of TicTacToe , you would have to pass an object of TicTacToe to Cell in order for the variables and methods in TicTacToe to be used in Cell . You will rewrite the program without using an inner class in Exercise 16.6.

The listener for MouseEvent is registered for the cell (line 81). If an empty cell is clicked and the game is not over, a token is set in the cell (line 113). If the game is over, whoseTurn is set to ' ' (lines 118, 122). Otherwise, whoseTurn is alternated to a new turn (line 125).

Tip

Use an incremental approach in developing and testing a Java project of this kind. The foregoing program can be divided into five steps.

1.
Lay out the user interface and display a fixed token X on a cell.

2.
Enable the cell to display a fixed token X upon a mouse click.

3.
Coordinate between the two players so as to display tokens X and O alternately.

4.
Check whether a player wins, or whether all the cells are occupied without a winner.

5.
Implement displaying a message on the label upon each move by a player.


 


Introduction to Java Programming-Comprehensive Version
Introduction to Java Programming-Comprehensive Version (6th Edition)
ISBN: B000ONFLUM
EAN: N/A
Year: 2004
Pages: 503

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net