How to fix index out of range error?

I’m currently getting the following error:

 ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
System.ThrowHelper.ThrowArgumentOutOfRangeException (System.ExceptionArgument argument, System.ExceptionResource resource) (at <eae584ce26bc40229c1b1aa476bfa589>:0)
System.ThrowHelper.ThrowArgumentOutOfRangeException () (at <eae584ce26bc40229c1b1aa476bfa589>:0)
System.Collections.Generic.List`1[T].get_Item (System.Int32 index) (at <eae584ce26bc40229c1b1aa476bfa589>:0)
GridSystem2D.addPoints (System.Collections.Generic.List`1[TilePoint]& points, System.Collections.Generic.List`1[T] add) (at Assets/Scripts/Grid/GridSystem2D.cs:172)
GridSystem2D.isConnected (TilePoint P, System.Boolean main) (at Assets/Scripts/Grid/GridSystem2D.cs:124)
GridSystem2D.verifyPlaySpace () (at Assets/Scripts/Grid/GridSystem2D.cs:62)
GridSystem2D.StartGame () (at Assets/Scripts/Grid/GridSystem2D.cs:33)
GridSystem2D.Start () (at Assets/Scripts/Grid/GridSystem2D.cs:23)

For context (because I am bad at commenting my code), I am currently trying to make one of those match 3 games and the part currently having problems is dedicated to making sure that the play space doesn’t generate with tiles already matching in groups of 3 or more. Currently my biggest theory is the “Void addPoints” method but knowing me I could be miles off.

 public class GridSystem2D : MonoBehaviour
 {
    int width = 96;
    int height = 96;

    System.Random random = new System.Random();

    Node[,] playSpace;
    public ArrayLayout playSpaceLayout;
    public Sprite[] Pieces;
    public RectTransform Board;
    public GameObject NodePiece;

    // Start is called before the first frame update
    void Start()
    {
        StartGame();
    }

    void StartGame()
    {
        playSpace = new Node[width, height];

        string seed = getRandomSeed();
        random = new System.Random(seed.GetHashCode());
        initializeBoard();
        verifyPlaySpace();
        instantiatePlaySpace();
    }

    void initializeBoard()
    {        
        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                playSpace[x, y] = new Node((playSpaceLayout.rows[y].row[x]) ? -1 : fillPiece(), new TilePoint(x, y));
            }
        }
    }


    void verifyPlaySpace()
    {
        
        List<int> remove;
        for (int x = 0; x < height; x++)
        {
            for (int y = 0; y < width; y++)
            {
               TilePoint P = new TilePoint(x, y);
               int val = getPointValue(P);
                if (val <= 0) continue;

                remove = new List<int>();
                while (isConnected(P, true).Count > 0)
                {
                    val = getPointValue(P);
                     if (!remove.Contains(val))
                     {
                        remove.Add(val);
                     }
                    setValueAtPoint(P, newValue(ref remove));
                }
            }
        }
    }

    void instantiatePlaySpace()
    {
        for (int x = 0; x < height; x++)
        {
            for (int y = 0; y < width; y++)
            {
                int val = playSpace[x, y].value;
                if (val <= 0)
                {
                    continue;
                }
                GameObject P = Instantiate(NodePiece, Board);
                NodePiece node = P.GetComponent<NodePiece>();
                RectTransform rect = P.GetComponent<RectTransform>();
                rect.anchoredPosition = new Vector2(47 + (64 * x), -52 - (64 * y));
                node.initialise(val, new TilePoint(x, y), Pieces[val - 1]);
            }
        }
    }

    //prevents the play space starting with tiles already matching
    List<TilePoint> isConnected(TilePoint P, bool main)
    {
        List<TilePoint> connected = new List<TilePoint>();
        int val = getPointValue((TilePoint) P);
        TilePoint[] directions =
        {
            TilePoint.up,
            TilePoint.right,
            TilePoint.down,
            TilePoint.left
        };

        foreach(TilePoint direction in directions)
        {
            List<TilePoint> line = new List<TilePoint>();

            int same = 0;            
            for (int i =1; i < 3; i++)
            {
                TilePoint next = TilePoint.add(P, TilePoint.mult(direction, i));
                if (getPointValue(next) == val)
                {
                    line.Add(next);
                    same++;
                }
                
            }
            if (same > 1)
            {
                addPoints(ref connected, line);
            }
        }

        for (int i = 0; i < 2; i++)
        {
            List<TilePoint> line = new List<TilePoint>();

            int same = 0;

            TilePoint[] check = { TilePoint.add(P, directions[i]), TilePoint.add(P, directions[i + 2]) };
            foreach (TilePoint next in check)
            {
                if (getPointValue(next) == val)
                {
                    line.Add(next);
                    same++;
                }
            }

            if (same > 1)
            {
                addPoints(ref connected, line);
            }
        }

        if (main)
        {
            for (int i = 0; i < connected.Count; i++)
            {
                addPoints(ref connected, isConnected(connected[i], main == false));
            }
        }

        if (connected.Count > 0)
        {
            connected.Add(P);
        }
        return connected;
    }

    void addPoints (ref List<TilePoint> points, List<TilePoint> add)
    {
        foreach (TilePoint P in add)
        {
            bool doAdd = true;
            for (int i = 0; i < add.Count; i++)
            {
                if (points[i].Equals(P))
                {
                    doAdd = false;
                    break;
                }
            }

            if (doAdd)
            {
                points.Add(P);
            }
        }
    }

    int fillPiece()
    {
        int val = 1;
        val = (random.Next(0,100) / (100 /Pieces.Length)) + 1;
        return val;
    }
    int getPointValue(TilePoint P)
    {
        if (P.x < 0 || P.x >= width || P.y < 0 || P.y > height) 
        { 
            return -1; 
        }
        return playSpace[P.x, P.y].value;
    }

    void setValueAtPoint (TilePoint P, int v)
    {
       
        playSpace[P.x, P.y].value = v;
    }

    int newValue(ref List<int> remove)
    {
        List<int> available = new List<int>();
        for(int i = 0; i <Pieces.Length; i++)
        {
            available.Add(i+1);
        }
        foreach (int i in remove)
        {
            available.Remove(i);
        }

        if (available.Count > -0)
        {
            return 0;
        }
        return available[random.Next(0, available.Count)];
    }

    string getRandomSeed()
    {
        string seed = "";
        string allowedCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!£$%^&*?@|><,.#~:;)(-_=+";
        for (int i = 0; i < 13; i++)
        {
            seed += allowedCharacters[Random.Range(0, allowedCharacters.Length)];
        }
        return seed;
    }
}

any and all tips or help solving this error would be greatly appreciated, thank you in advance.

Here are some notes on IndexOutOfRangeException and ArgumentOutOfRangeException:

http://plbm.com/?p=236

Steps to success:

  • find which collection it is and what line of code accesses it <— (critical first step!)
  • find out why it has fewer items than you expect
  • fix whatever logic is making the indexing value exceed the collection size

Remember also:

  • a collection with ZERO elements cannot be indexed at all: it is empty
  • you might have more than one instance of this script in your scene/prefab
  • the collection may be used in more than one location in the code
  • indices start at ZERO (0) and go to the count / length minus 1.

This means with three (3) elements in your collection, they are numbered 0, 1, and 2 only.