Zoltán Fekete
Zoltán Fekete

Reputation: 594

Create 3 dimensional array

I'm new at C# and I want to create a multidimensional array like this:


(source: parks.ca.gov)

But in 8x8x4 cells.

I want to store maze cells.

{
    {1,1,1,0}, {1,0,0,0}, {1,1,1,1}, {1,0,0,0}, {1,1,0,1}, {1,1,0,1}, {0,1,0,0}, {1,0,0,1},
    ...
    {0,1,1,0}, {1,0,1,0}, {0,0,1,1}, {1,0,1,0}, {1,0,0,1}, {0,1,0,1}, {1,1,1,0}, {1,1,0,1},
}
int[,,] table = new int[8,8,4]; // is this right?

table[0,0] = {0, 0, 1, 1}; // I want to fill it this way.

Upvotes: 2

Views: 3812

Answers (3)

svick
svick

Reputation: 244777

  1. With multidimensional arrays, you can either set them all at once (using basically the syntax you showed):

    int[,,] table = {
                      { { 1, 1, 1, 0 }, { 1, 0, 0, 0 } },
                      { { 0, 1, 1, 0 }, { 1, 0, 1, 0 } }
                    };
    

    or you can set the items one by one:

    int[,,] table = new int[8,8,4];
    table[0,0,0] = 0;
    

    there is nothing in between. The best you could do is to write an extension method that would work something like this:

    table.Set(0, 0, new int[] { 0, 0, 1, 1 });
    
  2. As an alternative, you could use 2D array of arrays:

    int[,][] table = {
                      { new[] { 1, 1, 1, 0 }, new[] { 1, 0, 0, 0 } },
                      { new[] { 0, 1, 1, 0 }, new[] { 1, 0, 1, 0 } }
                    };
    

    or you could use almost the syntax you proposed:

    int[,][] table = new int[8,8][];
    table[0,0] = new[] { 0, 0, 1, 1 };
    

    A disadvantage of this approach is that it doesn't force the inner arrays to be all the same length.

  3. As proposed in comments, another option would be use a custom type like Cell and have a 2D array of those. Doing that makes it clearer what the array actually means, table[0,0].Left is certainly more readable than table[0,0,1].

  4. If the wall can be there or not, you shouldn't use int values 0 and 1, you should use bool values false and true. If you want to have more states, an enum might be appropriate.

  5. Your structure contains a lot of duplication, since bottom of a cell is the same as top of the cell below it (unless you want to have one way walls). This means the structure can get into an inconsistent state, which is often hard to debug (“The wall isn't there? But I just looked and it is there.”).

    One way to avoid that would be store walls instead of cells. Instead of 8×8 cells, you would have 8×9 horizontal walls and 9×8 vertical walls. You could then have methods that would abstract this away, so you could easily look up walls of a particular cell.

Upvotes: 1

Pierre-Luc Pineault
Pierre-Luc Pineault

Reputation: 9201

I'm aware it does not explicitly answer the question, but in my opinion you're shooting yourself in the foot by working with 3D arrays. C# is an OO language, so it really helps if you think OO.

Instead of working with a multidimensional array representing cells for you 3d Maze (if it is really a 3d maze you want), why not create a List of classes named Cell, each one containing their position and other stuff you need, like :

public class Cell
{ 
    public Cell (int x, int y, int z)
    {
        X = x;
        Y = y;
        Z = z;
    }

    public int X { get; set; }
    public int Y { get; set; }
    public int Z { get; set; }
    public bool IsExplored { get; set; }
}

Then you can have a simple List<Cell> that you can iterate over. You can also remove the x,y,z and create a Position class.

For walls, you can create an Enum and use bitwise operations, or store a list of Enum. Since you're a beginner, I'd suggest you the list of enums. You would have to add this Enum in the code, and this property to the Cell class :

public Enum WallPosition
{
    Top,
    Left,
    Bottom,
    Right
}


public List<WallPosition> walls { get; set;} //This goes into the Cell class

That way, every operation will be much much easier to do. For example, if you need to explore every cell at the column #3, you can do

foreach (Cell cell in yourCellList.Where(c => c.Y == 3))
{
    cell.IsExplored = true;
}

Need to render every explored cell differently?

foreach (Cell cell in yourCellList.Where(c => c.IsExplored) { //Do stuff }

And so on.

No need for complicated for loops with your 3 dimensions, and a simple foreach is in my opinion far more readable than a

for (int i = 0; i < 8; i++)
    for (int j = 0; j < 8; j++)
        for (int k = 0; k < 4; k++)

every time you need to access your table.

The only ugly part would be to fill you list (By creating new Cell instances), but it would still be far more readable than a huge wall of { { { 0, 1, 0, 1 }, {1, 1, 1, 0} [...]

I'd also suggest that you read an introduction to OO principles.

Upvotes: 6

tom
tom

Reputation: 22959

An array initializer for a 3D array would look like this:

int[,,] table = {
                  { {1,1,1,0}, {1,0,0,0}, ... },
                  { {0,1,1,0}, {1,0,1,0}, ... },
                  ...
                };

The first line is right. The second line won't work. The closest thing is to use a 2D array of arrays:

int[,][] table = new int[8,8][];
table[0,0] = new int[] {0, 0, 1, 1};

Like @tigrou and @Pierre-Luc Pineault suggested, it would be a lot cleaner to encapsulate each cell in an object instead of a plain array.

Consider storing the data in an external file and reading it in instead of hardcoding the 256 numbers.

Upvotes: 0

Related Questions