2

I am working on a Tic-Tac-Toe Game. I have added the 9 JButtons with ActionListeners. Each button properly listens for action events. Finally I am working on the logic component of the game but I am stuck on how to go about it.

If you take a look at my TicTacToeButton class, I decided to give the TicTacToeButton object that extends JButton two instance variables: an integer variable that represents the number of the button(so I know which button # was pressed. Number zero is the first number) and a character variable that will be assigned a 'o' character to the character array called boardLogic for player 1 and 'x' for player 2.

The problem is I have no knowledge of how to go about referencing my elements inside the TicTacToeButton array in my TicTacToeBoard class to perform which JButton was actually pressed in the game. Is there a method inside the Java object that tells you whether JButton with number 0 was pressed or JButton with number 1 was pressed corresponding with the code I have stated below.

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Point;
import javax.swing.JFrame;
import javax.swing.JPanel;

/*
 * The TicTacToeBoard is an object that has characterisitics of a JFrame 
 */
public class TicTacToeBoard extends JFrame {

    /* create an array of characters that holds 9 elements 
     *  to create a model for the tic-tac-toe board logic since the board has 9 boxes
     *  create the board from a separate class to minimize bugs and for easier debugging
     *  simulate the game's logic by creating an array of characters
     */
    public static char[] boardLogic = {};
    // number of buttons in the game
    static int numOfButtons = 9;
    // TicTacToeButton is an object that extends JButton
    static TicTacToeButton[] buttons;

    public TicTacToeBoard() {
        // setTitle to the frame
        setTitle("TicTacToe Game");
        /* call this method to the GameFrame object if you do not call this 
         * method the JFrame subclass will not actually close
         */
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        /* set size to an appropriate size create a dimension object 
         * notice my Dimension object does not have a variable this is 
         * a prefer way to create this object since no further 
         * operations will be perform on this object besides this operation 
         */
        setSize(new Dimension(1000, 1000));
        // upon creating the object set the location of the frame to the center of the screen
        setLocation(new Point(0, 0));
        // prevent the user from resizing the GameFrame object
        // uncomment bottom to prevent window maximumization 
        //setResizable(false);
    }

    public void printButtons(Container contentPane) {
        JPanel gamePanel = new JPanel();
        gamePanel.setLayout(new GridLayout(3, 3));
        // the idea of boardLogic is creating a 9 element character array to simulate the game's logic
        boardLogic = new char[numOfButtons];
        // creates the objects of the type JButtons
        buttons = new TicTacToeButton[numOfButtons];
        // create 9 buttons for the game using a for loop
        for (int i = 0; i < buttons.length; i++) {
            // create a new JButton object every loop   
            buttons[i] = new TicTacToeButton(i);
            // set a default value. I use '-' for simplicity.
            boardLogic[i] = buttons[i].getButtonChar();
            // and add it to the frame
            gamePanel.add(buttons[i]);
        }
        contentPane.add(gamePanel, BorderLayout.CENTER);
    }
}

.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;


/* the class design is that we will create a class that has characteristics
 * of what a JButton can do but can also hear for action events
 */
public class TicTacToeButton extends JButton implements ActionListener {

    /* referring my Buttons with names denoted as String type
     * set it empty for now. I will name the JButtons using a for loop
     * the program will use buttonNumber assigned to each button
     * to create the game's logic
     */
    private int buttonNumber = 0;
    // Each character assigned to each button is assigned a hyphen by default
    private char buttonChar = '-';

    public TicTacToeButton(int buttonNumber) {
        // call the JButton super class constructor to initialize the JButtons
        super();
        // set the name of the parameter to the data member of the JButton object 
        this.buttonNumber = buttonNumber;
        // upon creating of the JButton the button will add ActionListener to itself
        addActionListener(this);
    }

    // a get method that retrieves the button's object data member
    public int getButtonNumber() {
        return buttonNumber;
    }

    // everytime the user press a button set the number 10 as the button number
    public void setButtonChar(char buttonChar) {
        if (buttonChar == 'O' || buttonChar == 'X') {
            this.buttonChar = buttonChar;
        }
    }

    public static void printArray() {
        for (int i = 0; i < TicTacToeBoard.boardLogic.length; i++) {
            System.out.println(TicTacToeBoard.boardLogic[i]);
        }
    }

    public char getButtonChar() {
        return buttonChar;
    }

    public void actionPerformed(ActionEvent e) {
        /* both cases must be true before this code can happen
         *  After Player A turn, then is Player B turn
         */
        if (e.getSource() instanceof JButton && TicTacToeBoard.currentPlayerTurn.equals(TicTacToeMain.firstPlayerName)) {
            // Player A uses circle 
            /* the state of the image for the Buttons will change depending on the player's turn 
             *  Player A will use the cross sign , Player B will use Circle Sign
             */
            ImageIcon icon = new ImageIcon("buttonImages/circle-sign.png");
            TicTacToeBoard.currentPlayerTurn = TicTacToeMain.secondPlayerName;
            // set the appropriate picture as the JButton icon
            setIcon(icon);
            // prevent user from clicking the button more than once
            setEnabled(false);
            //increment buttonClick variable by one for each mouse click 
            TicTacToeBoard.buttonClicks += 1;
            //notify both players whose turn is it
            TicTacToeMain.contentPane.remove(TicTacToeBoard.currentPlayerTurnLabel);
            TicTacToeBoard.printCurrentPlayerTurnLabel(TicTacToeMain.contentPane);
            // Tests the Winning conditions of the player's 
            TicTacToeBoardLogic boardLogic = new TicTacToeBoardLogic();
            boardLogic.checksWinningConditions();
        } else {// After Player B turn, then is Player A turn
            // Player B uses cross 
            /* the state of the image for the Buttons will change depending on the player's turn 
             *  Player A will use the cross sign , Player B will use Circle Sign
             */
            ImageIcon icon = new ImageIcon("buttonImages/x-sign.jpg");
            TicTacToeBoard.currentPlayerTurn = TicTacToeMain.firstPlayerName;
            // set the appropriate picture as the JButton icon
            setIcon(icon);
            // prevent user from clicking the button more than once
            setEnabled(false);
            //increment buttonClick variable by one for each mouse click 
            TicTacToeBoard.buttonClicks += 1;
            //notify both players whose turn is it
            TicTacToeMain.contentPane.remove(TicTacToeBoard.currentPlayerTurnLabel);
            TicTacToeBoard.printCurrentPlayerTurnLabel(TicTacToeMain.contentPane);
        }
        // if all buttons been pressed, the game makes a decision
        // Tests the Winning conditions of the player's 
        TicTacToeBoardLogic boardLogic = new TicTacToeBoardLogic();
        boardLogic.checksWinningConditions();
    }
}
Nicholas
  • 679
  • 2
  • 11
  • 29
  • 2
    See also [*How to get X and Y index of element inside GridLayout?*](http://stackoverflow.com/q/7702697/230513) – trashgod Sep 17 '12 at 18:52
  • 1
    I'd suggest using `setActionCommand(String s)` then use `getActionCommand()` which will return the String you assigned it. – David Kroukamp Sep 17 '12 at 19:33

3 Answers3

3

Your winner here is to expand this method a little:

public TicTacToeButton(int buttonNumber) { 
    // call the JButton super class constructor to initialize the JButtons 
    super(); 
    // set the name of the parameter to the data member of the JButton object  
    this.buttonNumber = buttonNumber; 
    // upon creating of the JButton the button will add ActionListener to itself 
    addActionListener(this); 
    setActionCommand(Integer.toString(buttonNumber));*************
} 

(My addition suffixed with stars)

This will "name" the action event associated with the button.

Then in Actionperformed (ActionEvent e) you can get that ActionCommand with e.getActionCommand(). With nine your simplest may be a switch statement. Remember to use varName.equals(e.getActionCommand()) to compare it.

HTH

David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
MrB
  • 818
  • 8
  • 28
2

To know which button was pressed in the TicTacBoard class, I would suggest implement action listener inside the TicTacToe class rather than TicTacToeButton class.

Here is a little demo code for Window class, in your case TicTacToeBoard.

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class Window implements ActionListener{

static Buttons[] buttons = new Buttons[2];

public Window(){
    JFrame f = new JFrame();
    f.setSize(400,400);
    JPanel p = new JPanel();
    GridLayout gl = new GridLayout(1,2);
    p.setLayout(gl);
    for(int i = 0; i<2; i++){
        buttons[i] = new Buttons(i);
        buttons[i].addActionListener(this);
        p.add(buttons[i]);
    }
    f.add(p);
    f.setVisible(true);
}

public static void main(String... args){
    new Window();
}

@Override
public void actionPerformed(ActionEvent e) {
    // TODO Auto-generated method stub
    if(e.getSource() == buttons[0] ){
        System.out.println("0");
    }

}

}

Here is demo of Buttons Class, in your case TicTacToeButton.

import javax.swing.JButton;


public class Buttons extends JButton{

int num = 0;

public Buttons(int num){
    this.num = num;
}



}
Robin Chander
  • 7,225
  • 3
  • 28
  • 42
1

You might want to consider separating out the model (the tictactoe board with the X's and O's) from the view (the JButtons). This will allow you to pass the current state of the game to whatever method you wish without the overhead of the Swing components.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • 1
    @Nicholas Yes, in a way. To put it another way, I suggest separating the game logic from the interface. For one thing this allows you to create a text-based, web-based, and desktop tictactoe games without rewriting the game logic. You just have to write the UI for each one. – Code-Apprentice Sep 17 '12 at 20:17
  • 1
    Finished coding the game logic! Everyone you have been a great help! My first java game completed. – Nicholas Sep 18 '12 at 01:08
  • @Nicholas Feel free to give up-votes to any answers that were helpful ;-) – Code-Apprentice Sep 18 '12 at 19:38