Thursday, November 17, 2011

How to Create a Tic-Tac-Toe Game in Java

Introduction

Tic Tac ToeAt some point in your life you may have heard of things like source codes and programming languages. If not, at least I hope you ever thought of how video games are created. For one thing, I am going to show you how to create the popular scribbles game Tic-Tac-Toe using Java. By the end of this tutorial I am hoping I have inspired some of you to experiment with programming languages and create your own fun games. Learning programming languages like Java is easy. All you need is a little bit of creativity and a good understanding of logic.

You can download a playable version of the game, although you must have Java installed in your computer.

 

Objectives and Disclaimer

Before we proceed to coding the game itself, let me show you first the objectives.

  • Learn how to code in Java. (Duh!)
  • Build a program using a graphical user interface (or GUI)

That's basically it. This tutorial however is not extensive. I will not bother explaining all the jargons as they can be sometimes overwhelming for many people, even for me. You will need to refer to other books and references if you want to advance in Java. And based on my experience, programming is a practical art. Obviously, lots of practice is needed to become a coding master.

By the end of this tutorial, I expect that you can create a program similar to the one in the video below.

Tic-Tac-Toe Video

Software Requirements

Many guides found elsewhere will tell you to begin with a Notepad or another simple text editor when you begin your first coding. Since I want to keep things concise, I am going ahead and tell you to download the application Eclipse. It is an integrated development environment. Or to simply put it, it can help you code Java faster than a text editor can.

Just go to the Eclipse download link and select Eclipse IDE for Java Developers. Be sure to download the version that is compatible to your operating system.

You must also download the Java Development Kit (JDK). It contains the compiler, which is like a translator that converts your code into something understandable to the computer. You can download any of the JDK links, although the standard version is all we need. Like for Eclipse, choose the right download as per your operating system.

Note: You cannot proceed to coding itself without these two, so you need to download them.

When downloading is finished, you need to install JDK, whereas the Eclipse download is a ZIP file that you need to extract. When you have finished extracting, go to the eclipse folder and run eclipse.exe.

Hello World!

When running Eclipse for the first time, it will prompt you to select a location for your workspace, or where the code files will be stored.

When your done selecting a location, you can finally start learning Java!

  1. To begin with, click File menu, click New, and click Java Project.
  2. A New Java Project dialog box will appear. Type in a project name and press OK.
  3. Your project will appear at the Package Explorer pane (located to the left by default).
  4. Right click on your project, select New, select Class.
  5. A New Java Class dialog box will appear. Type main in the Name text-field and press OK.
  6. The class will be automatically opened for you at the Editor window (the big white portion at the middle).
  7. Let's create a program with the most basic code there is. The Hello World!
  8. Modify whatever is in the Editor window so that it looks like the code below.
  9. Finally, click Run - the little green arrow at the top-left - and prepare to be amazed
public class main {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}



Hello Word OutputIf you're wondering what is supposed to happen, there's a Hello World!sentence that appears at the console window (the one below the editor window). If you know how to compile it using javac the output will be like the photo to the right.

Here's a short explanation to the code above. Every class starts with similar to line 1; it begins with a declaration of the class and anything inside it is contained within curly brackets. Line 2 contains the main function, where execution of the program starts. Line 3 contains the printlnmethod which means "print line" that displays an output contained within the double quotation marks.

Now that you got a taste of what's coming. I won't delay any further. Let's proceed to coding Tic-Tac-Toe!

Tic-Tac-Toe


Posted below are all the codes needed for the game Tic-Tac-Toe. In programming, there are possibly limitless ways to arrive at one point (or how you want a program to behave). Hence, I am not hesitating to tell you that my code may not be the best there is. Nonetheless I will try my best to explain my code bit by bit. If you see any double slashes in the code these are called comments which can be used to leave explanations for other programmers so they can easily understand the code.

There are five classes in the code. You will need to create them in Eclipse with the exact class names I used. If you don't know how to create a class, please refer to the Hello World section above.

Once you've copied and pasted the code to Eclipse, switch to the main class and hit the Run (green arrow) button, and voila! You now have a Tic-Tac-Toe game up and running!

Note: You can also download this JAR file which you will import to Eclipse.

main Class

public class main {
// any Java code will not run with the main method
public static void main(String[] args) {
// class main calls for another class, gui
gui g = new gui();
// within gui class g is launchFrame,
// used to launch a graphical user interface
g.launchFrame();
}
}

gui Class

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

public class gui {
// declaration of variables below

// a frame is a window with minimize, restore, and close buttons
private JFrame f;
// a panel is like a mini-frame used for layout
private JPanel p1, p2;
// buttons are for clicking! :)
// one has [] beside the name, making it an array, or a group of buttons
private JButton newB, quitB, b[];
// boolean values can either be true or false
// isXturn determines player's turn (X for true, O for false)
// isGameFinished determines whether the game is over
// isAITurn is used for playing against the computer
private boolean isXturn, isGameFinished, isAITurn;
// int have integer values
private int numberOfBoxesLeft, playerMode;
// myAction is another class which defines the behavior
// of the buttons when clicked
private myAction action;

// instantiation of the variables declared above
public gui() {
// defines the frame's title bar name
f = new JFrame("Tic-Tac-Toe");

p1 = new JPanel();
p2 = new JPanel();

// defines the names of the buttons
newB = new JButton("New");
quitB = new JButton("Quit");

// instantiates 10 buttons within the array b[]
b = new JButton[10];
for (int i = 0; i < 10; i++) {
// these buttons will be marked as X or O during play
// hence, their names are left blank using ""
b[i] = new JButton("");
}

// by default, X is first to play
isXturn = true;
isGameFinished = false;
numberOfBoxesLeft = 9;
}

public void launchFrame() {

// instantiate the actions for the buttons, etc.
action = new myAction(this);

// layout, defining how the GUI should appear
f.setLayout(new BorderLayout());
f.add(p1, BorderLayout.CENTER);
f.add(p2, BorderLayout.SOUTH);

// defining 3 row, 3 column layout of buttons
p1.setLayout(new GridLayout(3, 3));
for (int i = 1; i < 10; i++) {
p1.add(b[i]);
// adding action to the buttons
b[i].addActionListener(action);
// buttons are disabled first, will need to select game mode
b[i].setEnabled(false);
}

// second panel contains New game, Quit game, and game status
p2.setLayout(new FlowLayout());
p2.add(newB);
p2.add(b[0]);
p2.add(quitB);

// b[0] is an unclickable button
// that merely shows whose turn it is
b[0].setText("X Turn");
b[0].setEnabled(false);

// size of the frame window
f.setSize(280, 350);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// adding action to new and quit buttons
newB.addActionListener(action);
quitB.addActionListener(action);
}

// the following are methods to get values of the variables above
// when using them outside this class
// some methods are also setters, which replaces values of variables
// that must be done outside this class
public JButton getButton(int i) {
return b[i];
}

public JButton[] getButtonA() {
return b;
}

public boolean getXTurn() {
return isXturn;
}

public void setXTurn(boolean i) {
isXturn = i;
}

public boolean getComplete() {
return isGameFinished;
}

public void setComplete(boolean i) {
isGameFinished = i;
}

public int getLeftBoxes() {
return numberOfBoxesLeft;
}

public void setLeftBoxes(int i) {
numberOfBoxesLeft = i;
}

public void reduceLeftBoxes() {
numberOfBoxesLeft--;
}

public int getPlayerMode() {
return playerMode;
}

public void setPlayerMode(int i) {
playerMode = i;
}

public boolean getIsAITurn() {
return isAITurn;
}

public void setIsAITurn(boolean turn) {
isAITurn = turn;
}
}

myAction class

import java.awt.event.*;

public class myAction implements ActionListener {
// this class defines the behavior of the buttons made in
// the gui class, hence, the latter class must be declared
// in order to gain access to those buttons
private gui myGUI;

public myAction(gui getLogGUI) {
// intantiates myGUI with the values of gui
myGUI = getLogGUI;
}

public void actionPerformed(ActionEvent e) {

result a = new result(myGUI.getComplete(), myGUI.getButtonA());
pcMove b = new pcMove();

// action for quit button
if (e.getActionCommand() == "Quit") {
System.exit(0);

// action for new button
} else if (e.getActionCommand() == "New") {
// selecting player mode
myGUI.setPlayerMode(a.selectMode());
// does nothing if cancel is chosen
// in selecting modes
if (myGUI.getPlayerMode() < 2) {
for (int i = 1; i < 10; i++) {
myGUI.getButton(i).setText("");
myGUI.getButton(i).setEnabled(true);

}
myGUI.setComplete(false);
myGUI.setLeftBoxes(9);
// playerMode 0 is playing against AI
if (myGUI.getPlayerMode() == 0) {
myGUI.setIsAITurn(b.ifCPUMovesFirst());

// if true, AI selects first cell
if (myGUI.getIsAITurn()) {
int m = b.moveAI();
// computer is always O, player is X
myGUI.getButton(m).setText("O");
myGUI.getButton(m).setEnabled(false);
myGUI.reduceLeftBoxes();

}
}
}

// action for the other buttons (the ones to mark with X or O)
} else {
myGUI.reduceLeftBoxes(); // if one cell is clicked, then one less
// remaining un-clicked cells

if (myGUI.getPlayerMode() == 0) { // 1 player mode
for (int i = 1; i < 10; i++) { // player's move
if (e.getSource().equals(myGUI.getButton(i))) {
myGUI.getButton(i).setText("X");
myGUI.getButton(i).setEnabled(false);
myGUI.setXTurn(false);
}
}
myGUI.setComplete(a.preWin()); // AI won't move when player
// wins even if some cells are
// still available
// AI response
if (myGUI.getLeftBoxes() != 0 && myGUI.getComplete() == false) {
int m;
for (;;) {
m = b.moveAI();
if (myGUI.getButton(m).getText().equals("")) {
break;
}
}
myGUI.getButton(m).setText("O");
myGUI.getButton(m).setEnabled(false);
myGUI.reduceLeftBoxes();
}

} else if (myGUI.getPlayerMode() == 1) { // 2 player mode
for (int i = 1; i < 10; i++) {

if (e.getSource().equals(myGUI.getButton(i))) {
if (myGUI.getXTurn()) {
myGUI.getButton(i).setText("X");
myGUI.getButton(i).setEnabled(false);
myGUI.getButton(0).setText("O Turn");
myGUI.setXTurn(false);
} else if (myGUI.getXTurn() == false) {
myGUI.getButton(i).setText("O");
myGUI.getButton(i).setEnabled(false);
myGUI.setXTurn(true);
myGUI.getButton(0).setText("X Turn");
}
}
}
}

myGUI.setComplete(a.preWin()); // checking for win

if (myGUI.getLeftBoxes() == 0 && myGUI.getComplete() == false) { // conditions
// for draw
a.declareDraw();
}
}

}

}





pcMove Class

import javax.swing.*;

public class pcMove {
private boolean cpuMovesFirst;

// the AI behavior is merely a random selection of a cell/box to mark
public int moveAI() {
int a;
for (;;) {
a = (int) (Math.random() * 10);
if (a > 0 && a < 10) {
break;
}
}
return a;
}

// called when the AI is the first to move.
// this is just the same as the method above
public boolean ifCPUMovesFirst() {
int a = (int) (Math.random() * 10);
if (a % 2 == 0) {
cpuMovesFirst = true;
} else {
cpuMovesFirst = false;
}
return cpuMovesFirst;
}
}




result Class

import javax.swing.*;

// this class contains the check if the game is over
public class result {
private boolean resultGameFinished;
private JButton resultB[];

public result(boolean getIsGameFinished, JButton getB[]) {
resultB = getB;
resultGameFinished = getIsGameFinished;
}

public boolean preWin() {
for (int i = 1; i <= 7; i++) {
if (resultGameFinished == false) {
if (i == 1) {
// checking for diagonal win
checkWin(i, i + 4, i + 8);
}
if (i <= 3) {
// checking for column win
checkWin(i, i + 3, i + 6);
}
if (i == 1 || i == 4 || i == 7) {
// checking for row win
checkWin(i, i + 1, i + 2);
}
if (i == 3) {
// checking for inverse diagonal win
checkWin(i, i + 2, i + 4);
}
}
}
return resultGameFinished;
}

public void checkWin(int x, int y, int z) {
// checking if X wins
if (resultB[x].getText().equals("X")) {
if (resultB[y].getText().equals("X")) {
if (resultB[z].getText().equals("X")) {
declareResult("X");
}
}
}
// checking if O wins
if (resultB[x].getText().equals("O")) {
if (resultB[y].getText().equals("O")) {
if (resultB[z].getText().equals("O")) {
declareResult("O");
}
}
}
}

public void declareResult(String i) {
if (resultGameFinished == false) {
JOptionPane.showMessageDialog(null, i + " wins!");
for (int j = 1; j < 10; j++) {
resultB[j].setEnabled(false);
}
resultGameFinished = true;
}
}

// when game is draw
public void declareDraw() {
JOptionPane.showMessageDialog(null, "Draw!");
resultGameFinished = true;
}

// mode selection: against AI, another human, or cancel
public int selectMode() {
Object[] options = { "Play with Computer", "Player with Another Human",
"Cancel" };
int n = JOptionPane.showOptionDialog(null,
"Please select a game mode:", "Game Mode",
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.INFORMATION_MESSAGE, null, options, options[2]);
return n;
}
}