Search code examples
javaandroidnullpointerexceptiontic-tac-toe

I made a tictactoe game but it is crashing once I click on an empty space


I made a tictactoe game but it is crashing once I click on an empty space.

I used an Arraylist to change the state of the index when the corresponding place is clicked in the tictactoe grid. For example, if I ticked in the top right cell in the grid the index 2 will change to 1 if the current player is 'O' or to 2 if the current player is 'X'.

There is a counter to track who is playing, if the remainder is 0 then 'O' is places or else 'X' is placed.

Also,I used a flag 'gstate' to stop the game when one player wins.

The problem is that in the beginning the game works but when it comes to any part where I make the checking which player is the winner the game crashes.

May anyone please help me.

This is the Main Jave code

package com.example.tictactoe;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
    
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
    
public class MainActivity extends AppCompatActivity {

    public int counter = 0;
    Toast msg;
    ImageView img, img2, img3, img4, img5, img6, img7, img8, img9;


    int o = 1;
    int x = 2;

    List<Integer> winner = new ArrayList<>(9);

    boolean owin, xwin = false;
    boolean gstate = true;

    //oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO

    public void isOm() {
        if (counter % 2 != 0 && img5.getDrawable() != null) {
            winner.set(4, 1);
        } else {
        }
    }

    public void isOmr() {
        if (counter % 2 != 0 && img6.getDrawable() != null) {
            winner.set(5, 1);
        } else {
        }
    }

    public void isOml() {
        if (counter % 2 != 0 && img4.getDrawable() != null) {
            winner.set(3, 1);
        } else {
        }
    }

    public void isOru() {
        if (counter % 2 != 0 && img3.getDrawable() != null) {
            winner.set(2, 1);
        } else {
        }
    }

    public void isOmu() {
        if (counter % 2 != 0 && img2.getDrawable() != null) {
            winner.set(1, 1);
        } else {
        }
    }


    public void isOlu() {
        if (counter % 2 != 0 && img.getDrawable() != null) {
            winner.set(0, 1);
        } else {
        }
    }

    public void isOdr() {
        if (counter % 2 != 0 && img9.getDrawable() != null) {
            winner.set(8, 1);
        } else {
        }
    }

    public void isOmd() {
        if (counter % 2 != 0 && img8.getDrawable() != null) {
            winner.set(7, 1);
        } else {
        }
    }

    public void isOdl() {
        if (counter % 2 != 0 && img7.getDrawable() != null) {
            winner.set(6, 1);
        } else {
        }
    }

    //oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO

    //xXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxX

    public void isXm() {
        if (counter % 2 == 0 && img5.getDrawable() != null) {
            winner.set(4, 2);
        } else {
        }
    }

    public void isXmr() {
        if (counter % 2 == 0 && img6.getDrawable() != null) {
            winner.set(5, 2);
        } else {
        }
    }

    public void isXml() {
        if (counter % 2 == 0 && img4.getDrawable() != null) {
            winner.set(3, 2);
        } else {
        }
    }

    public void isXru() {
        if (counter % 2 == 0 && img3.getDrawable() != null) {
            winner.set(2, 2);
        } else {
        }
    }

    public void isXmu() {
        if (counter % 2 == 0 && img2.getDrawable() != null) {
            winner.set(1, 2);
        } else {
        }
    }

    public void isXlu() {
        if (counter % 2 == 0 && img.getDrawable() != null) {
            winner.set(0, 2);
        } else {
        }
    }

    public void isXdr() {
        if (counter % 2 == 0 && img9.getDrawable() != null) {
            winner.set(8, 2);
        } else {
        }
    }

    public void isXmd() {
        if (counter % 2 == 0 && img8.getDrawable() != null) {
            winner.set(7, 2);
        } else {
        }
    }

    public void isXdl() {
        if (counter % 2 == 0 && img7.getDrawable() != null) {
            winner.set(6, 2);
        } else {
        }
    }


    //xXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxX

    public boolean oWin() {
        try {
           if(((img.getDrawable() != null) && (img2.getDrawable() != null) && (img3.getDrawable() != null) && ((int)winner.get(0) == 1) && ((int)winner.get(1) == 1) && ((int)winner.get(2) == 1)) || ((img4.getDrawable() != null) && (img5.getDrawable() != null) && (img6.getDrawable() != null) && ((int)winner.get(3) == 1) && ((int)winner.get(4) == 1) && ((int)winner.get(5) == 1)) || ((img7.getDrawable() != null) && (img8.getDrawable() != null) && (img9.getDrawable() != null) && ((int)winner.get(6) == 1) && ((int)winner.get(7) == 1) && ((int)winner.get(8) == 1)) || ((img.getDrawable() != null) && (img4.getDrawable() != null) && (img7.getDrawable() != null) && ((int)winner.get(0) == 1) && ((int)winner.get(3) == 1) && ((int)winner.get(6) == 1)) || ((img2.getDrawable() != null) && (img5.getDrawable() != null) && (img8.getDrawable() != null) && ((int)winner.get(1) == 1) && ((int)winner.get(4) == 1) && ((int)winner.get(7) == 1)) || ((img3.getDrawable() != null) && (img6.getDrawable() != null) && (img9.getDrawable() != null) && ((int)winner.get(2) == 1) && ((int)winner.get(5) == 1) && ((int)winner.get(8) == 1)) || ((img.getDrawable() != null) && (img5.getDrawable() != null) && (img9.getDrawable() != null) && ((int)winner.get(0) == 1) && ((int)winner.get(4) == 1) && ((int)winner.get(8) == 1)) || ((img3.getDrawable() != null) && (img5.getDrawable() != null) && (img7.getDrawable() != null) && ((int)winner.get(2) == 1) && ((int)winner.get(4) == 1) && ((int)winner.get(6) == 1))){
                owin = true;
            }
            return owin;
        }
        catch(Exception e) {
            //Toast.makeText(this,"An image is not here",Toast.LENGTH_SHORT).show();
            return owin;
        }
    }

    public boolean xWin() {
        try {
            if (((img.getDrawable() != null) && (img2.getDrawable() != null) && (img3.getDrawable() != null) && ((int)winner.get(0) == 2) && ((int)winner.get(1) == 2) && ((int)winner.get(2) == 2)) || ((img4.getDrawable() != null) && (img5.getDrawable() != null) && (img6.getDrawable() != null) && ((int)winner.get(3) == 2) && ((int)winner.get(4) == 2) && ((int)winner.get(5) == 2)) || ((img7.getDrawable() != null) && (img8.getDrawable() != null) && (img9.getDrawable() != null) && ((int)winner.get(6) == 2) && ((int)winner.get(7) == 2) && ((int)winner.get(8) == 2)) || ((img.getDrawable() != null) && (img4.getDrawable() != null) && (img7.getDrawable() != null) && ((int)winner.get(0) == 2) && ((int)winner.get(3) == 2) && ((int)winner.get(6) == 2)) || ((img2.getDrawable() != null) && (img5.getDrawable() != null) && (img8.getDrawable() != null) && ((int)winner.get(1) == 2) && ((int)winner.get(4) == 2) && ((int)winner.get(7) == 2)) || ((img3.getDrawable() != null) && (img6.getDrawable() != null) && (img9.getDrawable() != null) && ((int)winner.get(2) == 2) && ((int)winner.get(5) == 2) && ((int)winner.get(8) == 2)) || ((img.getDrawable() != null) && (img5.getDrawable() != null) && (img9.getDrawable() != null) && ((int)winner.get(0) == 2) && ((int)winner.get(4) == 2) && ((int)winner.get(8) == 2)) || ((img3.getDrawable() != null) && (img5.getDrawable() != null) && (img7.getDrawable() != null) && ((int)winner.get(2) == 2) && ((int)winner.get(4) == 2) && ((int)winner.get(6) == 2))){
                xwin = true;
            }
            return xwin;
        }
        catch(Exception e) {
            //Toast.makeText(this,"An image is not here",Toast.LENGTH_SHORT).show();
            return xwin;
        }
    }

    public void greset(View view) {
        counter = 0;
        //img = (ImageView) findViewById(R.id.imageView);
        img.setImageResource(0);
        //img2 = (ImageView) findViewById(R.id.imageView2);
        img2.setImageResource(0);
        //img3 = (ImageView) findViewById(R.id.imageView3);
        img3.setImageResource(0);
        //img4 = (ImageView) findViewById(R.id.imageView4);
        img4.setImageResource(0);
        //img5 = (ImageView) findViewById(R.id.imageView5);
        img5.setImageResource(0);
        //img6 = (ImageView) findViewById(R.id.imageView6);
        img6.setImageResource(0);
        //img7 = (ImageView) findViewById(R.id.imageView7);
        img7.setImageResource(0);
        //img8 = (ImageView) findViewById(R.id.imageView8);
        img8.setImageResource(0);
        //img9 = (ImageView) findViewById(R.id.imageView9);
        img9.setImageResource(0);
        gstate = true;
    }

    public void pgame(View view) {
        ImageView image = (ImageView) view;

        img = (ImageView) findViewById(R.id.imageView);
        img2 = (ImageView) findViewById(R.id.imageView2);
        img3 = (ImageView) findViewById(R.id.imageView3);
        img4 = (ImageView) findViewById(R.id.imageView4);
        img5 = (ImageView) findViewById(R.id.imageView5);
        img6 = (ImageView) findViewById(R.id.imageView6);
        img7 = (ImageView) findViewById(R.id.imageView7);
        img8 = (ImageView) findViewById(R.id.imageView8);
        img9 = (ImageView) findViewById(R.id.imageView9);

        if (image.getDrawable() != null) {
            msg = Toast.makeText(this, "Please select another space", Toast.LENGTH_SHORT);
            msg.show();
            if((ImageView)view == img){
                winner.set(0, 1);
            }
            else if((ImageView)view == img2){
                winner.set(1, 1);
            }
            else if((ImageView)view == img3){
                winner.set(2, 1);
            }
            else if((ImageView)view == img4){
                winner.set(3, 1);
            }
            else if((ImageView)view == img5){
                winner.set(4, 1);
            }
            else if((ImageView)view == img6){
                winner.set(5, 1);
            }
            else if((ImageView)view == img7){
                winner.set(6, 1);
            }
            else if((ImageView)view == img8){
                winner.set(7, 1);
            }
            else if((ImageView)view == img9){
                winner.set(8, 1);
            }
            else if((ImageView)view == img){
                winner.set(0, 2);
            }
            else if((ImageView)view == img2){
                winner.set(1, 2);
            }
            else if((ImageView)view == img3){
                winner.set(2, 2);
            }
            else if((ImageView)view == img4){
                winner.set(3, 2);
            }
            else if((ImageView)view == img5){
                winner.set(4, 2);
            }
            else if((ImageView)view == img6){
                winner.set(5, 2);
            }
            else if((ImageView)view == img7){
                winner.set(6, 2);
            }
            else if((ImageView)view == img8){
                winner.set(7, 2);
            }
            else if((ImageView)view == img9){
                winner.set(8, 2);
            }

            if (counter > 5 && counter < 9){
                this.xWin();
                this.oWin();
            }

            if (owin) {
                msg = Toast.makeText(this, "\'O\' is the winner, press the reset button", Toast.LENGTH_SHORT);
                msg.show();
                xwin = false;
                gstate = false;
            }

            if (xwin) {
                msg = Toast.makeText(this, "\'X\' is the winner, press the reset button", Toast.LENGTH_SHORT);
                msg.show();
                xwin = false;
                gstate = false;
            }

        }

        if (image.getDrawable() == null) {
            if (counter % 2 == 0) {
                image.setImageResource(R.drawable.o);
                counter += 1;

            } else {
                image.setImageResource(R.drawable.x);
                counter += 1;

            }

            image.setTranslationY(-1500);
            image.animate().translationYBy(1500).setDuration(500);




        }


    }



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    }
}

The xml code is as following

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/cardview_light_background"
tools:context=".MainActivity">

<androidx.gridlayout.widget.GridLayout
    android:id="@+id/gridLayout"
    android:layout_width="420dp"
    android:layout_height="420dp"
    android:background="@drawable/grid"
    app:columnCount="3"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.555"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.733"
    app:rowCount="3">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="125dp"
        android:layout_height="125dp"
        android:onClick="pgame"
        app:layout_column="0"
        app:layout_row="0" />

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="125dp"
        android:layout_height="125dp"
        android:layout_marginLeft="22dp"
        android:onClick="pgame"
        app:layout_column="1"
        app:layout_row="0" />

    <ImageView
        android:id="@+id/imageView3"
        android:layout_width="125dp"
        android:layout_height="125dp"
        android:layout_marginLeft="18dp"
        android:onClick="pgame"
        app:layout_column="2"
        app:layout_row="0" />

    <ImageView
        android:id="@+id/imageView4"
        android:layout_width="125dp"
        android:layout_height="125dp"
        android:layout_marginTop="23dp"
        android:onClick="pgame"
        app:layout_column="0"
        app:layout_row="1" />

    <ImageView
        android:id="@+id/imageView5"
        android:layout_width="125dp"
        android:layout_height="125dp"
        android:layout_marginLeft="22dp"
        android:layout_marginTop="23dp"
        android:onClick="pgame"
        app:layout_column="1"
        app:layout_row="1" />

    <ImageView
        android:id="@+id/imageView6"
        android:layout_width="125dp"
        android:layout_height="125dp"
        android:layout_marginLeft="18dp"
        android:layout_marginTop="23dp"
        android:onClick="pgame"
        app:layout_column="2"
        app:layout_row="1" />

    <ImageView
        android:id="@+id/imageView7"
        android:layout_width="125dp"
        android:layout_height="125dp"
        android:layout_marginTop="23dp"
        android:onClick="pgame"
        app:layout_column="0"
        app:layout_row="2" />

    <ImageView
        android:id="@+id/imageView8"
        android:layout_width="125dp"
        android:layout_height="125dp"
        android:layout_marginLeft="22dp"
        android:layout_marginTop="23dp"
        android:onClick="pgame"
        app:layout_column="1"
        app:layout_row="2" />

    <ImageView
        android:id="@+id/imageView9"
        android:layout_width="125dp"
        android:layout_height="125dp"
        android:layout_marginLeft="18dp"
        android:layout_marginTop="23dp"
        android:onClick="pgame"
        app:layout_column="2"
        app:layout_row="2" />
</androidx.gridlayout.widget.GridLayout>

<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="90dp"
    android:layout_marginBottom="45dp"
    android:onClick="greset"
    android:text="Reset"
    app:layout_constraintBottom_toTopOf="@+id/gridLayout"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.498"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.0" />

</androidx.constraintlayout.widget.ConstraintLayout>

Solution

  • I copied your XML and Java code into a new project in Android Studio and replicated the error. It looks like you have not initialised your ArrayList winner properly, causing an IndexOutOfBoundsException when your code tries to replace values in the ArrayList.

    At the beginning of your code you have:

        List<Integer> winner = new ArrayList<>(9);
    

    However, the ArrayList is empty at this stage, and therefore when your pgame() method tries to call the set() method per example below, it fails:

        winner.set(0, 2); 
    

    Note that set() is a method to replace an existing value in an ArrayList, as I mentioned the ArrayList is empty so there is no value to be replaced.

    Add the following lines into the onCreate method to initialise the ArrayList by adding blank values (it's not elegant, but it should fix the problem):

        winner.add(0);
        winner.add(0);
        winner.add(0);
        winner.add(0);
        winner.add(0);
        winner.add(0);
        winner.add(0);
        winner.add(0);
        winner.add(0);