NullReferenceException in a total weird Space (Checkers AI)

Good Evening, i´m currently working on a Checkers Board Game (Specifically on the AI)

NullReferenceException: Object reference not set to an instance of an object
AI2.GetMoves () (at Assets/NewAI/AI2.cs:224)
AI2.minimax (Int32 depth, Int32 turn) (at Assets/NewAI/AI2.cs:123)
AI2.minimax (Int32 depth, Int32 turn) (at Assets/NewAI/AI2.cs:142)
AI2.minimax (Int32 depth, Int32 turn) (at Assets/NewAI/AI2.cs:158)
AI2.minimax (Int32 depth, Int32 turn) (at Assets/NewAI/AI2.cs:142)
AI2.minimax (Int32 depth, Int32 turn) (at Assets/NewAI/AI2.cs:158)
AI2.minimax (Int32 depth, Int32 turn) (at Assets/NewAI/AI2.cs:142)
AI2.minimax (Int32 depth, Int32 turn) (at Assets/NewAI/AI2.cs:158)
AI2.minimax (Int32 depth, Int32 turn) (at Assets/NewAI/AI2.cs:142)
AI2.callMiniMax (Int32 depth, Int32 turn) (at Assets/NewAI/AI2.cs:112)
AI2.AIMove () (at Assets/NewAI/AI2.cs:40)

So this is the Full Error, it runs through without Problems 7 times but suddenly there is an error ?
Attached the full code at the bottom if anyone can help it would be SOOOO much appreciated (every tip counts)

Thanks & Greetz
Kai

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Node
{
    public int x;
    public int y;
    public int player = 0; // 1 = white 2 = whiteQueen 3= black 4 = blackQueen
    public bool mustTake = false;
}
public class MoveScore
{
    public int score;
    public Node point;

    public MoveScore(int score , Node point)
    {
        this.score = score;
        this.point = point;
    }
}

public class AI2 : MonoBehaviour {
    Node[,] grid = new Node[8,8];
    public List<MoveScore> rootsChildrenScore;
    int moves;


    public void AIMove()
    {
        Debug.Log ("AIMove");
        for (int x = 0; x < 8; x++) {
            for (int y = 0; y < 8; y++) {
                grid [x, y] = new Node ();
            }
        }
        GetField ();

        callMiniMax (0,1);
        Node best = returnBestMove ();

        Debug.Log ("---" + best.x.ToString () + " " + best.y.ToString () + "---");
    }

    void GetField()
    {
        Debug.Log ("GetField");

        for (int i = 0; i < gameObject.GetComponent<BoardScript>().Fields.Length; i++) {
            grid [gameObject.GetComponent<BoardScript> ().Fields [i].GetComponent<BoardFieldScript> ().x, gameObject.GetComponent<BoardScript> ().Fields [i].GetComponent<BoardFieldScript> ().y].x = gameObject.GetComponent<BoardScript> ().Fields [i].GetComponent<BoardFieldScript> ().x;
            grid [gameObject.GetComponent<BoardScript> ().Fields [i].GetComponent<BoardFieldScript> ().x, gameObject.GetComponent<BoardScript> ().Fields [i].GetComponent<BoardFieldScript> ().y].y = gameObject.GetComponent<BoardScript> ().Fields [i].GetComponent<BoardFieldScript> ().y;
            grid [gameObject.GetComponent<BoardScript> ().Fields [i].GetComponent<BoardFieldScript> ().x, gameObject.GetComponent<BoardScript> ().Fields [i].GetComponent<BoardFieldScript> ().y].player = 0;
            if (gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().occupied == true && gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().white == true) {
                if (gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().queen == false) {
                    grid [gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().x, gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().y].player = 1;
                } else if (gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().queen == true) {
                    grid [gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().x, gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().y].player = 2;
                }
            } else if (gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().occupied == true && gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().white == false) {
                if (gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().queen == false) {
                    grid [gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().x, gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().y].player = 3;
                } else if (gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().queen == true) {
                    grid [gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().x, gameObject.GetComponent<BoardScript>().Fields [i].GetComponent<BoardFieldScript> ().y].player = 4;
                }
            }
        }
    }



    public Node returnBestMove()
    {
        Debug.Log ("RETURN BEST");

        int MAX = -1000;
        int best = -1;


        for (int i = 0; i < rootsChildrenScore.Count; i++) {
            if(MAX < rootsChildrenScore[i].score && isValidMove(rootsChildrenScore[i].point.x,rootsChildrenScore[i].point.y))
                {
                MAX = rootsChildrenScore [i].score;
                best = i;
                }
        }

        if (best > -1) {
            return rootsChildrenScore [best].point;
        }
        Node blank = new Node ();
        blank.x = 0;
        blank.y = 0;
        Debug.Log ("Return What");
        return blank;
    }

    public bool isValidMove(int x , int y){

        if (grid [x, y].player == 0) {
            return true;
        } else
            return false;
       
    }

    void callMiniMax(int depth,int turn)
    {
        Debug.Log ("callMiniMax");

        rootsChildrenScore = new List<MoveScore> ();
        minimax (depth, turn);
    }

    public int minimax(int depth,int turn)
    {
        Debug.Log ("MiniMax");

        if (hasWhiteWon ())
            return +1;
        if (hasBlackWon ())
            return -1;
        List<Node> pointsAvailable = GetMoves ();

        if (pointsAvailable.Capacity == 0) {
            Debug.Log ("WHAT");
            return 0;
        }

        List<int> scores = new List<int> ();
        for (int i = 0; i < pointsAvailable.Count; i++) {
            Node point = pointsAvailable [i];
            Debug.Log (i.ToString () + "TURN " + turn.ToString());

            if (turn == 1) {
                Debug.Log ("Turn 1");
                Node x = new Node ();
                x.x = point.x;
                x.y = point.y;
                x.player = 2;
                grid [point.x, point.y] = x;
                int currentScore = minimax (depth + 1, 2);
                scores.Add (currentScore);
                if (depth == 0) {
                    Debug.Log ("Depth 0");
                    MoveScore m = new MoveScore (currentScore, point);
                    m.point = point;
                    m.score = currentScore;
                    rootsChildrenScore.Add (m);
                }
            } else if (turn == 2) {
                Debug.Log("Turn 2");
                Node o = new Node ();
                o.x = point.x;
                o.y = point.y;
                o.player = 1;
                grid [point.x, point.y] = o;
                int currentScore = minimax (depth + 1, 1);
                scores.Add (currentScore);
                turn = 1;
            }
            grid [point.x, point.y] = null;
        }
        Debug.Log ("RETURN");
        return turn == 1 ? returnMax (scores) : returnMin (scores);
    }

    public int returnMin(List<int> list){
        Debug.Log ("ReturnMin");
        int min = 100000;
        int index = -1;
        for (int i = 0; i < list.Count; i++) {
            if (list [i] < min) {
                min = list [i];
                index = i;
            }
        }
        return list [index];
    }

    public int returnMax(List<int> list){
        Debug.Log ("ReturnMax");
        int max = -100000;
        int index = -1;
        for (int i = 0; i < list.Count; i++) {
            Debug.Log (i.ToString());
            if (list [i] > max) {
               
                max = list [i];
                index = i;
                Debug.Log ("MAX");
            }
        }
        return list [index];
    }

    List<Node> GetTakes()
    {
        List<Node> result = new List<Node> ();


        return result;
    }

    List<Node> GetMoves()
    {
        Debug.Log ("GetMoves");
        List<Node> result = new List<Node> ();
        int count = 0;

        for (int x = 0; x < 8; x++) {
            for (int y = 0; y < 8; y++) {
                Debug.Log (x.ToString () + y.ToString ());

                if (grid [x, y].player != 0) {
                    if (grid [x, y].player == 1) {
                        // whitepawn
                        if (x > 0 && y > 0 && grid [x - 1, y - 1].player == 0) {
                            result.Add (grid [x - 1, y - 1]);
                            result [count].x = grid [x - 1, y - 1].x;
                            result [count].y = grid [x - 1, y - 1].y;
                            count++;
                        }
                        if (x < 7 && y > 0 && grid [x + 1, y - 1].player == 0) {

                            result.Add (grid [x + 1, y - 1]);
                            result [count].x = grid [x + 1, y - 1].x;
                            result [count].y = grid [x + 1, y - 1].y;
                            count++;
                        }
                    } else if (grid [x, y].player == 3) {
                        if (x > 0 && y < 7 && grid [x - 1, y + 1].player == 0) {
                            result.Add (grid [x - 1, y + 1]);
                            result [count].x = grid [x - 1, y + 1].x;
                            result [count].y = grid [x - 1, y + 1].y;
                            count++;
                        }
                        if (x < 7 && y < 7 && grid [x + 1, y + 1].player == 0) {
                            result.Add (grid [x + 1, y + 1]);
                            result [count].x = grid [x + 1, y + 1].x;
                            result [count].y = grid [x + 1, y + 1].y;
                            count++;
                        }
                    }
                }
            }
        }

        Debug.Log ("RETURN RESULT WITH THE COUNT OF " + count.ToString ());

        return result;
    }

    public bool isValidMove(Node selected,int x,int y){
        if (selected.player == 1) {
            if (grid [x - 1, y - 1].player == 0 || grid [x + 1, y - 1].player == 0)
                return true;
            else
                return false;
        } else if (selected.player == 2) {
            return true;

        } else if (selected.player == 3) {
            if (grid [x - 1, y + 1].player == 0 || grid [x + 1, y + 1].player == 0)
                return true;
            else
                return false;

        } else if (selected.player == 4) {
            return true;

        } else
            return false;
    }


    bool hasBlackWon()
    {
        Debug.Log ("HasBlackWon");

        for (int y = 0; y < 8; y++) {
            for (int x = 0; x < 8; x++) {
                if (grid [x, y].player == 1 || grid [x, y].player == 2 ) {
                    Debug.Log ("No");

                    return false;

                }
            }
        }
        return true;
    }

    bool hasWhiteWon()
    {
        Debug.Log ("hasWhiteWon");

        bool won = true;
        for (int y = 0; y < 8; y++) {
            for (int x = 0; x < 8; x++) {
                if (grid [x, y].player == 3 || grid [x, y].player == 4 ) {
                    Debug.Log ("No");

                    return false;

                }
            }
        }
        return true;
    }
}

It’s a little hard to tell, but I noticed you used two if’s in a row, which generally is a bad idea unless you very specifically mean to do it because one if can change the results of the next one. It’s always best to use an if/else if/ or else.

Does ever grid position on the board contain a .player object? Looking at line 224, a null ref would only really be triggered if the value of grid [x + 1, y - 1].player is null.

Is it always the same line? If so, set a break point on it and run the game. See what happens when it gets to the break. What is the value of that variable?

yes ever object contains a .player object the weird thing is it runs 6-8 times (depending on the positions its calculating with) but than gives the error

i´ll try the break and report in a moment thanks

1 Like

its specific here for later would rly like to avoid using && or else here