//import everything:
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.applet.AudioClip;
import java.net.*;
//the class with the JFrame and the ActionListner:
public class TicTacToe extends JFrame implements ActionListener
{
//this is an array of the buttons (spots). We use an array, not
//an arrayList because the number of buttons is constant; it does
//not change.
JButton spots[] = new JButton[9];
//this will keep track of turns
int turn = 1;
//this is a JLabel: it will display the text
JLabel lbl = new JLabel(new ImageIcon("title.png"));
//this JLabel will display whose turn it is
JLabel turnLbl = new JLabel("X's Turn");
ImageIcon red = new ImageIcon("red.png");
ImageIcon blue = new ImageIcon("blue.png");
ImageIcon blank = new ImageIcon("blank.png");
ImageIcon loseImg = new ImageIcon("lose.png");
ImageIcon winImg = new ImageIcon("win.png");
ImageIcon drawImg = new ImageIcon("draw.png");
JLabel lose = new JLabel(loseImg);
JLabel win = new JLabel(winImg);
JLabel draw = new JLabel(drawImg);
URL hitURL = null, cheerURL = null, booURL = null;
AudioClip hit = null, cheer = null, boo = null;
//the constructor
public TicTacToe()
{
super("TicTacToe: Boxing Style");
setSize(450,700);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//this will hold the buttons:
Container container = getContentPane();
//this will tell the computer how to display the buttons:
container.setLayout(null);
//we will add the winning, losing, and draw labels, butt
//move them off the screen.
container.add(lose);
lose.setBounds(-500,-500,331,438);
container.add(win);
lose.setBounds(-500,-500,331,438);
container.add(draw);
lose.setBounds(-500,-500,331,438);
//add the lbl:
container.add(lbl);
lbl.setBounds(20,0,400,288);
try
{
hitURL = this.getClass().getResource("hit.wav");
booURL = this.getClass().getResource("boo.wav");
cheerURL = this.getClass().getResource("cheer.wav");
hit = JApplet.newAudioClip(hitURL);
boo = JApplet.newAudioClip(booURL);
cheer = JApplet.newAudioClip(cheerURL);
}
catch(Exception e){}
//before we can add the buttons to the container, we must
//initialize them. Use a for loop to do it:
int newLine = 0;
int lineCount = 0;
for(int i = 0; i < spots.length; i++)
{
//initialize it with a blank image
spots[i] = new JButton(blank);
//this checks whether to use a new row
if(i==3 || i ==6)
{
newLine++;
lineCount = 0;
}
//set the position of the button
spots[i].setBounds(75+(lineCount*100),300+(newLine*100),100,100);
//add it to the container
container.add(spots[i]);
//and now add the action listener:
spots[i].addActionListener(this);
lineCount++;
}
//add the JLabel that describes the turn
container.add(turnLbl);
turnLbl.setBounds(200,630,100,30);
container.setComponentZOrder(lose,0);
container.setComponentZOrder(win,0);
container.setComponentZOrder(draw,0);
}
public void reset()
{
for(int i = 0; i < spots.length; i++)
{
spots[i].setIcon(blank);
spots[i].addActionListener(this);
}
turn = 1;
}
//the mandatory method:
public void actionPerformed(ActionEvent e)
{
hit.play();
try
{
Thread.sleep(600);
}
catch(Exception excep){}
//this will check the button pressed:
for(int i = 0; i < spots.length; i++)
{
if(e.getSource()==spots[i])
{
//set the button to X
spots[i].setIcon(red);
//now, change the JLabel that describes the player's turn
turnLbl.setText("X's (Red's) Turn");
//disable the btn so it can't be re-pressed
spots[i].removeActionListener(this);
}
}
turn++;
//before letting the other player go, check whether a player won:
checkWin();
//this method lets the computer select its turn
ai();
}
public void ai()
{
boolean movedYet;
//if this is the computer's first turn, then try to go in the top left
//if already taken, take the middle
if(turn == 2)
{
//if the top left is taken, take the middle
if(spots[0].getIcon().equals(red))
{
spots[4] .setIcon(blue);
spots[4].removeActionListener(this);
movedYet = true;
}
//else, take the top left
else
{
spots[0] .setIcon(blue);
spots[0].removeActionListener(this);
movedYet = true;
}
}
//if this is not the first turn, then check for 2 out of 3 spots
//taken. If there are none, go to a random location
else
{
//callin this method checks for two in a row of the first String passed in.
//It then takes the 3rd spot with the 2nd String passed in:
movedYet = twoInARow(blue);
//if the computer didn't take an offensive spot, take a defensive
//one.
if(!movedYet)
{
movedYet = twoInARow(red);
//if there is no defensive move, take the next open one.
if(!movedYet)
{
//this loop finds the first untaken spot:
for(int i = 0; i < spots.length; i++)
{
//if empty, take it!
if(spots[i].getIcon().equals(blank))
{
spots[i] .setIcon(blue);
spots[i].removeActionListener(this);
movedYet = true;
break;
}
}
}
}
}
turn++;
System.out.println(turn);
checkWin();
if(!movedYet)
{
//if no spot was taken, it must be a cat's game:
draw.setBounds(50,50,331,438);
reset();
}
}
public boolean twoInARow(Icon a)
{
for(int i = 0; i < 3; i++)
{
//this checks for 2 in a row from the top
if(spots[i].getIcon().equals(a) &&
spots[i+3].getIcon().equals(a) &&
spots[i+6].getIcon().equals(blank))
{
spots[i+6].setIcon(blue);
spots[i+6].removeActionListener(this);
return true;
}
//this checks (from the top and bottom)
//for a taken spot, then a gap, then a taken one:
if(spots[i].getIcon().equals(a) &&
spots[i+6].getIcon().equals(a) &&
spots[i+3].getIcon().equals(blank))
{
spots[i+3].setIcon(blue);
spots[i+3].removeActionListener(this);
return true;
}
//this checks for 2 in a row from the bottom
if(spots[i+6].getIcon().equals(a) &&
spots[i+3].getIcon().equals(a) &&
spots[i].getIcon().equals(blank))
{
spots[i] .setIcon(blue);
spots[i].removeActionListener(this);
return true;
}
//this checks for 2 in a row from the left
if(spots[i*3].getIcon().equals(a) &&
spots[(i*3)+1].getIcon().equals(a) &&
spots[(i*3)+2].getIcon().equals(blank))
{
spots[(i*3)+2] .setIcon(blue);
spots[(i*3)+2].removeActionListener(this);
return true;
}
//this checks (from the left and right)
//for a taken spot, then a gap, then a taken one
if(spots[i*3].getIcon().equals(a) &&
spots[(i*3)+2].getIcon().equals(a) &&
spots[(i*3)+1].getIcon().equals(blank))
{
spots[(i*3)+1] .setIcon(blue);
spots[(i*3)+1].removeActionListener(this);
return true;
}
//this checks for 2 in a row from the right
if(spots[(i*3)+2].getIcon().equals(a) &&
spots[(i*3)+1].getIcon().equals(a) &&
spots[i*3].getIcon().equals(blank))
{
spots[i*3] .setIcon(blue);
spots[i*3].removeActionListener(this);
return true;
}
//now we will check for a diagnol 2 in a row:
for(int j = 0; j <= 2; j+=2)
{
//this will check for diagnol X wins
if(spots[j].getIcon()==a &&
spots[4].getIcon()==a &&
spots[8-j].getIcon().equals(blank))
{
spots[8-j] .setIcon(blue);
spots[8-j].removeActionListener(this);
return true;
}
//this checks (from a diagnol)
//for a taken spot, then a gap, then a taken one
if(spots[j].getIcon()==a &&
spots[8-j].getIcon()==a &&
spots[4].getIcon().equals(blank))
{
spots[4] .setIcon(blue);
spots[4].removeActionListener(this);
return true;
}
if(spots[8-j].getIcon()==a &&
spots[4].getIcon()==a &&
spots[j].getIcon().equals(blank))
{
spots[j] .setIcon(blue);
spots[j].removeActionListener(this);
return true;
}
}
}
return false;
}
public void checkWin()
{
//first, we will use to go through three iterations. This allows us to
//check for both horizontal and vertical wins without using too
//much code:
for(int i = 0; i < 3; i++)
{
//this checks for a vertical X win
if(spots[i].getIcon().equals(red) &&
spots[i+3].getIcon().equals(red) &&
spots[i+6].getIcon().equals(red))
{
cheer.play();
try
{
Thread.sleep(600);
}
catch(Exception excep){}
win.setBounds(50,50,331,438);
reset();
return;
}
//this checks for a vertical O win
if(spots[i].getIcon().equals(blue) &&
spots[i+3].getIcon().equals(blue) &&
spots[i+6].getIcon().equals(blue))
{
boo.play();
try
{
Thread.sleep(600);
}
catch(Exception excep){}
lose.setBounds(50,50,331,438);;
reset();
return;
}
//this checks for a horizontal X win
if(spots[i*3].getIcon().equals(red) &&
spots[(i*3)+1].getIcon().equals(red) &&
spots[(i*3)+2].getIcon().equals(red))
{
cheer.play();
try
{
Thread.sleep(600);
}
catch(Exception excep){}
win.setBounds(50,50,331,438);
reset();
return;
}
//this checks for a horizontal O win
if(spots[i*3].getIcon().equals(blue) &&
spots[(i*3)+1].getIcon().equals(blue) &&
spots[(i*3)+2].getIcon().equals(blue))
{
boo.play();
try
{
Thread.sleep(600);
}
catch(Exception excep){}
lose.setBounds(50,50,331,438);;
reset();
return;
}
}
//now, this loop will check for diagnol wins
for(int i = 0; i <= 2; i+=2)
{
//this will check for diagnol X wins
if(spots[i].getIcon().equals(red) &&
spots[4].getIcon().equals(red) &&
spots[8-i].getIcon().equals(red))
{
cheer.play();
try
{
Thread.sleep(600);
}
catch(Exception excep){}
win.setBounds(50,50,331,438);
reset();
return;
}
//this will check for diagnol O wins
if(spots[i].getIcon().equals(blue) &&
spots[4].getIcon().equals(blue) &&
spots[8-i].getIcon().equals(blue))
{
boo.play();
try
{
Thread.sleep(600);
}
catch(Exception excep){}
lose.setBounds(50,50,331,438);;
reset();
return;
}
}
}
//starter (main) method:
public static void main(String[] args) {
TicTacToe ttt = new TicTacToe();
}
}