Hex Worlds and a Mini-Catan Board#

A HexWorld consists of hexagonal tiles. Hexes are addressed with (column, row) coordinates, like tiles in a TiledWorld. Odd rows are shifted half a hex to the right.

Actors can be placed on three kinds of positions:

  • Tiles (the hexes themselves), e.g. (2, 3)

  • Corners (shared by up to three hexes), e.g. the "no" corner of a hex

  • Edges (shared by two hexes), e.g. the "o" edge of a hex

This is exactly the structure of a Catan board: land hexes, settlements on corners, and roads on edges.

Create a hex world#

import miniworlds

world = miniworlds.HexWorld(7, 7, tile_size=40)
world.background.grid = True
world.run()

Build a Catan-like board#

The 19 land hexes of a Catan board are arranged in rows of 3, 4, 5, 4, and 3 hexes. Actors placed on hexes are drawn as hexagons.

import miniworlds

world = miniworlds.HexWorld(7, 7, tile_size=40)
world.background.grid = True

land_positions = [
    (2, 1), (3, 1), (4, 1),
    (2, 2), (3, 2), (4, 2), (5, 2),
    (1, 3), (2, 3), (3, 3), (4, 3), (5, 3),
    (1, 4), (2, 4), (3, 4), (4, 4),
    (2, 5), (3, 5), (4, 5),
]
terrain_colors = [
    (0, 120, 0),      # forest
    (220, 180, 60),   # field
    (120, 200, 60),   # meadow
    (150, 150, 150),  # mountain
    (200, 90, 30),    # hill
    (230, 210, 160),  # desert
]

for number, position in enumerate(land_positions):
    actor = miniworlds.Actor(position)
    actor.fill_color = terrain_colors[number % len(terrain_colors)]
    actor.border = 1

world.run()

Click hexes, corners, and edges#

world.get_tile_from_pixel(mouse_pos) returns the hex under the mouse, world.get_corner_from_pixel(mouse_pos) the nearest corner, and world.get_edge_from_pixel(mouse_pos) the nearest edge. All three queries return None if the pixel is outside the world.

The example places a settlement (small circle) on the clicked corner and a road (small rectangle) on the clicked edge:

import miniworlds

world = miniworlds.HexWorld(7, 7, tile_size=40)
world.background.grid = True

@world.register
def on_mouse_left(self, mouse_pos):
    tile = world.get_tile_from_pixel(mouse_pos)
    if tile is None:
        return
    print("you clicked the hex", tile.position)

@world.register
def on_mouse_right(self, mouse_pos):
    corner = world.get_corner_from_pixel(mouse_pos)
    settlement = miniworlds.Actor(corner.position)
    settlement.fill_color = (200, 30, 30)
    settlement.size = (0.3, 0.3)

world.run()

Query the neighborhood#

world.get_tiles_in_radius(position, radius) returns all hexes within a given hex distance. tile.get_neighbour_tiles() returns the up to six neighbors of a hex. This is useful for Catan rules such as “the robber blocks all hexes around the desert”.

import miniworlds

world = miniworlds.HexWorld(7, 7, tile_size=40)
world.background.grid = True

center = world.get_tile((3, 3))
for tile in world.get_tiles_in_radius(center.position, 1):
    actor = miniworlds.Actor(tile.position)
    actor.fill_color = (0, 120, 0)

world.run()