FaTaLL
FaTaLL

Reputation: 511

Swap references of 3 hexagon neighbors

I have a two dimensional array that stores all hexagons. It's an array of Hexagon objects that is indexed with 2 integers.

I want to swap 3 hexagons with each other like i showed in the picture.

Can anyone help me with the algorithm that should do the job?

Thanks!

Example

Here is the functions for creating hexagons.

    public void CreateGrid(int gridWidth, int gridHeight)
    {
        for (int y = 0; y < gridHeight; y++)
        {
            for (int x = 0; x < gridWidth; x++)
            {


          GameObject Hexagon = Instantiate(HexagonPre, 
                                           Vector2.zero, 
                                           Quaternion.identity, 
                                           HexGrid);

                Vector2 gridPos = new Vector2(x, y);
                Hexagon.transform.position = CalcWorldPos(gridPos);
                Hexagon.transform.name = "X: " + x + " | Y: " + y;
            }
       }
}

 Vector2 CalcWorldPos(Vector2 gridPos)
{
    float offset = 0;
    if(gridPos.y %2 != 0)
        offset = hexWidth / 2f;

    float x = startPos.x + gridPos.x * hexWidth + offset;
    float y = startPos.y - gridPos.y * hexHeight * 0.75f;

    return new Vector2(x, y);

}

Okay I shared how the game looks like. I click somewhere in the game. The game finds 3 closest hexagons on where i click. Then I change the locations of those 3 hexagons. (I already did that). But somehow i need my array to know that those 3 hexagons swapped with each other. Be careful this would be any 3 hexagons. So we need an algorithm for this to work for any 3 hexagons to swap their place in the array.

Video showing what I already have: youtube.com/watch?v=fVvQd47OswQ&feature=youtu.be

Upvotes: 2

Views: 177

Answers (3)

Ruzihm
Ruzihm

Reputation: 20269

If you already have the coordinates of the 3 hexagons, then you can determine which hexagon has the unique Y coordinate, and determine which of the other two is on the right and which is on the left:

Vector2Int hexagonACoord;
Vector2Int hexagonBCoord;
Vector2Int hexagonCCoord;

Vector2Int loneHexagonCoord;
Vector2Int leftHexagonCoord;
Vector2Int rightHexagonCoord;

if (hexagonACoord.y != hexagonBCoord.y  && hexagonACoord.y != hexagonCCoord.y)
{
    loneHexagonCoord = hexagonACoord;

    leftHexagonCoord = hexagonBCoord;
    rightHexagonCoord = hexagonCCoord;
}
else if (hexagonBCoord.y != hexagonCCoord.y  && hexagonBCoord.y != hexagonACoord.y)
{
    loneHexagonCoord = hexagonBCoord;

    leftHexagonCoord = hexagonACoord;
    rightHexagonCoord = hexagonCCoord;
}
else 
{
    loneHexagonCoord = hexagonCCoord;

    leftHexagonCoord = hexagonACoord;
    rightHexagonCoord = hexagonBCoord;
}

if (leftHexagonCoord.x > rightHexagonCoord.x) 
{
    Vector2Int tempCoord = leftHexagonCoord;
    leftHexagonCoord = rightHexagonCoord;
    rightHexagonCoord = tempCoord;
} 

Then depending on if the lone hex is on top, we can determine which direction to rotate in order to rotation clockwise:

if (loneHexagonCoord.y > leftHexagonCoord.y)
{
    Hexagon tempHex = hexagonsArray[loneHexagonCoord.x, loneHexagonCoord.y];
    hexagonsArray[loneHexagonCoord.x, loneHexagonCoord.y] = 
            hexagonsArray[rightHexagonCoord.x, rightHexagonCoord.y];
    hexagonsArray[rightHexagonCoord.x, rightHexagonCoord.y] =  
            hexagonsArray[leftHexagonCoord.x, leftHexagonCoord.y];
    hexagonsArray[leftHexagonCoord.x, leftHexagonCoord.y] = tempHex;
}
else 
{
    Hexagon tempHex = hexagonsArray[loneHexagonCoord.x, loneHexagonCoord.y];
    hexagonsArray[loneHexagonCoord.x, loneHexagonCoord.y] =  
            hexagonsArray[leftHexagonCoord.x, leftHexagonCoord.y];
    hexagonsArray[leftHexagonCoord.x, leftHexagonCoord.y] =  
            hexagonsArray[rightHexagonCoord.x, rightHexagonCoord.y];
    hexagonsArray[rightHexagonCoord.x, rightHexagonCoord.y] = tempHex;
}

Then, update their HexCoordinates components on where they are:

hexagonsArray[loneHexagonCoord.x, loneHexagonCoord.y]
            .GetComponent<HexCoordinates>().Coordinates = new Vector2Int(
                loneHexagonCoord.x, loneHexagonCoord.y);

hexagonsArray[leftHexagonCoord.x, leftHexagonCoord.y]
            .GetComponent<HexCoordinates>().Coordinates = new Vector2Int(
                leftHexagonCoord.x, leftHexagonCoord.y);

hexagonsArray[rightHexagonCoord.x, rightHexagonCoord.y]
            .GetComponent<HexCoordinates>().Coordinates = new Vector2Int(
                rightHexagonCoord.x, rightHexagonCoord.y);

When I answered below, there was no indication that logic to select the 3 hexagons was already complete. I'm going to leave this up because it answers a very related question:


Well, we can divide the intersections of the hex grid into triangles, and pair them into parallelograms like so:

enter image description here

The Y coordinate of the parallelogram that a mouse position (in world space) is in is simply:

float pgYCoord = Mathf.Floor((startPos.y - mousePos.y) / (hexHeight * 0.75f));

The X coordinate of the parallelogram that a mouse position is in is more complicated:

float xOffsetAtMouseY =  startPos.x + hexWidth / 2f * (startPos.y - mousePos.y) / (hexHeight * 0.75f)
float pgXCoord = Mathf.Floor((mousePos.x - xOffsetAtMouseY) / hexWidth);

And then determine if the mouse in the A or the B triangle of that parallelogram:

float vertDistFromTopEdge = Mathf.Repeat(startPos.y-mousePos.y, hexHeight * 0.75f );
float horizDistFromTopLeftCorner = mousePos.x - startPos.x - pgXCoord*hexWidth - pgYCoord * hexWidth / 2f;

bool isInATriangle = 
        vertDistFromTopEdge 
        < 1.5f * hexHeight 
          - horizDistFromTopLeftCorner * (hexHeight * 0.75) / (hexWidth / 2f);

Then depending on if we're in an A triangle or not, we can determine the coordinates of the hexagons in clockwise order:

Vector2Int hexagonCoordA;
Vector2Int hexagonCoordB;
Vector2Int hexagonCoordC;

if (isInATriangle)
{
    hexagonCoordA = new Vector2Int(pgXCoord, pgYCoord);
    hexagonCoordB = new Vector2Int(pgXCoord+1, pgYCoord);
    hexagonCoordC = new Vector2Int(pgXCoord, pgYCoord+1);
} 
else 
{
    hexagonCoordA = new Vector2Int(pgXCoord, pgYCoord+1);
    hexagonCoordB = new Vector2Int(pgXCoord+1, pgYCoord);
    hexagonCoordC = new Vector2Int(pgXCoord+1, pgYCoord+1);
}

// every 2 rows, the pg x coord grows 1 additional higher than the hex x coord

hexagonCoordA.x += Mathf.Floor(0.5f*hexagonCoordA.y);
hexagonCoordB.x += Mathf.Floor(0.5f*hexagonCoordB.y);
hexagonCoordC.x += Mathf.Floor(0.5f*hexagonCoordC.y)

If any of the hexagonCoord variables have invalid indices (more appropriate in a separate question), then the mouse is not currently over an intersection of 3 hexagons. Otherwise, you can then swap the 3 hexagons.

int arrayXSize = hexagonArray.GetLength(0);
int arrayYSize = hexagonArray.GetLength(1);

if (   hexagonCoordA.x >= 0 && hexagonCoordA.x < arrayXSize 
    && hexagonCoordA.y >= 0 && hexagonCoordA.y < arrayYSize
    && hexagonCoordB.x >= 0 && hexagonCoordB.x < arrayXSize 
    && hexagonCoordB.y >= 0 && hexagonCoordB.y < arrayYSize
    && hexagonCoordC.x >= 0 && hexagonCoordC.x < arrayXSize 
    && hexagonCoordC.y >= 0 && hexagonCoordC.y < arrayYSize)
{

    Hexagon tempHex = hexagonsArray[hexagonCoordA.x, hexagonCoordA.y];
    hexagonsArray[hexagonCoordA.x, hexagonCoordA.y] =  
            hexagonsArray[hexagonCoordC.x, hexagonCoordC.y];
    hexagonsArray[hexagonCoordC.x, hexagonCoordC.y] =  
            hexagonsArray[hexagonCoordB.x, hexagonCoordB.y];
    hexagonsArray[hexagonCoordB.x, hexagonCoordB.y] = tempHex;


    Vector3 temp = hexagonA.transform.position;
    hexagonA.transform.position = hexagonB.transform.position;
    hexagonB.transform.position = hexagonC.transform.position;
    hexagonC.transform.position = temp;

}

Upvotes: 1

Daniel
Daniel

Reputation: 7724

This should do the job

void Rotate3Hexagons(GameObject hexagon1, GameObject hexagon2, GameObject hexagon3){
    Vector3 firstPos = hexagon1.transform.position;
    hexagon1.transform.position = hexagon2.transform.position;
    hexagon2.transform.position = hexagon3.transform.position;
    hexagon3.transform.position = firstPos;
}

In order to convert from world coordinates to grid coordinates, you need to set an inverse function for your CalcWorldPos function.

Vector2 CalcGridPos(Vector2 worldPos)
{
    float offset = 0;
    //the first thing to do is to decide if offset is 0 or hexWidth/2
    //I guess you can figure it out    
    Vector2 gridPos = new Vector2();
    gridPos.x = (worldPos.x - startPos.x - offset) / hexWidth;
    gridPos.y = (-worldPos.y + startPos.y) / hexHeight * 0.75f;

    return gridPos;
}

Upvotes: 1

Kjell Schwaricke
Kjell Schwaricke

Reputation: 129

if you just want to swap the positions between them its easy:

Vector3 tmpPos = hexagon1.transform.position; 
hexagon1.transform.position = hexagon2.transform.position;
hexagon2.transform.position = hexagon3.transform.position;
hexagon3.transform.position = tmpPos;

Upvotes: 0

Related Questions