1

I am having difficulty figuring out how to setup my array correctly.

I have a basic array of tiles set to my array grid[,] this works fine.

Now i am trying to make an array for my edges between grids so i can place down walls.

So i have this: walls[,][,] where each [,] is a grid position, thus each wall separates 2 grid positions.

The end goal here is that i want a wall array with two grid points say A and B such that i can then do:

Wall wallObject = walls[A.x,A.y][B.x,B.y];

Hope that makes sense. I tried doing something like this:

' Now since each 1 tile can have 4 walls i tried to set up my wall array like this but could not work out the syntax correctly to do it:

grids = new Tile[x,y];
walls = new Wall[grids.GetLength(0), grids.GetLength(1)][walls.GetLength(0) * 4, walls.GetLength(1) * 4]; // invalid rank specifier ERROR

for(int i = 0; i < x; i++) {
for(int j = 0; j < y; j++) {

   grids[i, j] = new Tile(new Vector3(i, 0, j));
   foreach (Vector3 gridNeighbour in AdjacentTiles(new Vector3(i, 0, j))) //4 directions
   {
      if (!InGrid(gridNeighbour)) continue;    
      walls[i, j][(int)gridNeighbour.x, (int)gridNeighbour.z] = new Wall(grid[i,j],grid[(int)gridNeighbour.x,(int)gridNeighbour.z]);
   }

}}

I get an error on the second line not sure the of the correct way to write it. I am also fairly sure my logic is wrong since this data setup i think would give me double data for my walls such that i would get wall[gridA][gridB] and wall[gridB][gridA] which i would like to avoid but i don't know how to.

2
  • I really don't think you need a 4-dimensional array for this, assuming I'm understanding you right. If I'm not, can you better explain why you need a 4-dimensional array? Commented Mar 12, 2017 at 3:58
  • A given wall seperates two tiles A and B so if i want to find a wall that seperates two specific tiles the idea was to grab it from the array like walls[A.x,A.y][B.x,B.y] Hope that makes sense. I presumed i would need this kind of array structure to do it. Commented Mar 12, 2017 at 4:02

2 Answers 2

1

Taking your question directly, the basic issue is that you are not really trying to create a 4-dimensional array. Instead, you are trying to create a two-dimensional array of two-dimensional arrays.

If you want to do that, you need to allocate the top-level two-dimensional array first, and then fill it in with the other two-dimensional array elements:

walls = new Wall[grids.GetLength(0), grids.GetLength(1)][,];

for (int i = 0; i < grids.GetLength(0); i++)
for (int j = 0; j < grids.GetLength(1); j++)
{
    walls[I, j] = new Wall[grids.GetLength(0) * 4, grids.GetLength(1) * 4];
}

Alternatively, you could create a true four-dimensional array:

Wall[,,,] walls = new Wall[grids.GetLength(0), grids.GetLength(1),
                           grids.GetLength(0) * 4, grids.GetLength(1) * 4];

That said, both of these approaches seem extremely wasteful to me. The vast majority of the elements in these arrays will be unused. You only care about four walls per tile, so why not store only four per tile? For example:

Wall[,,] walls = new Wall[x, y, 4];

(Rather than using GetLength(), I'm just reusing the x and y variables that in your original code appear to define the dimensions of the grid.)

Then write a helper method that, given x/y locations of two different cells, will return an index for the wall in question. Here's one way to approach it:

private static readonly int[,] directions =
{
    { 0, -1 },
    { 1,  0 },
    { 0,  1 },
    {-1,  0 }
};

int GetWallIndex(int x0, int y0, int x1, int y1)
{
    int dx = x0 - x1, dy = y0 -y1;

    for (int i = 0; i < 4; i++)
    {
        if (directions[i, 0] == dx && directions[i, 1] == dy)
        {
            return i;
        }
    }

    return -1;
}

The GetWallIndex() method above will return the appropriate index for the Wall object in question, or -1 if you pass it the locations for tiles that are not actually adjacent. You can then use that index in the three-dimensional Wall[,,] array to get the Wall object in question.

This still has the inefficiency of having to duplicate the Wall data, i.e. once for each cell on either side of the wall. IMHO, this is a minor concession, especially if the Wall object is a reference type (and so the only thing duplicated is the reference itself). However, it is possible to eliminate even this inefficiency by storing the data in a dictionary and normalizing the tile coordinates when you look it up. For example:

struct WallAddress
{
    public int X0 { get; }
    public int Y0 { get; }
    public int X1 { get; }
    public int Y1 { get; }

    public WallAddress(int x0, int y0, int x1, int y1)
    {
        // Optional, not shown here:
        // Validate addresses to make sure they represent adjacent tiles

        if (x1 < x0 || (x1 == x0 && y1 < y0))
        {
            int xT = x0, yT = y0;

            x0 = x1;
            x1 = xT;
            y0 = y1;
            y1 = yT;
        }

        X0 = x0;
        Y0 = y0;
        X1 = x1;
        Y1 = y1;
    }
}

Dictionary<WallAddress, Wall> walls = new Dictionary<WallAddress, Wall>();

Then you just create the WallAddress value for the pair of tiles for each Wall object and fill in the dictionary.

Sign up to request clarification or add additional context in comments.

Comments

1

Unlike in Java where you might do something like:

walls = new Wall[x][y][x2][y2];

C# won't let you initialize like that. There is a way to make Wall[,][,] work, but it's much easier to just make a 4-dimensional array of Wall[,,,].

However that won't even work, because if you really want to do things this way with a [reallybignumber]-dimensional array (which I'm not sure is the best way to do it but let's just go with it), you would need a Wall[,,,,] array to store x1, y1, x2, y2, and the wall orientation.

While this will cost the slightest amount of speed (probably? I don't actually know the performance impact of multi-dimensional arrays in C#), you'll save a lot of memory (and sanity) if you just go with a dictionary and struct like in Peter Duniho's answer.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.