Absinthe
Absinthe

Reputation: 3391

Step through 2D array in hexagon pattern

I use a nested for loop to create a grid of hexagons. This creates a square grid:

for (int z = 0; z < gridSize; z++)
{
    for (int x = 0; x < gridSize; x++)
    {
            // creates verts for a hexagon shape which later form a mesh
            // x and z form the basis of the Vector3 position of the center 
            // of each hexagon
            CreateCell(x, z); 
    }
}

enter image description here

I've drawn the start and end values for z & x on the image.

What I'd like is to have the grid itself also shaped hexagonally:

enter image description here

I think figured out the limits for x:

int greaterThan = Mathf.RoundToInt(gridSize/ 3) - 1;
int lessThan = width - greaterThan;

And that (I think) x should only be at it's min and max (0 & 6 in the examples) when z = gridSize / 2 rounded up, though I may well be wrong!

I tried putting a bunch if IFs in the loops but it quickly started to get overly complicated, I figure there must be a more 'mathsy' way to do it, but sadly I'm not mathsy!

Any idea how I can write a loop to form the required pattern?

Upvotes: 3

Views: 1405

Answers (3)

SergGr
SergGr

Reputation: 23788

If @AsfK's solution is not good enough, I'll give it a try as well:

    private static void PrintHexLine(int z, int size)
    {
        if (z >= size)
        {
            z = 2 * size - 2 - z;
        }
        int start = size - z - 1;
        int end = start + size + z;
        for (int x = 0; x < start; x++)
        {
            Console.Write(" ");
        }
        for (int x = start; x < end; x++)
        {
            Console.Write("* ");
            //Console.Write((x - start / 2) + " "); // position v1
            //Console.Write((x - (start + 1) / 2) + " "); // position v2

        }
        Console.WriteLine();
    }

    public static void PrintHex(int size)
    {
        for (int z = 0; z < 2 * size - 1; z++)
        {
            PrintHexLine(z, size);
        }
    }

With such code PrintHex(4) results in

   * * * *
  * * * * *
 * * * * * *
* * * * * * *
 * * * * * *
  * * * * *
   * * * *

And if you uncomment the position v1 line instead of the one that prints "* ", you'll get

   2 3 4 5
  1 2 3 4 5
 1 2 3 4 5 6
0 1 2 3 4 5 6
 1 2 3 4 5 6
  1 2 3 4 5
   2 3 4 5

similarly position v2

   1 2 3 4
  1 2 3 4 5
 0 1 2 3 4 5
0 1 2 3 4 5 6
 0 1 2 3 4 5
  1 2 3 4 5
   1 2 3 4

which looks like the x indices you want. Basing on your data I'm not really sure whether you need v1 or v2 variant. The v2 looks more consistent to me but it really depends on how your CreateCell(x, z); treats the x = 0 case.

P.S. obviously you can inline PrintHexLine call but it means having two different z variables that you should not mess up with and I think it is cleaner to move that in a separate method.

Upvotes: 2

Absinthe
Absinthe

Reputation: 3391

Thanks to a hint from AsfK I solved it like this

int xL, xU, xMid, zM2;
xL = Mathf.FloorToInt(width / 3) - 1;
xU = (width - xL) + 1;
xMid = Mathf.FloorToInt(width / 2);

for (int z = 0; z < height; z++)
{
    for (int x = xL; x < xU; x++)
    {
        CreateCell(x, z);
    }

    zM2 = z % 2;

    if(z < xMid)
    {
        if (zM2 == 0)
        {
            xL--;
        }
        if (z > 0 && zM2 == 1)
        {
            xU++;
        }
    } else
    {
        if (zM2 == 1)
        {
            xL++;
        }
        if (zM2 == 0)
        {
            xU--;
        }
        if (z == width - 1)
        {
            xL--;
            xU++;
        }
    }
}

Would be great if anyone can think of a more elegant solution!

Upvotes: 1

AsfK
AsfK

Reputation: 3476

According your excepted picture the center is the long row (gridSize = 7).

floor(7/2) = 3 (/2 because the long row is in the center)

Now, gridSize - 3 = 4 ==> 4 items in your first row

Then each iterate add one till you have 7 items in one row.

Then do a minus...

it's the code (draw "*", not added spaces before and after..)

int gridSize = 7;
int center = 7/2;
int delta = 1;
for (int r = 0; r < gridSize; r++) {
    for (int c = gridSize - center; c < gridSize + delta; c++){
        System.out.print("*");
        // location of c = c - delta (position)
    }
    System.out.println();
    if (r < center)
        delta++;
    else
        delta--;
}

Upvotes: 1

Related Questions