Voronchuk / hexagons / Hexagons.Hex

We treat Cube and Axial systems separately. Cube coordinates are a plane in x,y,z space, where x+y+z = 0. Axial coordinates have two axes q,r that are 60° or 120° apart.

See http://www.redblobgames.com/grids/hexagons/implementation.html

Types


type Hex
    = FloatCubeHex FloatCubeCoords
    | IntCubeHex IntCubeCoords
    | AxialHex AxialCoords

Generic hex field definition


type Direction
    = NE
    | E
    | SE
    | SW
    | W
    | NW

Direction ranges from 0 to 5 by sides of the hexagon, we use North, South, West, East definitions for simplicity

Helpers

q : Hex -> Basics.Float

Get q coordinate for Hex as Float value

q IntCubeHex ( 2, 3, -5 ) == 2.0

intQ : Hex -> Basics.Int

Get q coordinate for Hex as Int value, its generally not recommended to use on FloatCubeHex

intQ IntCubeHex ( 2, 3, -5 ) == 2

r : Hex -> Basics.Float

Get r coordinate for Hex as Float value

r IntCubeHex ( 2, 3, -5 ) == 3.0

intR : Hex -> Basics.Int

Get r coordinate for Hex as Int value, its generally not recommended to use on FloatCubeHex

intR IntCubeHex ( 2, 3, -5 ) == 3

s : Hex -> Basics.Float

Get s coordinate for Hex as Float value

s IntCubeHex ( 2, 3, -5 ) == -5.0

intS : Hex -> Basics.Int

Get s coordinate for Hex as Int value, its generally not recommended to use on FloatCubeHex

intS IntCubeHex ( 2, 3, -5 ) == 3

intFactory : ( Basics.Int, Basics.Int ) -> Hex

Build Hex object from Int coordinates

intFactory ( 2, 3 )
    |> eq (IntCubeHex ( 2, 3, -5 ))

floatFactory : ( Basics.Float, Basics.Float ) -> Hex

Build Hex object from Float coordinates

floatFactory ( 2.5, 3.5 )
    |> eq (FloatCubeHex ( 2.5, 3.5, -6.0 ))

toIntHex : Hex -> Hex

Convert Hex to IntCubeHex coordinate systems

FloatCubeHex ( 2.5, 3.5, -6.0 )
    |> toIntHex
    |> eq (IntCubeHex ( 2, 4, -6 ))

toFloatHex : Hex -> Hex

Convert Hex to FloatCubeHex coordinate systems

IntCubeHex ( 2, 3, -5 )
    |> toFloatHex
    |> eq (FloatCubeHex ( 2.0, 3.0, -5.0 ))

Equality

eq : Hex -> Hex -> Basics.Bool

Compare two Hex definitions, support both axial and cubic coordinates.

Not a strict comparation, FloatCubeHex is converted to IntCubeHex.

IntCubeHex ( 2, 3, -5 )
    |> eq (IntCubeHex ( 2, 3, -5 ))

AxialHex ( 2, 3 )
    |> eq (AxialHex ( 2, 3 ))

noteq : Hex -> Hex -> Basics.Bool

Compare two Hex definitions, if they are not equal, inversion of eq

IntCubeHex ( 2, 3, -5 )
    |> noteq (IntCubeHex ( 1, 1, -2 ))

AxialHex ( 2, 3 )
    |> noteq (AxialHex ( 2, 1 ))

Coordinate arithmetic

add : Hex -> Hex -> Hex

Since cube coordinates come from 3d cartesian coordinates, I automatically get things like addition, subtraction, multiplication, and division. For example, you can have Hex(2, 0, -2) that represents two steps northeast, and add that to location Hex(3, -5, 2) the obvious way: Hex(2 + 3, 0 + -5, -2 + -2). With other coordinate systems like offset coordinates, you can’t do that and get what you want. These operations are just what you’d implement with 3d cartesian vectors, but I am using q, r, s names in this class instead of x, y, z

IntCubeHex ( 2, 3, -5 )
    |> add (IntCubeHex ( 1, 2, -3 ))
    |> eq (IntCubeHex ( 3, 5, -8 ))

sub : Hex -> Hex -> Hex

Subtraction of Hexes, more info in sum description

IntCubeHex ( 1, 2, -3 )
    |> sub (IntCubeHex ( 2, 3, -5 ))
    |> eq (IntCubeHex ( 1, 1, -2 ))

mul : Basics.Int -> Hex -> Hex

Multiplication of Hexes, more info in sum description

IntCubeHex ( 2, 3, -5 )
    |> mult 5
    |> eq (IntCubeHex ( 10, 15, -25 ))

Distance

length : Hex -> Basics.Int

Length of Hex.

length (IntCubeHex ( 2, 3, -5 )) == 5

length (FloatCubeHex ( 2.2, 3.3, -5.5 )) == 5

distance : Hex -> Hex -> Basics.Int

The distance between two hexes is the length of the line between them.

distance (IntCubeHex ( 2, 3, -5 )) (FloatCubeHex ( 3.2, 4.3, -7.5 )) == 2

Neighbors

direction : Direction -> Hex

Direction relative to Hex polygon lines, we used shortcuts for the mix of North, East, South, West directions

neighbor : Hex -> Direction -> Hex

With distance, we defined two functions: length works on one argument and distance works with two. The same is true with neighbors. The direction function is with one argument and the neighbor function is with two.

neighbor (IntCubeHex ( 2, 3, -5 )) NW
    |> eq (IntCubeHex ( 2, 4, -6 ))