# hexbattle / hexgrid.py

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147``` ```#!/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() ```