Tic Tac Toe

I created a simple GUI Tic Tac Toe application this morning. It works fine. I would like to know if this is an efficient way to do this program?Any input is well received.

package tic_tac_toe;

import java.awt.GridLayout;

import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JOptionPane;

import javax.swing.JPanel;

import javax.swing.UIManager;

publicclass Tic_tac_toe{

publicstaticvoid main(String[] args){

new Tic_tac_toe();

}

public Tic_tac_toe(){

int turn = 0;

int turns_taken = 0;

try{

UIManager.getSystemLookAndFeelClassName();// looks like the XP default window.

}catch (Exception e){}

JFrame ticTacToe =new JFrame("Tic Tac Toe");// creates top level container.

ticTacToe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// makes so the frame closes when you hit x button.

JPanel buttonPanel =new JPanel();

buttonPanel.setLayout(new GridLayout(3,3));

JButton button1 =new JButton("");

button1.setName("");

JButton button2 =new JButton("");

button2.setName("");

JButton button3 =new JButton("");

button3.setName("");

JButton button4 =new JButton("");

button4.setName("");

JButton button5 =new JButton("");

button5.setName("");

JButton button6 =new JButton("");

button6.setName("");

JButton button7 =new JButton("");

button7.setName("");

JButton button8 =new JButton("");

button8.setName("");

JButton button9 =new JButton("");

button9.setName("");

button1.addMouseListener(new Click(turn,turns_taken,button1,button2,button3,button4,button5,button6,button7,button8,button9));

button2.addMouseListener(new Click(turn,turns_taken,button1,button2,button3,button4,button5,button6,button7,button8,button9));

button3.addMouseListener(new Click(turn,turns_taken,button1,button2,button3,button4,button5,button6,button7,button8,button9));

button4.addMouseListener(new Click(turn,turns_taken,button1,button2,button3,button4,button5,button6,button7,button8,button9));

button5.addMouseListener(new Click(turn,turns_taken,button1,button2,button3,button4,button5,button6,button7,button8,button9));

button6.addMouseListener(new Click(turn,turns_taken,button1,button2,button3,button4,button5,button6,button7,button8,button9));

button7.addMouseListener(new Click(turn,turns_taken,button1,button2,button3,button4,button5,button6,button7,button8,button9));

button8.addMouseListener(new Click(turn,turns_taken,button1,button2,button3,button4,button5,button6,button7,button8,button9));

button9.addMouseListener(new Click(turn,turns_taken,button1,button2,button3,button4,button5,button6,button7,button8,button9));

buttonPanel.add(button1);

buttonPanel.add(button2);

buttonPanel.add(button3);

buttonPanel.add(button4);

buttonPanel.add(button5);

buttonPanel.add(button6);

buttonPanel.add(button7);

buttonPanel.add(button8);

buttonPanel.add(button9);

ticTacToe.add(buttonPanel);// adds the superpanel to the frame.

ticTacToe.setResizable(true);

ticTacToe.pack();// makes the frame work

ticTacToe.setVisible(true);// makes the frame visible

}

publicstaticvoid reset(JButton button1,JButton button2,JButton button3,JButton button4,JButton button5,JButton button6,JButton button7,JButton button8,JButton button9){

button1.setName("");

button1.setText("");

button1.setEnabled(true);

button2.setName("");

button2.setText("");

button2.setEnabled(true);

button3.setName("");

button3.setText("");

button3.setEnabled(true);

button4.setName("");

button4.setText("");

button4.setEnabled(true);

button5.setName("");

button5.setText("");

button5.setEnabled(true);

button6.setName("");

button6.setText("");

button6.setEnabled(true);

button7.setName("");

button7.setText("");

button7.setEnabled(true);

button8.setName("");

button8.setText("");

button8.setEnabled(true);

button9.setName("");

button9.setText("");

button9.setEnabled(true);

}

}

class Clickextends MouseAdapter{

staticint t, tt;

JButton b1, b2, b3, b4, b5, b6, b7, b8, b9;

public Click(int turn,int turns_taken, JButton button1,JButton button2,JButton button3,JButton button4,JButton button5,JButton button6,JButton button7,JButton button8,JButton button9){

t = turn;

tt = turns_taken;

b1 = button1;

b2 = button2;

b3 = button3;

b4 = button4;

b5 = button5;

b6 = button6;

b7 = button7;

b8 = button8;

b9 = button9;

}

publicvoid mouseClicked(MouseEvent e){

JButton button = (JButton)e.getSource();

if (t==0 && button.getName() ==""){

button.setText(" X ");

button.setName("X");

t++;

tt++;

button.setEnabled(false);// disables button after use.

if (b1.getName() =="X" && b2.getName() =="X" && b3.getName() =="X"){

JOptionPane.showMessageDialog(null,"X Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (b1.getName() =="X" && b4.getName() =="X" && b7.getName() =="X"){

JOptionPane.showMessageDialog(null,"X Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (b1.getName() =="X" && b5.getName() =="X" && b9.getName() =="X"){

JOptionPane.showMessageDialog(null,"X Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (b4.getName() =="X" && b5.getName() =="X" && b6.getName() =="X"){

JOptionPane.showMessageDialog(null,"X Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (b7.getName() =="X" && b8.getName() =="X" && b9.getName() =="X"){

JOptionPane.showMessageDialog(null,"X Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (b2.getName() =="X" && b5.getName() =="X" && b8.getName() =="X"){

JOptionPane.showMessageDialog(null,"X Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (b3.getName() =="X" && b5.getName() =="X" && b7.getName() =="X"){

JOptionPane.showMessageDialog(null,"X Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (b3.getName() =="X" && b6.getName() =="X" && b9.getName() =="X"){

JOptionPane.showMessageDialog(null,"X Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (tt == 9){

JOptionPane.showMessageDialog(null,"Draw","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}

}elseif (t==1 && button.getName() ==""){

button.setText(" O ");

button.setName("O");

t--;

tt++;

button.setEnabled(false);// disables button after use

if (b1.getName() =="O" && b2.getName() =="O" && b3.getName() =="O"){

JOptionPane.showMessageDialog(null,"O Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (b1.getName() =="O" && b4.getName() =="O" && b7.getName() =="O"){

JOptionPane.showMessageDialog(null,"O Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (b1.getName() =="O" && b5.getName() =="O" && b9.getName() =="O"){

JOptionPane.showMessageDialog(null,"O Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (b4.getName() =="O" && b5.getName() =="O" && b6.getName() =="O"){

JOptionPane.showMessageDialog(null,"O Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (b7.getName() =="O" && b8.getName() =="O" && b9.getName() =="O"){

JOptionPane.showMessageDialog(null,"O Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (b2.getName() =="O" && b5.getName() =="O" && b8.getName() =="O"){

JOptionPane.showMessageDialog(null,"O Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (b3.getName() =="O" && b5.getName() =="O" && b7.getName() =="O"){

JOptionPane.showMessageDialog(null,"O Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (b3.getName() =="O" && b6.getName() =="O" && b9.getName() =="O"){

JOptionPane.showMessageDialog(null,"O Wins the Game!","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}elseif (tt == 9){

JOptionPane.showMessageDialog(null,"Draw","Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b1,b2,b3,b4,b5,b6,b7,b8,b9);

}

}

}

}

[18224 byte] By [sascottoa] at [2007-11-26 13:25:34]
# 1
You should split it up into more methods.
CaptainMorgan08a at 2007-7-7 18:01:05 > top of Java-index,Java Essentials,Java Programming...
# 2
There's a lot of code repetition going on there; shouldn't there be a 'for'loop somewhere in there?kind regards,Jos
JosAHa at 2007-7-7 18:01:05 > top of Java-index,Java Essentials,Java Programming...
# 3

1) create the buttons and add them to an array so you can use loops for processing as suggested above

2) after you create the buttons you invoke the reset() method. No need for duplicate "reset" code.

3) change the reset method to loop through the array and reset the buttons

4) don't use a MouseListener, use an ActionListener. Thats the standard way to handle clicking of a button. For example, what if the user want to use the space bar to click the button instead of using the mouse.

5) you only need to create a single listener that is shared by all the button. You do this by implementing ActionListener in your class and then implementing the actionPerformed(...) method

6) you don't need to use the setName(...) method of the button to determine its value, you can just use getText().

7) don't use "==" to compare Strings, use the equals() method.

8) you don't need to test for "X"' or "O" separately. You only care that the three buttons you are testing have the same value.

camickra at 2007-7-7 18:01:05 > top of Java-index,Java Essentials,Java Programming...
# 4

Thank you for the time and tips. Here is the result I came up with.

package tic_tac_toe;

import java.awt.GridLayout;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JOptionPane;

import javax.swing.JPanel;

import javax.swing.UIManager;

public class Tic_tac_toe {

static int rows = 3;

static int cols = 3;

static int turn = 0;

static int turns_taken = 0;

public static void main(String[] args) {

new Tic_tac_toe();

}

public Tic_tac_toe(){

try {

UIManager.getSystemLookAndFeelClassName(); // looks like the XP default window.

} catch (Exception e) { }

JFrame ticTacToe = new JFrame("Tic Tac Toe"); // creates top level container.

ticTacToe.setSize(300,300);

ticTacToe.setLocation(200,200);

ticTacToe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // makes so the frame closes when you hit x button.

JPanel buttonPanel = new JPanel();

buttonPanel.setLayout(new GridLayout(rows,cols));

JButton buttons[] = new JButton[rows * cols];

for(int y = 0; y < rows; y++){

for(int x = 0; x < cols; x++)

{

int index = y * rows + x;

buttons[index] = new JButton("");

buttons[index].addActionListener(new Click(turn,turns_taken,buttons));

buttonPanel.add(buttons[index]);

}

}

ticTacToe.add(buttonPanel); // adds the superpanel to the frame.

ticTacToe.setResizable(false);

ticTacToe.pack(); // makes the frame work

ticTacToe.setVisible(true); // makes the frame visible

}

public static void reset(JButton buttons[]) {

for (int i = 0; i < rows * cols; i++){

buttons[i].setText("");

buttons[i].setEnabled(true);

}

}

public static boolean checkWon(JButton b[]){

boolean won = false;

JButton button[] = b;

if ((button[0].getText().equals(" X ") || button[0].getText().equals(" O ")) && button[0].getText().equals(b[1].getText()) && button[1].getText().equals(b[2].getText())) {

won = true;

} else if ((button[0].getText().equals(" X ") || button[0].getText().equals(" O ")) && button[0].getText().equals(b[1].getText()) && button[1].getText().equals(b[2].getText())) {

won = true;

} else if ((button[3].getText().equals(" X ") || button[3].getText().equals(" O ")) && button[3].getText().equals(b[4].getText()) && button[3].getText().equals(b[5].getText())) {

won = true;

} else if ((button[6].getText().equals(" X ") || button[6].getText().equals(" O ")) && button[6].getText().equals(b[7].getText()) && button[6].getText().equals(b[8].getText())) {

won = true;

} else if ((button[0].getText().equals(" X ") || button[0].getText().equals(" O ")) && button[0].getText().equals(b[4].getText()) && button[0].getText().equals(b[8].getText())) {

won = true;

} else if ((button[2].getText().equals(" X ") || button[2].getText().equals(" O ")) && button[2].getText().equals(b[4].getText()) && button[2].getText().equals(b[6].getText())) {

won = true;

} else if ((button[0].getText().equals(" X ") || button[0].getText().equals(" O ")) && button[0].getText().equals(b[3].getText()) && button[0].getText().equals(b[6].getText())) {

won = true;

} else if ((button[1].getText().equals(" X ") || button[1].getText().equals(" O ")) && button[1].getText().equals(b[4].getText()) && button[1].getText().equals(b[7].getText())) {

won = true;

} else if ((button[2].getText().equals(" X ") || button[2].getText().equals(" O ")) && button[2].getText().equals(b[5].getText()) && button[2].getText().equals(b[8].getText())) {

won = true;

}

return won;

}

}

class Click implements ActionListener {

static int t, tt;

JButton b[];

public Click(int turn, int turns_taken, JButton buttons[]){

t = turn;

tt = turns_taken;

b = buttons;

}

public void actionPerformed(ActionEvent event){

JButton button = (JButton)event.getSource();

if (t==0 && button.getText() == ""){

button.setText(" X ");

t++;

tt++;

button.setEnabled(false); // disables button after use.

boolean won = Tic_tac_toe.checkWon(b);

if(tt>4){

if (won){

JOptionPane.showMessageDialog(null, button.getText() + "Wins the game!", "Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b);

tt = 0;

t = 0;

}

}

}else if (t==1 && button.getText() == "") {

button.setText(" O ");

t--;

tt++;

button.setEnabled(false); // disables button after use

boolean won = Tic_tac_toe.checkWon(b);

if (tt>5){

if (won){

JOptionPane.showMessageDialog(null, button.getText() + "Wins the game!", "Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b);

tt = 0;

t = 0;

}

}

}if (tt == 9) {

JOptionPane.showMessageDialog(null, "Draw", "Game Over", JOptionPane.ERROR_MESSAGE);

Tic_tac_toe.reset(b);

tt = 0;

t = 0;

}

}

}

sascottoa at 2007-7-7 18:01:05 > top of Java-index,Java Essentials,Java Programming...
# 5

I'd say it works fine now.

If it really was a good object oriented design it would probably consist of more classes, but also of more lines of code. (There's stil some repetition in the method that checks for a win situation, however I don't think the code for this can be cut down to be much less lines because the board in tic-tac-toe isn't that large.)

Strider80a at 2007-7-7 18:01:05 > top of Java-index,Java Essentials,Java Programming...
# 6
I think you should have your TicTacToe class extend JFrame and implement ActionListener. That way, you would have to create a whole seperate class for the ActionListener. Also, there has to be an easier way to write the checkWon() method.
CaptainMorgan08a at 2007-7-7 18:01:05 > top of Java-index,Java Essentials,Java Programming...
# 7
Er, you want him to make it *less* OO? That doesn't make any sense.
es5f2000a at 2007-7-7 18:01:05 > top of Java-index,Java Essentials,Java Programming...
# 8
> Er, you want him to make it *less* OO? That doesn't> make any sense.Inheritance is part of OO Programming. He can split the program up into different classes, but making a whole new class just for the ActionListener seems pointless to me.
CaptainMorgan08a at 2007-7-7 18:01:05 > top of Java-index,Java Essentials,Java Programming...
# 9

TicTacToe is not a JFrame. It has nothing to do with JFrames. There's

no functionality that has anything to do with Frames being extended.

He's absolutely correct to use composition instead of inheritance.

The ActionListener isn't functional inheritance. There's a group of

people who consider implementing an interface to be

inheritance .. I don't count myself among them, but I suppose you

might.

Making TicTacToe implement ActionListener is also not OO.

TicTacToe is a game. It's responsible for playing the game. The

Click ActionListener is responsible for reacting to button clicks in

the game. Separate responsibility, separate class.

http://www.google.com/search?q=Single+Responsibility+Principle

Most of the links are from an Agile Development point of view,

but the idea dates back at least as far as 1979.

I'm not sure what your opposition is to "making a whole new class".

Do you get paid to keep the class count down or something?

I've seen plenty of well-designed classes smaller than Click.

es5f2000a at 2007-7-7 18:01:05 > top of Java-index,Java Essentials,Java Programming...
# 10

If you do want to tighten up the Click class, I have some suggestions.

=> Remove turn and turns_taken from Tic_tac_toe .. they

aren't ever used there, and don't need to be passed in to

Click, which tracks them separately.

=> Rather than making Click.t an int, make it a char or String.

It can alternate between ' ', 'X', and 'O'.

=> Use full variable names rather than t and tt. Your compiler

won't charge you by the letter (I hope!)

Coding is just like English. Writing is re-writing. :)

es5f2000a at 2007-7-7 18:01:05 > top of Java-index,Java Essentials,Java Programming...
# 11

> (There's stil some repetition in

> the method that checks for a win situation, however I

> don't think the code for this can be cut down to be

> much less lines because the board in tic-tac-toe

> isn't that large.)

I think the way out of that is to parameterize what constitutes a win

so you're not repeating the win check code eight times. There are

a variety of ways to do so -- this is one of them:

import java.awt.BorderLayout;

import java.awt.GridLayout;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JOptionPane;

import javax.swing.JPanel;

public class TicTacToe {

private final static int[][] winChances = new int[][] {

{0, 1, 2}, {3, 4, 5}, {6, 7, 8},

{0, 3, 6}, {1, 4, 7}, {2, 5, 8},

{0, 4, 8}, {2, 4, 6}

};

private final JFrame frame = new JFrame("Tic Tac Toe");

private final JButton[] buttons = new JButton[9];

private String turn = "X";

public TicTacToe() {

final JPanel mainPanel = new JPanel(new GridLayout(3, 3));

final ActionListener buttonListener = new ButtonListener();

for (int i = 0; i < 9; i++) {

this.buttons[i] = new JButton();

mainPanel.add(this.buttons[i]);

this.buttons[i].addActionListener(buttonListener);

}

this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

this.frame.getContentPane().add(mainPanel, BorderLayout.CENTER);

this.frame.setBounds(200, 200, 300, 300);

this.frame.setVisible(true);

}

private void checkEndgame() {

for (final int[] winChance : TicTacToe.winChances) {

if (this.checkVictory(winChance)) {

final String winner = this.turn.equals("X") ? "O" : "X";

JOptionPane.showMessageDialog(this.frame, winner + " won the game!",

"Game Over", JOptionPane.INFORMATION_MESSAGE);

this.reset();

return;

}

}

for (final JButton button : this.buttons) {

if (button.getText().equals("")) {

return;

}

}

JOptionPane.showMessageDialog(this.frame, "This game is a draw.", "Game Over",

JOptionPane.INFORMATION_MESSAGE);

this.reset();

}

private boolean checkVictory(final int[] winChance) {

final String firstButtonText = this.buttons[winChance[0]].getText();

final boolean firstSecondEqual =

firstButtonText.equals(this.buttons[winChance[1]].getText());

final boolean firstThirdEqual =

firstButtonText.equals(this.buttons[winChance[2]].getText());

return (!firstButtonText.equals("")) && firstSecondEqual && firstThirdEqual;

}

private void reset() {

this.turn = "X";

for (int i = 0; i < 9; i++) {

this.buttons[i].setText("");

this.buttons[i].setEnabled(true);

}

}

private class ButtonListener implements ActionListener {

public void actionPerformed(final ActionEvent ae) {

final JButton source = (JButton) ae.getSource();

source.setText(TicTacToe.this.turn);

source.setEnabled(false);

if (TicTacToe.this.turn.equals("X")) {

TicTacToe.this.turn = "O";

} else {

TicTacToe.this.turn = "X";

}

TicTacToe.this.checkEndgame();

}

}

public static void main(final String[] argv) {

new TicTacToe();

}

}

es5f2000a at 2007-7-7 18:01:05 > top of Java-index,Java Essentials,Java Programming...