Tic Tac Toe Java game coding tutorial, How to make a simple tic tac toe in Java using 2D array? Creating algorithm, minimax java code tutorial.

Before diving into Tic Tac Toe Java Game coding, let’s understand how the game works!

Working of Tic Tac Toe Algorithm Java

Basically, there are two players and a grid of 3×3 squares. If the 1st player on his/her move marks a square with ‘x‘ then the other player marks his/her square with ‘o’. If any row/column/diagonal gets filled with x/o then the respective player wins.

Tic Tac Toe Java

O Wins! (Tic Tac Toe in Java)

For instance, in the above case, o wins.

How to make Tic Tac Toe in Java?

Using the power of Object-Oriented Programming in Java, we can make tic tac toe game in java easily.

Tic tac toe java coding using Array

First, we create a private inner class called Player.

Player contains sign (x/o), move (number of moves), moves[](an array containing the exact moves played by the Player: in order [x1, y1, x2, y2, …]).

Then, a parameterized constructor is used to define player sign and declares moves[] array with the proper size.

private static class Player{
		char sign;
		int move = 0;
		int moves[];
		public Player(char s, int size){
			sign = s;
			moves = new int[(size*size)+2];
		}
	}

Create a Tic Tac Toe  Board in Java

The generateBoard method declares a 2d array of size x size and returns it to the caller method.

static char[][] generateBoard(int size) {
		char board[][] = new char[size][size];
		for(int i =0; i<size; i++) {
			for(int j =0; j<size; j++) {
				board[i][j] = '.';
			}
		}
		return board;
	}

The very next method called printBoard takes the board as an input and prints it in the console.

static void printBoard(char board[][],int size) {
		for(int i =0; i<size; i++) {
			for(int j =0; j<size; j++) {
				System.out.print(" "+board[i][j]);
			}
			System.out.println();
		}
	}

The move method

The move method is called when a player makes a move. He/she enters the x and y co-ordinate of the board he/she wants to mark. At first, we shall check if the index is valid, i.e in range 0 to (board length -1). We shall also check if the index is previously occupied by the other player? [ board[y][x] != ‘.’ ]

tic tac toe java code using 2d array

Java 2D Array

Why board[y][x] and not board[x][y]? Well, our natural instincts favor the 2nd one but, do not forget how the 2D array works. It is basically an array of arrays. So the first index refers to one among multiple arrays whereas the 2nd index refers to an element in that array. In other words, the first index represents the row and the 2nd index represents the column.

If the condition fails, we throw a custom-made Invalid move exception and ask the Player to enter move again.

public class InvalidMoveException extends Exception{
	public InvalidMoveException(int size) {
		System.out.println("==================================");
		System.out.println("| 1. x and y co-ordinates should |");
		System.out.println("|    range from 0 to "+size+" !!        |");
		System.out.println("| 2. x and y co-ordinates are    |");
		System.out.println("|    already marked !!           |");
		System.out.println("==================================");
	}
}

Else if the condition is satisfied, We store the Player move in the moves[] array, increment the number of moves played(move) by one and update the board cell with the Player sign (x/o).

static void move(Player p, char board[][], int x, int y) throws InvalidMoveException {
		if(x<0 || y<0 || x >= board.length || y >= board.length || board[y][x] != '.') {
			throw new InvalidMoveException(board.length);
		}
		p.moves[2*p.move] = x;
		p.moves[2*p.move+1] = y;
		p.move+=1;
		board[y][x] = p.sign;
	}

A winner and draw method are created to print respective messages in the console.

static void winner(Player p) {
		System.out.println("****************");
		System.out.println("*    "+p.sign+" won!    *");
		System.out.println("****************");
	}
	static void draw() {
		System.out.println("****************");
		System.out.println("*  match draw! *");
		System.out.println("****************");
	}

The checkWinner method

The checkWinner method checks if the win condition is reached for any player. First, we determine whose move it is when the method is called? Since player1 plays first, if the number of moves played by player 1 is greater than player2 it means that the last move was played by player1. So we simply check if player1 has won the game? Vice versa for player2.

To check for the rows and columns we have used Maps X and Y. Map X contains the x co-ordinates of the player-move as the key and the number of times it has occurred in the board as value. Similarly, Map Y contains the y co-ordinates of the player move. The logic is that if any x or y co-ordinate has occurred for 3 times(for a board of 3×3). We declare the respective player as the winner. Then we check for the diagonals using the formulae for the line equation. We see that the diagonals have a slope of 1 or -1. So, using y = mx [m= 1/ -1], we create conditions for diagonal elements and check if all are containing the Player sign. As soon as we find both the diagonals do not satisfy the condition we break the loops.

At the same time, if a unique co-ordinate is entered for x and y, we store it in our defined Maps. Also if any of the diagonal reaches the win condition, we declare the respective play as the winner.

static void checkWinner(char board[][], Player p1, Player p2) {
		Player p;

		if(p1.move > p2.move)
			p = p1;
		else
			p = p2;
		
		//check row and columns
		Map<Integer, Integer> X = new HashMap<Integer, Integer>();
		Map<Integer, Integer> Y = new HashMap<Integer, Integer>();
		//System.out.println(p.moves.length);
		for(int i=0, j=1; j<(2*p.move); i+=2, j+=2) {
			//System.out.println(p.moves[i]+" "+p.moves[j]);
			
			if(X.containsKey(p.moves[i]) || Y.containsKey(p.moves[j])) {
				if(X.containsKey(p.moves[i])) {
					if(X.get(p.moves[i])+1 == board.length) {
						winner(p);
						System.exit(0);
					}
					X.put(p.moves[i], X.get(p.moves[i])+1);
				}
				if(Y.containsKey(p.moves[j])) {
					if(Y.get(p.moves[j])+1 == board.length) {
						winner(p);
						System.exit(0);
					}
					Y.put(p.moves[j], Y.get(p.moves[j])+1);
				}
			}
			else {
				X.put(p.moves[i], 1);
				Y.put(p.moves[j], 1);
			}
		}
		//check diagonals
		boolean d1 = true, d2 = true;
		
		for(int i = 0; i<board.length; i++) {
			for(int j=0; j<board.length; j++) {
				if(!d1 && !d2)
					break;
				if(i == j && d1) {
					if(!(board[i][j] == p.sign))
						d1 = false;	
				}
				if(i+j==(board.length-1) && d2) {
					if(!(board[i][j] == p.sign))
						d2 = false;	
				}
			}
			if(!d1 && !d2)
				break;
		}
		if(d1 || d2) {
			winner(p);
			System.exit(0);
		}
	}

The startGame method

First, we print a tip about how to enter moves.

Then we calculate the number of moves using the size of the board.

Using a while loop we alternatively ask Player1 and Player2 to enter their move. Using a try-catch block we handle invalid inputs and wrong inputs and display a suitable message.

Then we print the current status of the board and check if the win condition is satisfied. If the loop ends it simply means that all the moves have been played and a draw state is reached.

static void startGame(char board[][], Player p1, Player p2, int size) {
		System.out.println("==============================");
		System.out.println("| enter x and y co-ordinates |");
		System.out.println("| of your move. [ex- 0 0]    |");
		System.out.println("==============================");
		int n=1;
		int numberOfMoves = size*size;
		Scanner sc = new Scanner(System.in);
		while(numberOfMoves>0) {
			try {
			System.out.print("\nPlayer "+n+" move--> ");
			int x = sc.nextInt();
			int y = sc.nextInt();
			
				if(n == 1) {
					move(p1, board, x, y);
					n++;
				}
				else {
					move(p2, board, x, y);
					n--;
				}
				numberOfMoves--;
			}catch(InvalidMoveException e) {
				System.out.println("invalid move!");
			}
			catch(InputMismatchException e) {
				System.out.println("wrong input!");
				sc.next();
			}
			printBoard(board, size);
			checkWinner(board, p1, p2);
		}
		draw();
		sc.close();
	}

 

In the main method, we declare board size as 3. Create a board, declare 2 Players, and start playing the Game!

Tic tac toe Java Coding | Java Program

package game;

import java.util.HashMap;
import java.util.InputMismatchException;
import java.util.Map;
import java.util.Scanner;

public class TicTacToe {
	private static class Player{
		char sign;
		int move = 0;
		int moves[];
		public Player(char s, int size){
			sign = s;
			moves = new int[(size*size)+2];
		}
	}
	static char[][] generateBoard(int size) {
		char board[][] = new char[size][size];
		for(int i =0; i<size; i++) {
			for(int j =0; j<size; j++) {
				board[i][j] = '.';
			}
		}
		return board;
	}
	static void printBoard(char board[][],int size) {
		for(int i =0; i<size; i++) {
			for(int j =0; j<size; j++) {
				System.out.print(" "+board[i][j]);
			}
			System.out.println();
		}
	}
	static void move(Player p, char board[][], int x, int y) throws InvalidMoveException {
		if(x<0 || y<0 || x >= board.length || y >= board.length || board[y][x] != '.') {
			throw new InvalidMoveException(board.length);
		}
		p.moves[2*p.move] = x;
		p.moves[2*p.move+1] = y;
		p.move+=1;
		board[y][x] = p.sign;
	}
	static void winner(Player p) {
		System.out.println("****************");
		System.out.println("*    "+p.sign+" won!    *");
		System.out.println("****************");
	}
	static void draw() {
		System.out.println("****************");
		System.out.println("*  match draw! *");
		System.out.println("****************");
	}
	static void checkWinner(char board[][], Player p1, Player p2) {
		Player p;

		if(p1.move > p2.move)
			p = p1;
		else
			p = p2;
		
		//check row and columns
		Map<Integer, Integer> X = new HashMap<Integer, Integer>();
		Map<Integer, Integer> Y = new HashMap<Integer, Integer>();
		//System.out.println(p.moves.length);
		for(int i=0, j=1; j<(2*p.move); i+=2, j+=2) {
			//System.out.println(p.moves[i]+" "+p.moves[j]);
			
			if(X.containsKey(p.moves[i]) || Y.containsKey(p.moves[j])) {
				if(X.containsKey(p.moves[i])) {
					if(X.get(p.moves[i])+1 == board.length) {
						winner(p);
						System.exit(0);
					}
					X.put(p.moves[i], X.get(p.moves[i])+1);
				}
				if(Y.containsKey(p.moves[j])) {
					if(Y.get(p.moves[j])+1 == board.length) {
						winner(p);
						System.exit(0);
					}
					Y.put(p.moves[j], Y.get(p.moves[j])+1);
				}
			}
			else {
				X.put(p.moves[i], 1);
				Y.put(p.moves[j], 1);
			}
		}
		//check diagonals
		boolean d1 = true, d2 = true;
		
		for(int i = 0; i<board.length; i++) {
			for(int j=0; j<board.length; j++) { if(!d1 && !d2) break; if(i == j && d1) { if(!(board[i][j] == p.sign)) d1 = false; } if(i+j==(board.length-1) && d2) { if(!(board[i][j] == p.sign)) d2 = false; } } if(!d1 && !d2) break; } if(d1 || d2) { winner(p); System.exit(0); } } static void startGame(char board[][], Player p1, Player p2, int size) { System.out.println("=============================="); System.out.println("| enter x and y co-ordinates |"); System.out.println("| of your move. [ex- 0 0] |"); System.out.println("=============================="); int n=1; int numberOfMoves = size*size; Scanner sc = new Scanner(System.in); while(numberOfMoves>0) {
			try {
			System.out.print("\nPlayer "+n+" move--> ");
			int x = sc.nextInt();
			int y = sc.nextInt();
			
				if(n == 1) {
					move(p1, board, x, y);
					n++;
				}
				else {
					move(p2, board, x, y);
					n--;
				}
				numberOfMoves--;
			}catch(InvalidMoveException e) {
				System.out.println("invalid move!");
			}
			catch(InputMismatchException e) {
				System.out.println("wrong input!");
				sc.next();
			}
			printBoard(board, size);
			checkWinner(board, p1, p2);
		}
		draw();
		sc.close();
	}
	public static void main(String[] args) {
		int size = 3;
		char board[][] = generateBoard(size);
		Player p1 = new Player('x',size);
		Player p2 = new Player('o',size);
		startGame(board, p1, p2, size);
	}
}

OUTPUT

Finally, we are done with the java game. For any Java programming help, you can reach us out. Feel free to share the article.