Home » Programming » JAVA » How to Make a Tic Tac Toe Game in Android?

How to Make a Tic Tac Toe Game in Android?

In this article, we will be making a Tic Tac Toe Game Project using Java and XML in Android. The Tic Tac Toe Game is based on a two-player game. Each player chooses between X and O. Player play one move at a time simultaneously. In a move, a player can choose any position from a 3×3 grid. The goal here is to get three consecutive X or O in a horizontal, vertical, or diagonal direction. There will be a single activity in this application. This activity will show a 3×3 grid. The status of the game will be displayed at the bottom.

Step by Step Implementation

Step 1: Create a New Project

To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Java as the programming language.

Step 2: Before going to the coding section first you have to do some pre-task

Add these lines in themes.xml file: 

<style name="TableRow">
    <item name="android:layout_width">50dp</item>
    <item name="android:layout_height">70dp</item>
    <item name="android:background">@color/black</item>
    <item name="android:gravity">center_horizontal</item>
    <item name="android:clickable">true</item>
</style>

<style name="Cell">
    <item name="android:layout_width">80dp</item>
    <item name="android:layout_height">100dp</item>
    <item name="android:layout_gravity">center</item>
    <item name="android:gravity">center</item>
    <item name="android:textStyle">bold</item>
    <item name="android:textColor">@color/green</item>
    <item name="android:textSize">38dp</item>

    <item name="android:background">@color/white</item>
    <item name="android:maxWidth">100dp</item>
    <item name="android:text">"@string/none"</item>
    <item name="android:clickable">true</item>
</style>
<style parent="@style/Cell" name="LeftCell">
    <item name="android:layout_marginLeft">2dp</item>
    <item name="android:layout_marginTop">2dp</item>
    <item name="android:layout_marginRight">1dp</item>
    <item name="android:layout_marginBottom">2dp</item>
</style>
<style parent="@style/Cell" name="MiddleCell">
    <item name="android:layout_marginLeft">1dp</item>
    <item name="android:layout_marginTop">2dp</item>
    <item name="android:layout_marginRight">1dp</item>
    <item name="android:layout_marginBottom">2dp</item>
</style>
<style parent="@style/Cell" name="RightCell">
    <item name="android:layout_marginLeft">1dp</item>
    <item name="android:layout_marginTop">2dp</item>
    <item name="android:layout_marginRight">2dp</item>
    <item name="android:layout_marginBottom">2dp</item>
</style>

Add these lines in colors.xml file: 

<color name="maroon">#800000</color>
<color name="teal">#008080</color>
<color name="green">#008000</color>
<color name="blue">#0000FF</color>
<color name="navy">#000080</color>
<color name="black">#09534C</color>

Add these lines in strings.xml file: 

<string name="app_name">Tic Tac Toe</string>
<string name="size_of_board">3</string>
<string name="X">" X "</string>
<string name="O">" O "</string>
<string name="none">" "</string>

Create a dimens.xml file under values folder and add these lines in the dimens.xml file 

<dimen name="activity_horizontal_margin">16dp</dimen>

<dimen name="activity_vertical_margin">16dp</dimen>

Step 3: Working with the activity_main.xml file

The XML codes are used to build the structure of the activity as well as its styling part. It contains a TextViewat the very top of the activity to display the title. Then it contains an ImageView of the grid and in each box, there is an ImageView. At the bottom of the activity, there is a TextView to display the status of the game. Below is the code for the activity_main.xml file.

<?xml version="1.0"?>

<LinearLayout tools:context=".MainActivity"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:orientation="vertical"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android">


    <TableLayout
        android:id="@+id/mainBoard"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="top|center"
        android:clickable="true"
        android:gravity="center"
        android:layout_marginTop="55dp"
        android:nestedScrollingEnabled="false"
        android:padding="10dp">
        <TableRow
            android:id="@+id/row0"
            style="@style/TableRow"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                style="@style/LeftCell"
                android:width="80dp"
                android:layout_column="0"></TextView>

            <TextView
                style="@style/MiddleCell"
                android:width="80dp"
                android:layout_column="1"></TextView>

            <TextView
                style="@style/RightCell"
                android:width="80dp"
                android:layout_column="2"></TextView>

        </TableRow>

        <TableRow
            android:id="@+id/row1"
            style="@style/TableRow"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                style="@style/LeftCell"
                android:width="80dp"
                android:layout_column="0"></TextView>

            <TextView
                style="@style/MiddleCell"
                android:width="80dp"
                android:layout_column="1"></TextView>

            <TextView

                style="@style/RightCell"
                android:width="80dp"
                android:layout_column="2"
                ></TextView>

        </TableRow>

        <TableRow
            android:id="@+id/row2"
            style="@style/TableRow"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                style="@style/LeftCell"
                android:width="80dp"
                android:layout_column="0"></TextView>

            <TextView
                style="@style/MiddleCell"
                android:width="80dp"
                android:layout_column="1"></TextView>

            <TextView
                style="@style/RightCell"
                android:width="80dp"
                android:layout_column="2"></TextView>

        </TableRow>

    </TableLayout>

    <TextView android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        android:id="@+id/turn"
        android:padding="10dp"
        android:layout_marginTop="50dp"
        android:gravity="left"
        android:textColor="@color/black"
        android:fontFamily="sans-serif-medium"
        android:textSize="24dp"
        android:text="          Turn:  "/>

    <Button
        android:id="@+id/reset"
        android:layout_marginTop="30dp"
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="   Restart   " />

</LinearLayout>

Step 4: Working with the MainActivity.java file

We will create a two-dimensional array that will store all the winning positions. We will create a function that will run when a box inside the grid is clicked. Inside this function, we will first check if the box selected is empty or not. After that, we will set the image of X if the last move was of O or we will set the image of O if the last move was of X. Then we will check if the move has reached the move position and then reset the game. Below is the code for the MainActivity.java file. Comments are added inside the code to understand the code in more detail.

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {


    private int grid_size;
    TableLayout gameBoard;
    TextView txt_turn;
    char [][] my_board;
    char turn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        grid_size = Integer.parseInt(getString(R.string.size_of_board));
        my_board = new char [grid_size][grid_size];
        gameBoard = (TableLayout) findViewById(R.id.mainBoard);
        txt_turn = (TextView) findViewById(R.id.turn);

        resetBoard();
        txt_turn.setText("Turn: "+turn);

        for(int i = 0; i< gameBoard.getChildCount(); i++){
            TableRow row = (TableRow) gameBoard.getChildAt(i);
            for(int j = 0; j<row.getChildCount(); j++){
                TextView tv = (TextView) row.getChildAt(j);
                tv.setText(R.string.none);
                tv.setOnClickListener(Move(i, j, tv));
            }
        }

        Button reset_btn = (Button) findViewById(R.id.reset);
        reset_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent current = getIntent();
                finish();
                startActivity(current);
            }
        });
    }

    protected void resetBoard(){
        turn = 'X';
        for(int i = 0; i< grid_size; i++){
            for(int j = 0; j< grid_size; j++){
                my_board[i][j] = ' ';
            }
        }
    }

    protected int gameStatus(){

        //0 Continue
        //1 X Wins
        //2 O Wins
        //-1 Draw

        int rowX = 0, colX = 0, rowO = 0, colO = 0;
        for(int i = 0; i< grid_size; i++){
            if(check_Row_Equality(i,'X'))
                return 1;
            if(check_Column_Equality(i, 'X'))
                return 1;
            if(check_Row_Equality(i,'O'))
                return 2;
            if(check_Column_Equality(i,'O'))
                return 2;
            if(check_Diagonal('X'))
                return 1;
            if(check_Diagonal('O'))
                return 2;
        }

        boolean boardFull = true;
        for(int i = 0; i< grid_size; i++){
            for(int j = 0; j< grid_size; j++){
                if(my_board[i][j]==' ')
                    boardFull = false;
            }
        }
        if(boardFull)
            return -1;
        else return 0;
    }

    protected boolean check_Diagonal(char player){
        int count_Equal1 = 0,count_Equal2 = 0;
        for(int i = 0; i< grid_size; i++)
            if(my_board[i][i]==player)
                count_Equal1++;
        for(int i = 0; i< grid_size; i++)
            if(my_board[i][grid_size -1-i]==player)
                count_Equal2++;
        if(count_Equal1== grid_size || count_Equal2== grid_size)
            return true;
        else return false;
    }

    protected boolean check_Row_Equality(int r, char player){
        int count_Equal=0;
        for(int i = 0; i< grid_size; i++){
            if(my_board[r][i]==player)
                count_Equal++;
        }

        if(count_Equal== grid_size)
            return true;
        else
            return false;
    }

    protected boolean check_Column_Equality(int c, char player){
        int count_Equal=0;
        for(int i = 0; i< grid_size; i++){
            if(my_board[i][c]==player)
                count_Equal++;
        }

        if(count_Equal== grid_size)
            return true;
        else
            return false;
    }

    protected boolean Cell_Set(int r, int c){
        return !(my_board[r][c]==' ');
    }

    protected void stopMatch(){
        for(int i = 0; i< gameBoard.getChildCount(); i++){
            TableRow row = (TableRow) gameBoard.getChildAt(i);
            for(int j = 0; j<row.getChildCount(); j++){
                TextView tv = (TextView) row.getChildAt(j);
                tv.setOnClickListener(null);
            }
        }
    }

    View.OnClickListener Move(final int r, final int c, final TextView tv){

        return new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if(!Cell_Set(r,c)) {
                    my_board[r][c] = turn;
                    if (turn == 'X') {
                        tv.setText(R.string.X);
                        turn = 'O';
                    } else if (turn == 'O') {
                        tv.setText(R.string.O);
                        turn = 'X';
                    }
                    if (gameStatus() == 0) {
                        txt_turn.setText("Turn: Player " + turn);
                    }
                    else if(gameStatus() == -1){
                        txt_turn.setText("This is a Draw match");
                        stopMatch();
                    }
                    else{
                        txt_turn.setText(turn+" Loses!");
                        stopMatch();
                    }
                }
                else{
                    txt_turn.setText(txt_turn.getText()+"\nChoose an Empty Cell");
                }
            }
        };
    }
}

Output:

Leave a Reply

Your email address will not be published. Required fields are marked *