Subscribe to Martyr2's Programming Underground        RSS Feed
***** 1 Votes

A Beginner Tic-Tac-Toe Class for Java

Icon 1 Comments
Around this time each year we mentors on Dream.In.Code see a bunch of students and beginners, attempting to do there final programming projects, come on the boards asking for help with coding problems. Some even come on asking for ideas to help them out and a large majority want help with simple games they can do like connect four, "the snake game" or even Tic-Tac-Toe. Then each year we throw out some code to help them out and hope they come back to thank us later after the semester ends. So to help out this year I thought I would address a few students who were asking about the game of Tic-Tac-Toe and some code to get them started. Enjoy!

A Java Class for Tic-Tac-Toe

Each beginner who comes in and asks about this game tends to have a slight variation on the theme. Some need just a console app, some need to add a Graphical User Interface (GUI) and some need to add additional functionality (different characters, play online, more squares etc). To address all these variations I thought the best approach would be a simple Java Class where the programmer can take the class, tack on a GUI interface that calls the class' methods or integrate it directly into a console app. Heck perhaps to even part it out for the various functions... I don't mind.

The class code below is divided into three sections.

  • The first part is the board functions. These include initializing the board (which can be called to also reset the board state), printing a representation of the board state (so you can see what the game looks like at that point in time) and a check to see if the board is full (for detecting a draw scenario).

  • The second part is the win conditions. Here we have a simple function which will tell us if there is a win or not on the board. This function will call other functions to check the rows, the columns and the diagonals for a win condition. Each of these functions call a key function called "checkRowCol()" which is given the three values of a row/col and yes even a diagonal to see if they are a match.

  • The last part is the player functions. These control which player mark is active and where a user can place their mark on the board.


The Java Code

Below is the code, in its entirety, for you do do what you wish with it. It is in the public domain and can be used or modified as you see fit. But a reminder to students, do keep in mind that plagiarism can be frowned upon at school so learn what you can from this and try and make your own version. I would hate to see you guys get kicked out of class and blame me.

public class TicTacToe {

    private char[][] board; 
    private char currentPlayerMark;
			
    public TicTacToe() {
        board = new char[3][3];
        currentPlayerMark = 'x';
        initializeBoard();
    }
	
	
    // Set/Reset the board back to all empty values.
    public void initializeBoard() {
		
        // Loop through rows
        for (int i = 0; i < 3; i++) {
			
            // Loop through columns
            for (int j = 0; j < 3; j++) {
                board[i][j] = '-';
            }
        }
    }
	
	
    // Print the current board (may be replaced by GUI implementation later)
    public void printBoard() {
        System.out.println("-------------");
		
        for (int i = 0; i < 3; i++) {
            System.out.print("| ");
            for (int j = 0; j < 3; j++) {
                System.out.print(board[i][j] + " | ");
            }
            System.out.println();
            System.out.println("-------------");
        }
    }
	
	
    // Loop through all cells of the board and if one is found to be empty (contains char '-') then return false.
    // Otherwise the board is full.
    public boolean isBoardFull() {
        boolean isFull = true;
		
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (board[i][j] == '-') {
                    isFull = false;
                }
            }
        }
		
        return isFull;
    }
	
	
    // Returns true if there is a win, false otherwise.
    // This calls our other win check functions to check the entire board.
    public boolean checkForWin() {
        return (checkRowsForWin() || checkColumnsForWin() || checkDiagonalsForWin());
    }
	
	
    // Loop through rows and see if any are winners.
    private boolean checkRowsForWin() {
        for (int i = 0; i < 3; i++) {
            if (checkRowCol(board[i][0], board[i][1], board[i][1]) == true) {
                return true;
            }
        }
        return false;
    }
	
	
    // Loop through columns and see if any are winners.
    private boolean checkColumnsForWin() {
        for (int i = 0; i < 3; i++) {
            if (checkRowCol(board[0][i], board[1][i], board[2][i]) == true) {
                return true;
            }
        }
        return false;
    }
	
	
    // Check the two diagonals to see if either is a win. Return true if either wins.
    private boolean checkDiagonalsForWin() {
        return ((checkRowCol(board[0][0], board[1][1], board[2][2]) == true) || (checkRowCol(board[0][2], board[1][1], board[2][0]) == true));
    }
	
	
    // Check to see if all three values are the same (and not empty) indicating a win.
    private boolean checkRowCol(char c1, char c2, char c3) {
        return ((c1 != '-') && (c1 == c2) && (c2 == c3));
    }
	
	
    // Change player marks back and forth.
    public void changePlayer() {
        if (currentPlayerMark == 'x') {
            currentPlayerMark = 'o';
        }
        else {
            currentPlayerMark = 'x';
        }
    }
	
	
    // Places a mark at the cell specified by row and col with the mark of the current player.
    public boolean placeMark(int row, int col) {
		
        // Make sure that row and column are in bounds of the board.
        if ((row >= 0) && (row < 3)) {
            if ((col >= 0) && (col < 3)) {
                if (board[row][col] == '-') {
                    board[row][col] = currentPlayerMark;
                    return true;
                }
            }
        }
		
        return false;
    }
}



What I love about this style of game, and this class shown above, is that it has very defined and easily written tasks. For example, check a row, check a column, change the player's mark, is the board full etc. Because of this the code can be seen as being very modular and each method is short and easy to read. If you have trouble figuring out all the parts to it, just focus in on one method at a time and dissect it line by line.

Using The Class

Using this class is straight forward and very versatile. As you can see, many of the methods are declared as public and by calling them from a GUI or a console app you can control the game. Just creating an instance of the class will create the board and initialize it. Any time you want to restart the board, you can call the initialize method again. Below is an example of how you might create a pattern for the game mechanics...

// Create game and initialize it.
// First player will be 'x'
TicTacToe game = new TicTacToe();

// Player 'x' places a mark in the top right corner row 0, column 2
// These values are based on a zero index array, so you may need to simply take in a row 1 and subtract 1 from it if you want that.
game.placeMark(0,2);

// Lets print the board
game.printBoard();

// Did we have a winner?
if (game.checkForWin()) {
   System.out.println("We have a winner! Congrats!");
   System.exit(0);
}
else if (game.isBoardFull()) {
   System.out.println("Appears we have a draw!");
   System.exit(0);
}

// No winner or draw, switch players to 'o'
game.changePlayer();

// Repeat steps again for placing mark and checking game status...



As you can see from the code above, we can do many things with this class and implement any step in any order. We created a game, placed a mark for the player, checked win conditions, checked for a draw and changed player. If I have done my job right, you should be able to look at this class and say to yourself "Oh I could just tweak this and get another effect." You should be able to take this code straight into a GUI setup where starting your JFrame constructor would create and initialize this class and clicking a square would trigger the placeMark() method. A reset button might trigger the initalizeBoard() method and you could either use the printBoard() function or write your own to display the board in your GUI.

Conclusion

I hope that this code has helped all those students out there looking to build a simple game program. Or if you are just a hobbyist or beginner to Java and want to see how things fit together in a simple game scenario, a little class like this should do the trick.

If you are looking for more fun little projects like this and want to expand your mind, your skills in Java, or any other programming language, I encourage you to check out our ebook titled "The Programmers Idea Book 200 Software Project Ideas And Tips To Developing Them" which is available on The Coders Lexicon.

Thanks for reading and keep on coding! :)

1 Comments On This Entry

Page 1 of 1

andrewsw Icon

29 April 2014 - 12:22 PM
(Off-topic ish) Because there are only 8 possible win-lines I was speculating how difficult it would be to achieve this using matrix multiplication, but it is bit beyond my (current) maths knowledge. SO topic.

My thinking was to have a 3x3 matrix and one of 3x8, multiplication producing a 3x8 result-matrix. What should (could?) happen is that the multiplication fills in, effectively, eight columns where one column being filled with the same value denotes the win.

As the mult. is performed each individual column could be completed and checked at that time. If one is the win then the process could halt.

I wondered if it may even be possible to remove a column if it is completed without containing a win.

I wondered if it possible to go the other way; to just have a 3x8 matrix and then use this to produce the 3x3 visual, GUI, representation of the game-board.

Am I talking complete nonsense? Or perhaps it's possible but just too complex? Andy.
0
Page 1 of 1

August 2014

S M T W T F S
     12
3456789
10111213141516
171819 20 212223
24252627282930
31