메모리에서 16 진수 / 16 진수 그리드를 어떻게 표현하나요?


119

Settlers of Catan 과 같이 육각 격자로 보드 게임을 만들고 있다고 가정 해 보겠습니다 .

imgur.com에서 호스팅

각 정점과 모서리에는 속성 (위의 도로 및 정착지)이있을 수 있습니다.

이 보드를 나타내는 데이터 구조를 어떻게 만들 수 있습니까? 각 타일의 이웃, 가장자리 및 정점에 액세스하기위한 패턴은 무엇입니까?


hilbert 곡선을 사용할 수도 있습니다. 평면의 인접성이 선형 인코딩으로 유지되도록 간격을 두는 파일링 곡선입니다. 공간 인덱싱과 이것이 어떻게 사용되는지 확인하십시오! v 흥미로운
pbordeaux

답변:


156

Amit Patel 은이 주제에 대한 놀라운 페이지를 게시했습니다 . 너무 포괄적이고 훌륭 해서이 질문에 대한 확실한 답이 필요합니다. 육각 격자

Cubez


27
감사합니다 :) 그 페이지는 가장자리와 꼭지점을 다루지 않지만, 내 그리드 기사의 파트 간 관계 섹션 ( www-cs-students.stanford.edu/~amitp/game-programming/grids) 에서 다룹니다 (다이어그램은 정사각형 그리드의 경우 표에는 축 육각 그리드의 공식도 포함되어 있습니다.)
amitp

18

이러한 그리드는 2 차원 배열로 표현할 수 있습니다.

만약

   2
7     3
   1   
6     4
   5

헥스 그리드에서 이웃이있는 숫자 1이면 다음과 같이 2D 배열에 넣을 수 있습니다.

2 3
7 1 4
  6 5

분명히 인접성은 수평 또는 수직으로 인접 할뿐만 아니라 하나의 대각선을 사용하여이 그리드에서 결정됩니다.

그래도 원하는 경우 그래프를 사용할 수 있습니다.


멋있는. 모서리와 꼭지점에 대한 데이터는 어떻습니까?
유료 괴짜

1
나는 아마 그것들을 따로 보관할 것입니다. 주로 타일을 보든 가장자리 / 정점을 보든 관계없이 데이터의 나머지 절반은 저장하기에 고통 스럽거나 중복됩니다.
Joey

"유료 괴상한"답변에서 Amit Patel의 기사를 참조하십시오.
aredridel 2013-06-03

11

이 기사에서는 Isomeric / Hexagonal 그리드 게임을 설정하는 방법을 설명합니다. Forcing Isometric and Hexagonal Maps onto a Rectangular Grid섹션과 이동 섹션을 살펴 보시기 바랍니다 . 찾고있는 것과는 다르지만 원하는 작업을 수행하는 방법을 공식화하는 데 도움이 될 수 있습니다.


2

나는 헥스를 많이 다루었습니다. 이와 같은 경우에는 16 진수의 경계에 대해 6 개 지점을 각각 추적합니다. 이렇게하면 아주 쉽게 그릴 수 있습니다.

헥스를 나타내는 단일 객체 배열이 있습니다. 이러한 각 16 진수 개체에는 "측면"의 다른 배열을 가리키는 6 개의 "포인터"(또는 다른 배열에 대한 인덱스)도 있습니다. "정점"도 마찬가지입니다. 물론 정점에는 인접한 헥스에 대한 3 개의 포인터가 있고 측면에는 2 개의 포인터가 있습니다.

따라서 16 진수는 X, Y, Point (6), Vertices (6), Sides (6)와 같을 수 있습니다.

그런 다음 Hex 배열, 정점 배열 및 측면 배열이 있습니다.

그런 다음 16 진수에 대한 정점 / 측면을 찾는 것은 매우 간단합니다.

내가 포인터를 말할 때 그것은 vertice 또는 side array 또는 무엇이든간에 요소를 가리키는 정수가 될 수 있습니다. 그리고 물론 배열은 목록 등이 될 수 있습니다.


0
   2
7     3
   1   
6     4
   5

지도의 행을 '평평하게'할 수도 있습니다. 이 예에서는 다음과 같습니다.

  2
7 1 3
6 5 4

한 행에 행을 갖는 것이 때때로 더 유용합니다.


1
예를 들어 1과 6은 이웃이지만 3과 5는 그렇지 않지만 상대적 위치가 동일하기 때문에 이것은 지저분한 이웃 검사 코드를 가질 수 있습니다.
베른하르트 바커

0

다음과 같은 것을 제안합니다 (델파이 스타일 선언을 사용합니다).

type
  THexEdge = record
    Hexes: array[1..2] of Integer; // Index of adjoining hexes.
    // Other edge stuff goes here.
  end;

  THexVertex = record
    Hexes: array[1..3] of Integer; // Index of adjoining hexes.
    // Other vertex stuff goes here.
  end;

  THex = record
    Edges: array[1..6] of Integer; // Index of edge.
    Vertices: array[1..6] of Integer; // Index of vertex.
    // Other hex stuff goes here.
  end;

var
  Edges: array of THexEdge;
  Vertices: array of THexVertex;
  HexMap: array of THex;

각 16 진수에는 6 개의 모서리와 6 개의 정점이 있습니다. 각 가장자리는 인접한 두 개의 헥스를 추적하고 각 정점은 인접한 세 개의 헥스를 추적합니다 (맵 가장자리의 헥스는 특별한 경우입니다).

물론 다른 방식으로 할 수있는 일이 많이 있습니다. 배열보다는 포인터를 사용할 수 있고, 레코드보다는 객체를 사용할 수 있으며, 다른 응답자가 제안한대로 헥스를 2 차원 배열에 저장할 수 있습니다.

바라건대, 그것에 접근하는 한 가지 방법에 대한 아이디어를 얻을 수 있습니다.


0

우리는 클래스 프로젝트를 위해 Settlers of Catan AI를 구현 하고이 답변 (버그가 많음)의 코드를 수정 하여 정점과 가장자리에 대한 일정한 시간 랜덤 액세스 권한이있는 보드를 만들었습니다. 재미있는 문제 였지만 보드는 많은 시간이 걸렸기 때문에 누군가가 여전히 간단한 구현을 찾고 있다면 Python 코드가 있습니다.

class Board:
  # Layout is just a double list of Tiles, some will be None
  def __init__(self, layout=None):
    self.numRows = len(layout)
    self.numCols = len(layout[0])
    self.hexagons = [[None for x in xrange(self.numCols)] for x in xrange(self.numRows)] 
    self.edges = [[None for x in xrange(self.numCols*2+2)] for x in xrange(self.numRows*2+2)] 
    self.vertices = [[None for x in xrange(self.numCols*2+2)] for x in xrange(self.numRows*2+2)] 
    for row in self.hexagons:
      for hexagon in row:
        if hexagon == None: continue
        edgeLocations = self.getEdgeLocations(hexagon)
        vertexLocations = self.getVertexLocations(hexagon)
        for xLoc,yLoc in edgeLocations:
          if self.edges[xLoc][yLoc] == None:
            self.edges[xLoc][yLoc] = Edge(xLoc,yLoc)
        for xLoc,yLoc in vertexLocations:
          if self.vertices[xLoc][yLoc] == None:
            self.vertices[xLoc][yLoc] = Vertex(xLoc,yLoc)

  def getNeighborHexes(self, hex):
    neighbors = []
    x = hex.X
    y = hex.Y
    offset = 1
    if x % 2 != 0:
      offset = -1

    if (y+1) < len(self.hexagons[x]):
      hexOne = self.hexagons[x][y+1]
      if hexOne != None: neighbors.append(hexOne)
    if y > 0:
      hexTwo = self.hexagons[x][y-1]
      if hexTwo != None: neighbors.append(hexTwo)
    if (x+1) < len(self.hexagons):
      hexThree = self.hexagons[x+1][y]
      if hexThree != None: neighbors.append(hexThree)
    if x > 0:
      hexFour = self.hexagons[x-1][y]
      if hexFour != None: neighbors.append(hexFour)
    if (y+offset) >= 0 and (y+offset) < len(self.hexagons[x]):
      if (x+1) < len(self.hexagons):
        hexFive = self.hexagons[x+1][y+offset]
        if hexFive != None: neighbors.append(hexFive)
      if x > 0:
        hexSix = self.hexagons[x-1][y+offset]
        if hexSix != None: neighbors.append(hexSix)
    return neighbors

  def getNeighborVertices(self, vertex):
    neighbors = []
    x = vertex.X
    y = vertex.Y
    offset = -1
    if x % 2 == y % 2: offset = 1
    # Logic from thinking that this is saying getEdgesOfVertex
    # and then for each edge getVertexEnds, taking out the three that are ==vertex
    if (y+1) < len(self.vertices[0]):
      vertexOne = self.vertices[x][y+1]
      if vertexOne != None: neighbors.append(vertexOne)
    if y > 0:
      vertexTwo = self.vertices[x][y-1]
      if vertexTwo != None: neighbors.append(vertexTwo)
    if (x+offset) >= 0 and (x+offset) < len(self.vertices):
      vertexThree = self.vertices[x+offset][y]
      if vertexThree != None: neighbors.append(vertexThree)
    return neighbors

  # used to initially create vertices
  def getVertexLocations(self, hex):
    vertexLocations = []
    x = hex.X
    y = hex.Y
    offset = x % 2
    offset = 0-offset
    vertexLocations.append((x, 2*y+offset))
    vertexLocations.append((x, 2*y+1+offset))
    vertexLocations.append((x, 2*y+2+offset))
    vertexLocations.append((x+1, 2*y+offset))
    vertexLocations.append((x+1, 2*y+1+offset))
    vertexLocations.append((x+1, 2*y+2+offset))
    return vertexLocations

  # used to initially create edges
  def getEdgeLocations(self, hex):
    edgeLocations = []
    x = hex.X
    y = hex.Y
    offset = x % 2
    offset = 0-offset
    edgeLocations.append((2*x,2*y+offset))
    edgeLocations.append((2*x,2*y+1+offset))
    edgeLocations.append((2*x+1,2*y+offset))
    edgeLocations.append((2*x+1,2*y+2+offset))
    edgeLocations.append((2*x+2,2*y+offset))
    edgeLocations.append((2*x+2,2*y+1+offset))
    return edgeLocations

  def getVertices(self, hex):
    hexVertices = []
    x = hex.X
    y = hex.Y
    offset = x % 2
    offset = 0-offset
    hexVertices.append(self.vertices[x][2*y+offset]) # top vertex
    hexVertices.append(self.vertices[x][2*y+1+offset]) # left top vertex
    hexVertices.append(self.vertices[x][2*y+2+offset]) # left bottom vertex
    hexVertices.append(self.vertices[x+1][2*y+offset]) # right top vertex
    hexVertices.append(self.vertices[x+1][2*y+1+offset]) # right bottom vertex
    hexVertices.append(self.vertices[x+1][2*y+2+offset]) # bottom vertex
    return hexVertices

  def getEdges(self, hex):
    hexEdges = []
    x = hex.X
    y = hex.Y
    offset = x % 2
    offset = 0-offset
    hexEdges.append(self.edges[2*x][2*y+offset])
    hexEdges.append(self.edges[2*x][2*y+1+offset])
    hexEdges.append(self.edges[2*x+1][2*y+offset])
    hexEdges.append(self.edges[2*x+1][2*y+2+offset])
    hexEdges.append(self.edges[2*x+2][2*y+offset])
    hexEdges.append(self.edges[2*x+2][2*y+1+offset])
    return hexEdges

  # returns (start, end) tuple
  def getVertexEnds(self, edge):
    x = edge.X
    y = edge.Y
    vertexOne = self.vertices[(x-1)/2][y]
    vertexTwo = self.vertices[(x+1)/2][y]
    if x%2 == 0:
      vertexOne = self.vertices[x/2][y]
      vertexTwo = self.vertices[x/2][y+1]
    return (vertexOne, vertexTwo)

  def getEdgesOfVertex(self, vertex):
    vertexEdges = []
    x = vertex.X
    y = vertex.Y
    offset = -1
    if x % 2 == y % 2: offset = 1
    edgeOne = self.edges[x*2][y-1]
    edgeTwo = self.edges[x*2][y]
    edgeThree = self.edges[x*2+offset][y]
    if edgeOne != None: vertexEdges.append(edgeOne)
    if edgeTwo != None: vertexEdges.append(edgeTwo)
    if edgeThree != None: vertexEdges.append(edgeThree)
    return vertexEdges

  def getHexes(self, vertex):
    vertexHexes = []
    x = vertex.X
    y = vertex.Y
    xOffset = x % 2
    yOffset = y % 2

    if x < len(self.hexagons) and y/2 < len(self.hexagons[x]):
      hexOne = self.hexagons[x][y/2]
      if hexOne != None: vertexHexes.append(hexOne)

    weirdX = x
    if (xOffset+yOffset) == 1: weirdX = x-1
    weirdY = y/2 
    if yOffset == 1: weirdY += 1
    else: weirdY -= 1
    if weirdX >= 0 and weirdX < len(self.hexagons) and weirdY >= 0 and weirdY < len(self.hexagons):
      hexTwo = self.hexagons[weirdX][weirdY]
      if hexTwo != None: vertexHexes.append(hexTwo)

    if x > 0 and x < len(self.hexagons) and y/2 < len(self.hexagons[x]):
      hexThree = self.hexagons[x-1][y/2]
      if hexThree != None: vertexHexes.append(hexThree)

    return vertexHexes

이 대답은 끔찍합니다. 아무것도 설명하지 않고 수많은 코드를 붙여 넣었습니다 (코드 작성자 제외). 여기에서 괜찮 았더라도 코드 자체는 끔찍합니다. 독 스트링이없고, 주석이 거의 없으며, 포함 된 주석은 이해할 수 없습니다 (논리가 이것이 getEdgesOfVertex라고 생각한 다음 각 에지에 대해 getVertexEnds, == vertex 인 3 개를 제거함).
칼 스미스

0

나는 여기에 hexes와 함께 "재미를 위해 코딩하는 나의 자유 시간"에 앉아있다. 그리고 이렇게됩니다 ... 말로 어떻게 생겼는지 말씀 드리겠습니다.

  1. 육각형 : 6 개의 이웃 육각형이 있습니다. 인접한 각 헥스 타일에 대한 참조를 전달할 수 있습니다. 구성 요소 (물, 바위, 먼지)를 알려줍니다. 다른 사람과 연결될 수 있으며 그 반대의 경우도 마찬가지입니다. 심지어 그를 둘러싼 다른 사람들을 자동으로 연결하여 더 큰 필드를 만들거나 모든 필드가 이웃에 의해 지정 될 수 있도록 할 수도 있습니다.
  2. 건물은 최대 3 개의 도로와 3 개의 육각 타일을 참조합니다. 그들은 그들이 무엇인지 말할 수 있습니다.
  3. 도로는 인접한 타일로 주소가 지정 될 때 두 개의 헥스와 다른 도로를 참조합니다. 그들은 어떤 타일이 있고 어떤 도로 또는 건물에 연결되는지 알 수 있습니다.

이것은 내가 어떻게 작업 할 것인지에 대한 아이디어입니다.


0

2D 배열을 만든 다음 유효한 위치를 다음과 같이 고려할 수 있습니다.

  • 짝수 행 (0,2,4, ...) : 홀수 셀.
  • 홀수 행 (1,3,5, ...) : 짝수 셀.

각 셀의 이웃은 다음과 같습니다.

  • 같은 열, 2 행 위로
  • 같은 열, 아래로 2 행
  • 1 개 남음 + 1 개 위로
  • 1 개 남음 + 1 개 아래로
  • 오른쪽 1 개 + 위쪽 1 개
  • 오른쪽 1 개 + 아래쪽 1 개

삽화: Hex Grid

x 표시는 육각형입니다. 서로 대각선 인 x는 이웃입니다. | 수직 이웃을 연결합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.