Source

hexbattle / hexgrid.py

#!/usr/bin/env python2
# encoding: utf-8

"""Functions for working with a hexgrid."""

def coordinate_to_hexgrid(x, y, hex_width=72):
    """turn a coordinate into a hexgrid position.

    see
    
    - http://www-cs-students.stanford.edu/~amitp/Articles/Hexagon1.html
    
    Adapted to this numbering scheme: 
       _______     ______
      /|   \ |    /|   \ |
     / |01  \|_____|20  \|
     \ |    /|   \ |    /|
      \|___/_|10  \|___/_|
      /|   \ |    /|   \ |
     / |00  \|___/_|2-1 \|
     \ |    /|   \ |    /|
      \|___/_|    \|___/_|

    Known bug (rounding error): coordinate_to_hexgrid(54.0, 0.0, 72) should give (1, -1), but gives (0, 0).

    Alternative: http://www-cs-students.stanford.edu/~amitp/Articles/Hexagon2.html

    ⇒ z = -(x+y) # “convert” from mine to his (add another axis, 120° to the others). 
      distance(hex1, hex2) = 0.5*(abs(hex1.x-hex2.x)+abs(hex1.y-hex2.y)+abs(hex1.z-hex2.z))

    >>> c2h = coordinate_to_hexgrid
    >>> hw = 72
    >>> # center of the zeroes hex
    >>> c2h(36.0, 36.0, hw)
    (0, 0)
    >>> c2h(36.0, 71.0, hw)
    (0, 0)
    >>> c2h(36.0, 72.0, hw)
    (0, 1)
    >>> c2h(36.0, 648.0, hw)
    (0, 9)
    >>> c2h(53.0, 71.0, hw)
    (0, 0)
    >>> c2h(55.0, 71.0, hw)
    (1, 0)
    >>> c2h(55.0, 73.0, hw)
    (1, 0)
    >>> known_bug = c2h(54.0, 0.0, hw)
    >>> known_bug == (1, -1)
    False
    >>> known_bug == (0, 0)
    True
    >>> c2h(54.1, 0.0, hw)
    (1, -1)
    >>> c2h(73.0, -35.0, hw)
    (1, -1)
    >>> known_bug = c2h(54.0, 36.0, hw) # known bug, should be (1, -1)
    >>> known_bug == (1, -1)
    False
    >>> known_bug == (0, 0)
    True
    >>> c2h(73.0, 36.0, hw)
    (1, 0)
    """
    if hex_width%4:
        raise ValueError("Currently this code can only handle hex_width with divisor 4")
    # adapt the algorithm to start at the leftmost part of the image, not at the bottom left.
    x -= 0.25 * hex_width
    # guess the hex, but ignore the edges.
    #: The x value in the hex grid. 
    tx = int(x/(0.75*hex_width))
    rx = x%int(0.75*hex_width)
    y += tx * hex_width/2
    #: The y value in the hex grid. 
    ty = int(y/hex_width)
    ry = y%hex_width
    rx = int(0.75*hex_width - rx)
    ry -= hex_width/2
    # fix the edges. 
    if hex_width/2 * ry > rx*hex_width:
        tx += 1
        ty += 1
    if hex_width/2 * ry < -rx*hex_width:
        tx += 1
    # adapt the algorithm to have the x axis pointing right upwards
    # instead of right downwards. 
    ty -= tx
    return tx, ty

def hexgrid_to_coordinate(x, y, hex_width=72):
    """turn a hexgrid position into a coordinate for a hexfield (bottom left corner).

    >>> h2c = hexgrid_to_coordinate
    >>> hw = 72
    >>> h2c(0,0, hex_width=hw)
    (0.0, 0.0)
    >>> h2c(0,1, hw)
    (0.0, 72.0)
    >>> h2c(0,2, hw)
    (0.0, 144.0)
    >>> h2c(1,0, hw)
    (54.0, 36.0)
    >>> h2c(2, 0, hw)
    (108.0, 72.0)
    >>> h2c(1, 1, hw)
    (54.0, 108.0)
    """
    y = (y + 0.5*x)*hex_width
    x = hex_width*x
    x *= (3.0/4)
    return x, y

def hexgrid_distance(sx, sy, tx, ty):
    """Get the distance between this hex and the target.

    >>> d = hexgrid_distance
    >>> d(0, 0, 1, 0)
    1
    >>> d(0, 0, 1, 1)
    2
    >>> d(1, 0, 0, 0)
    1
    >>> d(0, 0, -1, 0)
    1
    >>> d(0, 0, 10, -4)
    10
    """
    sz = -(sx+sy) # “convert” from mine to his (add another axis, 120° to the others). 
    tz = -(tx+ty) # “convert” from mine to his (add another axis, 120° to the others). 
    return int(0.5 * (abs(sx-tx) + abs(sy-ty) + abs(sz-tz)))

#: vectors around the current hex, including the center.
hex_vectors = [
    (0, 0), # center
    (0, -1), # bottom
    (-1, 0), # bottom left
    (-1, 1), # top left
    (0, 1), # top
    (1, 0), # top right
    (1, -1) # bottom right
]

if __name__ == "__main__":
    # there’s only one reason for calling this file: doctests
    from doctest import testmod
    testmod()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.