Enumeration over grid states

In my problem, I have a series of "states" I need to be able to iterate over. Each state holds a 2-dimensional array of objects. Each object has a boolean and an int, both initialized to random values. The next state depends on the current and, for any given state, there is only one possible next state.

Assuming the initial state is considered to be 0, how would I implement IEnumerator or IEnumerable (or both, or neither), in order to iterate over these states.

Ideally, I would be able to use syntax like this:

State++;

or:

if(State == State + 3) {
    DoSomething();
}

Or maybe even use a slider to move between states.

I'm fairly new to Unity and C# and I have been beating my head against a wall trying to figure this out. I'm not even sure if these interfaces are the way to go, or if another method would be more appropriate. Any help is highly appreciated.

Below is a skeleton of what I already have. It seems the StateData class would be my IEnumerable(?) because it holds what I want to iterate over. This seems to fulfill IEnumerator.MoveNext(), though; so, I'm confused.

MonoState.cs

public class MonoState : MonoBehaviour {
    public StateData currentState;
    private void Start() {
        // here's where I initialize the data.
    }
    private void Update() {
        // here's where refresh my scene to match the data
    }
}

StateData.cs

public class StateData {
    ItemData[][] data;
    public StateData(ItemData[][] initalState) {
        data = initialState;
    }
    public ItemData[][] GetNextState() {
        // here's where I calculate the next state
        //     and I assign it to data.
    }
}

ItemData.cs

public class ItemData {
    public bool Flag;
    public int Value;
}

I am not quite sure if this is what you mean, but the issue seems to be that you have an ordered list of “things” (state objects) and you want to go through them in order, and to be able to perform comparisons (e.g. if the “state” you are in now is equal to the third “state” then do something).

If you create State as a class (not derived from Monobehaviour) then you can populate instances of State into an array (i.e. State if you know the total number of states at the point you create the array) or a List.

If you want to see the list/array of states in the inspector then you can set the State class as serializable. But if there are a lot of them then only do this whilst you are working on the logic as I find a large number of these will be slow on performance.

Does that help?

First, a clarification.

//This is a jagged array (an array of arrays)
ItemData[][] data;

//This is a multidimensional array
ItemData[,] data;

The difference between these types is that a multidimensional array exists as a fixed block, whereas a jagged array can have different array lengths per element. If your item data has fixed lengths on both axes I would suggest using a multidimensional array instead.

Another thing to point out is reference types vs. value types. If you compare two classes, chances are you aren’t comparing the values held within them, rather just comparing if they point to the same object (this goes for arrays too). For that reason, I would recommend using structs in this case (or at least overloading the comparison operators);

public struct ItemData 
{
    public bool Flag;
    public int Value;
}

public struct StateData : IEquatable<StateData>
{
    public ItemData[][] data;
    
    public StateData(ItemData[][] initalState) 
    {
        data = initialState;
    }
    
    public ItemData[][] GetNextState() 
    {
        // here's where I calculate the next state
        //     and I assign it to data.
    }

    //Compare the values of the array rather than the array itself
    public bool Equals (StateData a_Other)
    {
        if (data.Length != a_Other.data.Length)
            return false;

        for (int i = 0; i < data.Length; i++)
        {
            if (data<em>.Length != a_Other.data*.Length)*</em>

return false;
for (int j = 0; j < data*.Length; j++)*
{
if (data[j] != a_Other.data*[j])
return false;
_}
}
return true;
}
public static bool operator == (StateData a_LHS, StateData a_RHS) => return a_LHS.Equals (a_RHS);
public static bool operator != (StateData a_LHS, StateData a_RHS) => return !a_LHS.Equals (a_RHS);
}
Finally, to do what you require I would then have another class on top that keeps a list of StateData objects which you can enumerate over;
public class States
{*

private List states;_

public States (ItemData initialState)
{
states = new List();
states.Add (new StateData (initialState));
}

//This lets you access a States object as though it were an array, i.e.
// States states = new States();
// StateData data = states[3];
public StateData this
{
get
{
//If we don’t have enough states, start generating and caching them until we do
while (states.Count <= i)
{
states.Add (new StateData (Current.GetNextState ()));
i++;
}

return states*;*
}
}

//Helper properties to access the current and next states
public int CurrentIndex => states.Count - 1;
public StateData Current => states[CurrentIndex];
public StateData Next => this[CurrentIndex + 1];
public StateData FutureState (int a_Index) => this[CurrentIndex + a_Index];
//To get syntax equivalent to your ‘state + 3’
public static StateData operator + (States a_States, int a_Index) => a_States.FutureState (a_Index);
}
Now you should be able to access it like you showed above, i.e.
States states = new States ( /* … */ );

//Grab the current state data;
ItemData[][] data = states.Current.data;

//Compare states;
if (states.Current == (states + 3))
DoSomething();
You can still inherit from IEnumerable (just point to to the ‘List’), however I felt it may be easier to understand if done without first.