如何在内存中表示一个六进制/hex网格?

假设我正在用一个六边形网格来构build一个棋盘游戏,比如卡坦的定居者

由imgur.com主办

请注意,每个顶点和边可能有一个属性(上面的道路和结算)。

我将如何build立一个代表这个板子的数据结构? 访问每个瓦片的邻居,边缘和顶点的模式是什么?

阿米特·帕特尔(Amit Patel)在这个话题上发表了一篇非常棒 它是如此全面而精彩,它需要成为这个问题的明确答案: 六边形网格

cubez

这样的网格可以用二维数组表示:

如果

2 7 3 1 6 4 5 

是它的邻居在hex网格中的头号,那么你可以把它放到一个二维数组,如下所示:

 2 3 7 1 4 6 5 

显然,在这个网格中邻近性不仅是水平或垂直相邻,而且也是使用一个对angular线。

不过,如果你喜欢,也可以使用图表。

本文将通过如何build立一个异构/六边形网格游戏。 我build议你看看Forcing Isometric and Hexagonal Maps onto a Rectangular Grid部分和运动部分。 虽然它与你正在寻找的不同,但它可能会帮助你制定如何做你想做的事情。

我已经处理了很多问题。 在这种情况下,您可以跟踪hex边界的6个点中的每一个。 这让你很容易画出来。

你将有一个单一的数组代表对象的对象。 每个这些hex对象也有6个“指针”(或另一个数组的索引)指向另一个“边”arrays。 同样的事情“顶点”。 当然,顶点会有3个指向相邻的六边形的指针,而边将有2个指针。

所以,hex可能是这样的:X,Y,Point(6),Vertices(6),Sides(6)

然后你有一个hex数组,顶点数组和边数组。

然后,findhex的顶点/边,或者其他任何东西都很简单。

当我说指针时,它可以很容易地是一个指向vertice或side数组中元素的整数。 当然,数组可以是列表或其他。

我们为一个类项目实现了一个Catan AI定居者,并且从这个答案中修改了代码(这是错误的),以创build一个具有恒定时间随机访问顶点和边的板。 这是一个有趣的问题,但董事会花了很多时间,所以如果有人仍然在寻找一个简单的实现,这里是我们的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 
  2 7 3 1 6 4 5 

您也可以尝试“平放”您的地图的行。 对于这个例子,它将是:

  2 7 1 3 6 5 4 

有时在一行中有行更有用:P

我会build议像下面这样(我将使用Delphi风格的声明):

 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; 

每个hex有六个边和六个顶点。 每条边都跟踪它的两个相邻的格,每个顶点跟踪它的三个相邻的格(地图边上的格是特殊情况)。

有很多事情你可以做一个不同的方式,当然。 你可以使用指针而不是数组,你可以使用对象而不是logging,并且可以像其他答案者所build议的那样,将你的数据库存储在一个二维数组中。

希望这可能会给你一些想办法的方法。