Bees make honeycombs of hexagonal wax cells. The shape of the cells provides a highly efficient layout, increases strength and reduces the amount of wax required to produce a robust structure. As a result, the available space is used in an optimal way for storing honey and energy is saved in wax production, because the production of one kilogram of wax costs four to six kilos of honey.

honeycomb
Honeycomb with eggs and larvae.
chicken wire
Chicken wire fencing.
graphene
Graphene is an atomic-scale hexagonal lattice made of carbon atoms.
nanotube
A carbon nanotube can be seen as a hexagon tiling on a cylindrical surface.
kitchen wall
Kitchen wall covered with hexagonal tiles.

In nature, hexagonal structures also exists in the form of graphite, where each sheet of graphene resembles chicken wire, with strong covalent carbon bonds. Tubular graphene sheets called carbon nanotubes are also being synthesized. They have many potential applications, due to their high tensile strength and electrical properties.

The beauty of nature is also mimicked indoors, where mosaic patterns of hexagon tiles add unique character and geometric elegance to kitchens, bathrooms, living rooms and bedrooms. Offering a timeless finish, these versatile tiles seamlessly complement subtle and bold interiors alike, making them an increasing popular walling and flooring option for a multitude of interior environments.

Assignment

To describe patterns in grids of hexagonal cells, we need a coordinate system that uniquely determines the position of each cell. We consider grids in which the hexagons are pointing up and use an axial coordinate system. In it, the position of each cell is indicated by a pair of coordinates $$(q, r)$$, with $$q, r \in \mathbb{N}$$.

Each hexagonal cell has six neighbors that are east (E), southeast (SE), southwest (SW), west (W), northwest (NW) and northeast (NE) of the cell. The directions of these six neighbors are indicated by strings (str) with one or two uppercase letters, as shown in the preceding listing. This is the relationship between the axial coordinates $$(q, r)$$ of a cell an the axial coordinates of its six neighbors:

axial coordinate system
Relationship between the axial coordinates $$(q, r)$$ of a cell and the axial coordinates of its six neighbors.

If we choose a reference cell with axial coordinates $$(0, 0)$$ in a grid of hexagonal cells, the axial coordinates of its surrounding cells are:

axial coordinates
Axial coordinates of a reference cell at position $$(0, 0)$$ and its surrounding cells.

The distance between a hexagon $$h$$ with coordinates $$(q, r)$$ and a hexagon $$\bar{h}$$ with coordinates $$(\bar{q}, \bar{r})$$ is defined as the minimal number of steps to neighboring cells needed to go from cell $$h$$ to cell $$\bar{h}$$. This distance is computed as \[ \frac{1}{2}(|q - \bar{q}| + |r - \bar{r}| + |q + r - \bar{q} - \bar{r}|) \] where $$|x|$$ represents the absolute value of $$x$$.

Define a class Hexagon that can be used to represent hexagonal cells (pointing up) in a grid with an axial coordinate system. When creating a hexagon (Hexagon), the coordinates $$q$$ (int) and $$r$$ (int) of the cell must be passed. Hexagons are immutable.

If a hexagon (Hexagon) is passed to the built-in function str, a description (str) of the position of the hexagon must be returned. If a hexagon (Hexagon) is passed to the built-in function repr, a string representation (str) must be returned that reads as a Python expression to create a new hexagon (Hexagon) at the same position as the hexagon passed to the function repr.

To enable adding hexagons (Hexagon) to sets (set), the built-in function hash must return the hash value of hexagons and the operator == must determine if two hexagons are equal. Make sure a hexagon (Hexagon) with coordinates $$(q, r)$$ has the same hash value as a tuple $$(q, r)$$. Make sure that two hexagons (Hexagon) are equal if and only if they are at the same position in the grid.

In addition, it should be possible to call at least the following methods on a hexagon $$h$$ (Hexagon):

Example

>>> tile = Hexagon(0, 0)
>>> tile
Hexagon(0, 0)
>>> print(tile)
(0, 0)
>>> tile.distance(Hexagon(4, 3))
7

>>> tile.neighbor('E').neighbor('SE').neighbor('NE').neighbor('E')
Hexagon(3, 0)
>>> tile.neighbor('NW').neighbor('W').neighbor('SW').neighbor('E').neighbor('E')
Hexagon(0, 0)
>>> tile.path('ESENEE')
Hexagon(3, 0)
>>> tile.path('NWWSWEE')
Hexagon(0, 0)

>>> tile.path('ESENEE') == tile
False
>>> tile.path('NWWSWEE') == tile
True

>>> hash(tile)
3713080549408328131

>>> tile.neighbors()
{Hexagon(0, 1), Hexagon(-1, 1), Hexagon(-1, 0), Hexagon(0, -1), Hexagon(1, 0), Hexagon(1, -1)}