def create_torus(width=1, height=None): """ Returns a mapping of boards containing width * height threeboards connected in a torus with corresponding hexagonal coordinates. If height is not specified, height = width. """ height = width if height is None else height boards = {} # Create the boards for coord in threeboards(width, height): boards[coordinates.Hexagonal(*coord)] = Board() # Link the boards together for coord in boards: for direction in [ Direction.east, Direction.north_east, Direction.north ]: # Get the coordinate of the neighbour in each direction n_coord = wrap_around(add_direction(list(coord) + [0], direction), (width, height)) # Connect the boards together boards[coord].connect_wire(boards[n_coord], direction) return [(b, c) for (c, b) in iteritems(boards)]
def test_hexagonal(): a = coordinates.Hexagonal(1, 2, 3) b = coordinates.Hexagonal(-1, -1, -1) # Should always equal their equivilent tuples assert a == (1, 2, 3) assert b == (-1, -1, -1) # Basic operators assert a + b == (0, 1, 2) assert a - b == (2, 3, 4) assert abs(b) == (1, 1, 1) # Magnitude assert a.magnitude() == 2 assert b.magnitude() == 0
def add_direction(vector, direction): """ Returns the vector moved one unit in the given direction. """ return coordinates.Hexagonal(*(v + a for (v, a) in zip(vector, direction.vector)))
def threeboards(width=1, height=None): r""" Generates a list of width x height threeboards. If height is not specified, height = width. Width defaults to 1. Coordinates are given as (x,y,0) tuples on a hexagonal coordinate system like so:: | y | / \ z / \ x A threeboard looks like so:: ___ / 1 \___ \___/ 2 \ / 0 \___/ \___/ With the bottom-left hexagon being at (0,0). And is tiled in to long rows like so:: ___ ___ ___ ___ / 0 \___/ 1 \___/ 2 \___/ 3 \___ \___/ 0 \___/ 1 \___/ 2 \___/ 3 \ / 0 \___/ 1 \___/ 2 \___/ 3 \___/ \___/ \___/ \___/ \___/ And into a mesh like so:: ___ ___ ___ ___ / 4 \___/ 5 \___/ 6 \___/ 7 \___ \___/ 4 \___/ 5 \___/ 6 \___/ 7 \ / 4 \___/ 5 \___/ 6 \___/ 7 \___/ \___/ 0 \___/ 1 \___/ 2 \___/ 3 \___ \___/ 0 \___/ 1 \___/ 2 \___/ 3 \ / 0 \___/ 1 \___/ 2 \___/ 3 \___/ \___/ \___/ \___/ \___/ """ height = width if height is None else height # Create the boards for y in range(height): for x in range(width): # z is the index of the board within the set. 0 is the bottom left, 1 is # the top, 2 is the right for z in range(3): # Offset within threeboard --+ # Y offset ---------+ | # X offset -+ | | # | | | x_coord = (x * 2) + (-y) + (z >= 2) y_coord = (x) + (y) + (z >= 1) yield coordinates.Hexagonal(x_coord, y_coord, 0)
def board_to_chip(coords, layers=4): """ Convert a hexagonal board coordinate into a hexagonal chip coordinate for the chip at the bottom-left of a board that size. """ x, y = hex_to_skewed_cartesian(coords) x *= layers y *= layers return coordinates.Hexagonal(x, y, 0)
def wrap_around(coord, bounds): """ Wrap the coordinate given around the edges of a torus made of hexagonal pieces. Assumes that the world is a NxM arrangement of threeboards (see threeboards function) with bounds = (N, M). XXX: Implementation could be nicer (and non iterative)... """ w, h = bounds x, y = to_xy(coord) assert (w > 0) assert (h > 0) while True: # Where is the coordinate relative to the world left = x + y < 0 right = x + y >= w * 3 below = (2 * y) - x < 0 above = (2 * y) - x >= h * 3 if below and left: x += 1 + (w - 1) * 2 - (h - 1) y += 2 + (w - 1) + (h - 1) continue if above and right: x -= 1 + (w - 1) * 2 - (h - 1) y -= 2 + (w - 1) + (h - 1) continue if left: x += w * 2 y += w continue if right: x -= w * 2 y -= w continue if below: x -= h y += h continue if above: x += h y -= h continue break return coordinates.Hexagonal(x, y, 0)
def to_shortest_path(vector): """ Converts a vector into the shortest-path variation. A shortest path has at least one dimension equal to zero and the remaining two dimensions have opposite signs (or are zero). """ assert (len(vector) == 3) # The vector (1,1,1) has distance zero so this can be added or subtracted # freely without effect on the destination reached. As a result, simply # subtract the median value from all dimensions to yield the shortest path. median = median_element(vector) return coordinates.Hexagonal(*(v - median for v in vector))
def test___repr__(): # Make sure the generic repr implementation uses the correct name and lists # all dimensions in the correct order. assert repr(coordinates.Hexagonal(1, 2, 3)) == "Hexagonal(1, 2, 3)" assert repr(coordinates.Cartesian2D(1, 2)) == "Cartesian2D(1, 2)"