Chapter 11

Developing a Tic-Tac-Toe Applet

Now that you’re familiar with the basics of Java applets, it’ll be nice to write a program a bit more useful than Hello World. In this lesson you’ll program the game of tic-tac-toe as a Java Swing applet.

Every game implements some algorithm — a set of rules or a strategy that has to be applied depending on the player’s actions. The algorithms for the same game can be simple or very complicated. When you hear that the world chess champion plays against a computer, he actually plays against a program. Teams of experts are trying to invent sophisticated algorithms to beat him. Let’s come up with the algorithm for tic-tac-toe.

The Strategy

In the unlikely event that you aren’t familiar with tic-tac-toe, or if it has a different name in your part of the world, read the following Wikipedia article: http://en.wikipedia.org/wiki/Tic-tac-toe. Our version of the popular game will implement the following strategy:

  • The game will be played on a two-dimensional board of three cells by three cells.
  • Two players can play this game. One will play with the symbol X, and the other will use O.
  • The winner must have a full row, column, or diagonal of his or her designated symbol.
  • After each move, the program has to check if there is a winner.
  • The game should end if there are no empty squares left.
  • The player has to press the New Game button to play again.
  • When the program makes a decision about where to put the next letter O, it has to try to find a row, column, or diagonal that already contains two Os, and add the third accordingly.
  • If there is no such row, column, or diagonal, the program has to try to find two Xs in such a configuration and place an O in the free cell to block the player’s winning move.
  • If no winning or blocking move was found, the program has to try to occupy the central square, or pick the next empty square at random.

Coding Tic-Tac-Toe

Let’s implement the strategy for tic-tac-toe as an applet. First, program the UI portion, and then add event processing. I decided to use JPanel, containing nine Jbuttons, to render the three-by-three grid. Review the code in Listing 11-1. Note that the panel uses GridLayout, but with an extra row (four by three). The last row will display the player’s identifier: “Player X” or “Player 0.” Figure 11-1 shows how it may look.

By setting the button label to X or O, on the click event, it’s easy to keep track of each player’s move. At the bottom of the window you’ll see the name of the player who is to make the next move (see the method setPlayerName() in Listing 11-1). The method reset() will clear all the squares after the winner has been announced.

download.eps

Listing 11-1: Coding UI for tic-tac-toe

package com.practicaljava.lesson11;
 
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.GridLayout;
 
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
 
public class TicTacToeApplet1 extends JApplet{
 
    private static String PLAYERX = "Player X";
    private static String PLAYERO = "Player O";
      
    private String playerName = PLAYERX;
 
    private JButton button1;
    private JButton button2;
    private JButton button3;
    private JButton button4;
    private JButton button5;
    private JButton button6;
    private JButton button7;
    private JButton button8;
    private JButton button9;
    private JLabel playerNumber;
    private java.awt.Panel buttonsPanel;
 
    public void init(){
 
        initComponents();
    }
 
    private void initComponents(){
 
        buttonsPanel = new java.awt.Panel();
        button1 = new JButton();
        button2 = new JButton();
        button3 = new JButton();
        button4 = new JButton();
        button5 = new JButton();
        button6 = new JButton();
        button7 = new JButton();
        button8 = new JButton();
        button9 = new JButton();
        playerNumber = new JLabel(playerName, SwingConstants.CENTER);
 
       Font buttonFont = new Font("Times New Roman", Font.PLAIN, 60);
         
        button1.setFont(buttonFont);
        button2.setFont(buttonFont);
        button3.setFont(buttonFont);
        button4.setFont(buttonFont);
        button5.setFont(buttonFont);
        button6.setFont(buttonFont);
        button7.setFont(buttonFont);
        button8.setFont(buttonFont);
        button9.setFont(buttonFont);
          
        buttonsPanel.setLayout(new GridLayout(4, 3));
 
        buttonsPanel.add(button1);
        buttonsPanel.add(button2);
        buttonsPanel.add(button3);
        buttonsPanel.add(button4);
        buttonsPanel.add(button5);
        buttonsPanel.add(button6);
        buttonsPanel.add(button7);
        buttonsPanel.add(button8);
        buttonsPanel.add(button9);
        
        buttonsPanel.add(new Component(){});
        setPlayeName(PLAYERX);
        buttonsPanel.add(playerNumber);
        
        add(buttonsPanel);
    }
      
    private void setPlayerName(String playerName){
 
        this.playerName = playerName;
        playerNumber.setText(playerName +", your turn.");
    }
      
    public void reset(){
        button1.setText("");
        button2.setText("");
        button3.setText("");
        button4.setText("");
        button5.setText("");
        button6.setText("");
        button7.setText("");
        button8.setText("");
        button9.setText("");
        setPlayerName(PLAYERX);
    }
}

As you learned in Lesson 10, the callback method init() will be automatically called by the Java plug-in when the applet is downloaded by the web browser. While in development mode, you can also test your applets right in Eclipse with appletviewer. Note that the code in Listing 11-1 does not set the size of the game board — that has to be done externally, either in an HTML file, as in Listing 11-2, or in Eclipse in the Run Configuration window. The width of my game board is set to 350 pixels and the height is 400.

download.eps

Listing 11-2: HTML wrapper for the tic-tac-toe applet

<HTML>
  <HEAD>
   <Title>My First Game in Java</Title>
  </HEAD>
 
  <BODY>
 
     <STRONG>Play Tic-Tac-Toe with me! </STRONG>
     <BR>
     <APPLET code="com.practicaljava.lesson11.TicTacToeApplet" 
             codebase="./bin" width="350" height="400" />
 
  </BODY>
 
</HTML>

Swing and GroupLayout

The code in Listing 11-1 was written manually. But most likely, if you’re developing a complex GUI, you’ll use some Swing GUI builder such as Matisse that will allow you to design windows in what-you-see-is-what-you-get mode by dragging and dropping visual components onto the design area. If you look at the auto-generated code you may find GroupLayout, created by the GUI builder (but you can program this layout manually, too).

GroupLayout groups components inside a container. Imagine a shipping or billing form that contains several text labels, one under another, each having an input field next to it. Each label contains a different number of characters, which means that you’ll need to align the input fields so the form looks pretty. If you can think of this UI as of two vertical groups (labels belong to one and input fields to another), you can simply set the gap between the left and right groups to 20 pixels or so.

Similarly, you can distinguish some horizontal groups in your UI. If you want to learn more about GroupLayout, follow this link: http://download-llnw.oracle.com/javase/6/docs/api/javax/swing/GroupLayout.html.

After the UI part is ready, let’s take care of the processing logic. Our applet will be processing mouse clicks to set the label of the selected button to X or O and checking for the winner. That’s why you’ll need to perform these steps:

1. Add implements MouseListener to the class TicTacToeApplet.

2. Add MouseListener to each of the buttons so they properly report which player (X or O) clicked them, for example

button1.addMouseListener(this);

3. Implement methods required by the MouseListener interface — only the mouseClicked() callback will have code in this applet.

4. Call the method checkForWinner() on each click to determine whether there are three identical symbols in a row, column, or diagonal, as shown in Listing 11-3.

download.eps

Listing 11-3: Processing button click events

public void mouseClicked(MouseEvent e) {
 
  JButton currentButton = (JButton)e.getComponent();
  if (currentButton.getText() == ""){
         if (playerName == PLAYERX) {
                currentButton.setText("X");
                setPlayerName(PLAYERO);
            
         } else if (playerName == PLAYERO){
 
                currentButton.setText("O");
                setPlayerName(PLAYERX);
         }
  }
 
        checkForWinner();
}

When the user clicks a button, the method mouseClicked() checks the name of the current player and displays X or O accordingly by calling currentButton.SetText(). Figure 11-2 depicts how this looks in the web browser.

The method checkForWinner() will call another private method, findThreeInARow(). If three identical symbols are found diagonally or in any vertical or horizontal line, the method checkForWinner() will congratulate the winner and call reset() so the new game can be started. The methods checkForWinner() and findThreeInARow() are shown in Listings 11-4 and 11-5 respectively.

download.eps

Listing 11-4: The method checkForWinner()

private void checkForWinner(){
 
  String [] str = {"OK"};
 
  if(findThreeInARow()){
 
   String winnerName=(playerName == PLAYERX)?PLAYERO:PLAYERX;
   JOptionPane.showOptionDialog(this, winnerName.concat(
              " won!!! Congratulations!!!"), "Congratulations!",
JOptionPane.YES_OPTION, JOptionPane.PLAIN_MESSAGE, null, str, "OK");
 
   reset();
  }    
}
download.eps

Listing 11-5: The method findThreeInARow()

private boolean findThreeInARow(){
 
 if ((button1.getText() == button2.getText() && button2.getText() ==
   button3.getText() && button1.getText() != "") ||
 (button4.getText() == button5.getText() && button5.getText() ==   
   button6.getText() && button4.getText() != "") || 
 (button7.getText() == button8.getText() && button8.getText() ==  
  button9.getText() && button7.getText() != "") ||
 (button1.getText() == button4.getText() && button4.getText() ==
   button7.getText() && button1.getText() != "") ||
 (button2.getText() == button5.getText() && button5.getText() ==
   button8.getText() && button2.getText() != "") ||
 (button3.getText() == button6.getText() && button6.getText() == 
  button9.getText() && button3.getText() != "") ||
 (button1.getText() == button5.getText() && button5.getText() ==  
   button9.getText() && button1.getText() != "") ||
 (button3.getText() == button5.getText() && button5.getText() ==  
   button7.getText() && button3.getText() != "")
)
   //There is a winner! 
  return true;
 
else
  //No three-in-a-row was found
  return false;
}

The complete code for this version of tic-tac-toe is included on the website and is given in Listing 11-6 for your reference.

download.eps

Listing 11-6: Complete code for the tic-tac-toe game

package com.practicaljava.lesson11;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
public class TicTacToeApplet extends JApplet                                     implements MouseListener {
 
    private static String PLAYERX = "Player X";
    private static String PLAYERO = "Player O";
    private String playerName = PLAYERX;
    private JButton button1;
    private JButton button2;
    private JButton button3;
    private JButton button4;
    private JButton button5;
    private JButton button6;
    private JButton button7;
    private JButton button8;
    private JButton button9;
    private JLabel playerNumber;
    private Panel buttonsPanel;
 
    public void init(){
        initComponents();
    }
    private void initComponents(){
        buttonsPanel = new Panel();
        button1 = new JButton();
        button2 = new JButton();
        button3 = new JButton();
        button4 = new JButton();
        button5 = new JButton();
        button6 = new JButton();
        button7 = new JButton();
        button8 = new JButton();
        button9 = new JButton();
 
        playerNumber = new JLabel(playerName,                                  SwingConstants.CENTER);
        button1.addMouseListener(this);
        button2.addMouseListener(this);
        button3.addMouseListener(this);
        button4.addMouseListener(this);
        button5.addMouseListener(this);
        button6.addMouseListener(this);
        button7.addMouseListener(this);
        button8.addMouseListener(this);
        button9.addMouseListener(this);
 
        Font buttonFont = new Font("Times New Roman",                                           Font.PLAIN, 60);
        button1.setFont(buttonFont);
        button2.setFont(buttonFont);
        button3.setFont(buttonFont);
        button4.setFont(buttonFont);
        button5.setFont(buttonFont);
        button6.setFont(buttonFont);
        button7.setFont(buttonFont);
        button8.setFont(buttonFont);
        button9.setFont(buttonFont);
        
        buttonsPanel.setLayout(new java.awt.GridLayout(4, 3));
        buttonsPanel.add(button1);
        buttonsPanel.add(button2);
        buttonsPanel.add(button3);
        buttonsPanel.add(button4);
        buttonsPanel.add(button5);
        buttonsPanel.add(button6);
        buttonsPanel.add(button7);
        buttonsPanel.add(button8);
        buttonsPanel.add(button9);
        buttonsPanel.add(new Component(){});
 
        setPlayerName(PLAYERX); 
        buttonsPanel.add(playerNumber);
        add(buttonsPanel);
    }
 
    private void setPlayerName(String playerName){
        this.playerName = playerName;
        playerNumber.setText(playerName  + ", your turn. ");
    }
      
    private void reset(){
        button1.setText("");
        button2.setText("");
        button3.setText("");
        button4.setText("");
        button5.setText("");
        button6.setText("");
        button7.setText("");
        button8.setText("");
        button9.setText("");
 
        setPlayerName(PLAYERX);
    }
 
   private void checkForWinner(){
        String [] str = {"OK"};
       if(findThreeInARow()){
         String winnerName=         (playerName == PLAYERX)?PLAYERO:PLAYERX;
 
         JOptionPane.showOptionDialog(this,          winnerName.concat(" won!!! Congratulations!!!"),
         "Congratulations!", JOptionPane.YES_OPTION,          JOptionPane.PLAIN_MESSAGE, null, str, "OK");
            reset();
        }    
}
 
public void mouseClicked(MouseEvent e) {
        JButton currentButton = (JButton)e.getComponent();
        if (currentButton.getText() == ""){
            if (playerName == PLAYERX) {
                currentButton.setText("X");
                setPlayerName(PLAYERO);
            } else if (playerName == PLAYERO){
                currentButton.setText("O");
                setPlayerName(PLAYERX);
            }
        }
        checkForWinner();
    }
 
      public void mousePressed(MouseEvent e) {}
      public void mouseReleased(MouseEvent e) {}
      public void mouseEntered(MouseEvent e) {}
      public void mouseExited(MouseEvent e) {}
 
      public boolean findThreeInARow(){
          if ((button1.getText() == button2.getText() && button2.getText() == button3.getText() && button1.getText() != "") ||
                (button4.getText() == button5.getText() && button5.getText() == button6.getText() && button4.getText() != "") || 
              (button7.getText() == button8.getText() && button8.getText() == button9.getText() && button7.getText() != "") ||
            (button1.getText() == button4.getText() && button4.getText() == button7.getText() && button1.getText() != "") ||
            (button2.getText() == button5.getText() && button5.getText() == button8.getText() && button2.getText() != "") ||
            (button3.getText() == button6.getText() && button6.getText() == button9.getText() && button3.getText() != "") ||
            (button1.getText() == button5.getText() && button5.getText() == button9.getText() && button1.getText() != "") ||
            (button3.getText() == button5.getText() && button5.getText() == button7.getText() && button3.getText() != "")
        ){
             return true;
        }else {
              return false;
        }      
      }
 
}

Congratulations! You’ve completed your first game in Java. This program uses a simple strategy because our goal is just to learn how to program Java applets. There is one more important class for working with Swing UI using the Swing Worker Thread, but it’s a bit too early to explain it here because I haven’t covered Java threads yet. You can read about the SwingWorker class in Lesson 20.

Try It

Today’s homework is to modify the code from Listing 11-6 to make it shorter and change the game — the current version of tic-tac-toe requires two human players, but I want you to replace one of them with the computer (which also has some brainpower). I also want you to highlight the winning combination rather than displaying a pop-up window with congratulations.

Lesson Requirements

You should have Java installed.

note.ai

You can download the code and resources for this Try It from the book’s web page at www.wrox.com. You can find them in the Lesson11 folder in the download.

Step-by-Step

1. Create a new Eclipse project called Lesson11, copy TicTacToeApplet from the DVD accompanying the book into this project, and run it to ensure that you can play this two-player game.

2. The code in Listing 11-6 performs lots of repetitive actions on buttons, such as setFont(), setText(), and addMouseListener(). Create an array and store all instances of JButton there. Introduce loops to perform all repetitive actions on the buttons.

3. Get rid of the pop-up window congratulating the winner with JOptionPane.showOptionDialog(). Display this text instead at the bottom of the window (use the existing JLabel playerNumber for this).

4. Highlight the winning combination by giving the winning squares (Swing JButtons) a different color.

5. Add a new button, Play Again, at the bottom of the window for starting a new game.

6. Replace the moves of Player O with randomly generated moves made by the computer right after the Player X moves. Use the method nextInt() from the class java.util.Random. If the randomly generated square is occupied, call this method again.

7. Test this program and enjoy the game!

8. This step is optional. If you want to make the computer’s moves smarter, learn minimax strategy (see http://en.wikipedia.org/wiki/Minimax) to enable the computer to select the best move.

cd.ai

Please select Lesson 11 on the DVD with the print book, or watch online at www.wrox.com/go/fainjava to view the video that accompanies this lesson.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.218.105