View Single Post
  #2 (permalink)  
Old 01-11-2007, 02:12 PM
John's Avatar   
John John is offline
Co-Administrator
 
Join Date: Jul 2006
Age: 19
Posts: 2,733
Last Blog:
Passwords
Rep Power: 20
John has much to be proud ofJohn has much to be proud ofJohn has much to be proud ofJohn has much to be proud ofJohn has much to be proud ofJohn has much to be proud ofJohn has much to be proud ofJohn has much to be proud ofJohn has much to be proud of
Send a message via AIM to John
Default

Now in the tutorial above there is a lot of repeated code that can be accounted for by loops an arrays. The first thing I did to make the code more efficient was add the JButtons to an array and loop the array to add the JButton objects to the frame. So lets make an array

Code:
private JButton buttons[] = new JButton[9];
Then replacing the lines that look like this
Code:
private JButton button1 = new JButton("");
and this
Code:
button1.addActionListener(this);
with this
Code:
for(int i=0; i<=8; i++){
	buttons[i] = new JButton();
	window.add(buttons[i]);
	buttons[i].addActionListener(this);
}
Now we've just replaced 27 lines of code with 5. How about making the win conditions more efficient? Well I created an array that listed all the possible win combonations:
Code:
private int[][] winCombinations = new int[][] {
	{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, //horizontal wins
	{0, 3, 6}, {1, 4, 7}, {2, 5, 8}, //virticle wins
	{0, 4, 8}, {2, 4, 6}			 //diagonal wins
};
Rather than creating a condition for each possible win, we can use our winCombinations in conjunction with a loop like so:
Code:
for(int i=0; i<=7; i++){
	if( buttons[winCombinations[i][0]].getText().equals(buttons[winCombinations[i][1]].getText()) && 
		buttons[winCombinations[i][1]].getText().equals(buttons[winCombinations[i][2]].getText()) && 
		buttons[winCombinations[i][0]].getText() != ""){
		win = true;
	}
}
At this point I wasn't satisfied with how I determined who's turn it was. Although there is only a possibility of 4 turns and the code in version 1 works fine, I felt there was a better way to calculate it, and this is what I came up with
Code:
if(count % 2 == 0){
	letter = "O";
} else {
	letter = "X";
}
The % is the remainder operator, meaning if the count value is an even number, when divided by 2 the remainder is 0 which satisfies the first condition, if the number is odd the remainder is 1 causing the condition to branch to the else condition. Finally I came up with a better way to write the X's and O's to the button which looks like this:
Code:
 JButton pressedButton = (JButton)a.getSource(); 
 pressedButton.setText(letter);
 pressedButton.setEnabled(false);
So using a little lateral thinking and making full use of Java's capabilities (loops, arrays, ect...) you can change your code from 140 lines to 80 lines! Here is what my version 2 looks like

Code:
package mytictactoe;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class TicTacToeV2 implements ActionListener {
	/*Instance Variables*/
	private int[][] winCombinations = new int[][] {
			{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, //horizontal wins
			{0, 3, 6}, {1, 4, 7}, {2, 5, 8}, //virticle wins
			{0, 4, 8}, {2, 4, 6}			 //diagonal wins
		};
	private JFrame window = new JFrame("Tic-Tac-Toe");
	private JButton buttons[] = new JButton[9];
	private int count = 0;
	private String letter = "";
	private boolean win = false;

	public TicTacToeV2(){
	/*Create Window*/
	window.setSize(300,300);
	window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	window.setLayout(new GridLayout(3,3));
	
	/*Add Buttons To The Window*/
	for(int i=0; i<=8; i++){
		buttons[i] = new JButton();
		window.add(buttons[i]);
		buttons[i].addActionListener(this);
	}
	
	/*Make The Window Visible*/
	window.setVisible(true);
	}
	
	/**
	 When an object is clicked, perform an action.
	 @param a action event object
	 */
	public void actionPerformed(ActionEvent a) {
		count++;
		
		/*Calculate whose turn it is*/
		if(count % 2 == 0){
			letter = "O";
		} else {
			letter = "X";
		}

		/*Write the letter to the button and deactivate it*/
		 JButton pressedButton = (JButton)a.getSource(); 
		 pressedButton.setText(letter);
		 pressedButton.setEnabled(false);
		
		/*Determine who won*/
		for(int i=0; i<=7; i++){
			if( buttons[winCombinations[i][0]].getText().equals(buttons[winCombinations[i][1]].getText()) && 
				buttons[winCombinations[i][1]].getText().equals(buttons[winCombinations[i][2]].getText()) && 
				buttons[winCombinations[i][0]].getText() != ""){
				win = true;
			}
		}
		
		/*Show a dialog when game is over*/
		if(win == true){
			JOptionPane.showMessageDialog(null, letter + " wins the game!");
			System.exit(0);
		} else if(count == 9 && win == false){
			JOptionPane.showMessageDialog(null, "The game was tie!");
			System.exit(0);
		}		
	}
	
	public static void main(String[] args){
		TicTacToeV2 starter = new TicTacToeV2();
	}
}

Last edited by John; 01-20-2007 at 12:40 PM.
Reply With Quote