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.
See our other article, How to Make a Tic Tac Toe Game in Android using Kotlin
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>
Attach 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 TextView at 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:
That’s a very good content