8 static int inversecantor(int cantor, int *x, int *y);
11 * This file is written by Nathan Wagner and dedicated to the public
15 double HL_vertexv[] = {
16 .577350269189625764509148780502, 0.0,
17 .288675134594812882254574390251, 0.5,
18 -.288675134594812882254574390251, 0.5,
19 -.577350269189625764509148780502, 0.0,
20 -.288675134594812882254574390251, -0.5,
21 .288675134594812882254574390251, -0.5};
23 /* these all are for a hex one unit across */
24 double hexptvd[6][2] = {
25 {.577350269189625764509148780502, 0.0}, /* 1.0/sqrt3 */
26 {.288675134594812882254574390251, 0.5}, /* 0.5/sqrt3 */
27 {-.288675134594812882254574390251, 0.5},
28 {-.577350269189625764509148780502, 0.0},
29 {-.288675134594812882254574390251, -0.5},
30 {.288675134594812882254574390251, -0.5}
33 /* TODO how is this related? to the above? */
34 double texptvd[6][2] = {
35 {1.154700538379251529018297561004, 0.5}, /* 2.0/sqrt3 */
36 {.866025403784438646763723170753, 1.0}, /* 1.5/sqrt3 */
37 {.288675134594812882254574390251, 1.0},
39 {.288675134594812882254574390251, 0.0},
40 {.866025403784438646763723170753, 0.0}
43 double hexpthd[6][2] = {
44 {0.0, .577350269189625764509148780502},
45 {0.5, .288675134594812882254574390251},
46 {0.5, -.288675134594812882254574390251},
47 {0.0, -.577350269189625764509148780502},
48 {-0.5, -.288675134594812882254574390251},
49 {-0.5, .288675134594812882254574390251}
52 void HL_vertices(int cantor, double *vc) {
56 HL_hexcenter(cantor, &xc, &yc);
59 *vc++ = hexptvd[i][0] + xc;
60 *vc++ = hexptvd[i][1] + yc;
62 *vc++ = hexptvd[0][0] + xc;
63 *vc++ = hexptvd[0][1] + yc;
66 void HL_trianglefan(int cantor, double *vc) {
67 HL_hexcenter(cantor, vc, vc+1);
68 HL_vertices(cantor, vc+2);
71 double HL_center_x(int cantor) {
74 HL_hexcenter(cantor, &x, 0);
78 double HL_center_y(int cantor) {
81 HL_hexcenter(cantor, 0, &y);
85 int HL_hexcenter(int cantor, double *xc, double *yc) {
87 double stride = 1.5/sqrt(3.0);
89 inversecantor(cantor, &x, &y);
91 if (xc) *xc = x * stride;
92 if (yc && x >= 0) *yc = y + ((x + 1) % 2) / 2.0 - 0.5;
93 if (yc && x < 0) *yc = y + ((-x + 1) % 2) / 2.0 - 0.5;
99 * This function assumes that the hexes are one unit across, and vertically
100 * oriented. If that is not the case, you will need to transform
101 * your input coordinates first.
103 int HL_cantor_bin(double x, double y) {
106 HL_hexbin(1.0, x, y, &i, &j);
107 return HL_cantor_xy(i, j);
110 static int xy2ijk(int x, int y, int *i, int *j, int *k) {
116 pj = pj + (-x + 1) / 2;
126 return HL_cantor_xy(x,y);
129 static int ijk2xy(int i, int j, int k, int *x, int *y) {
146 return HL_cantor_xy(px,py);
149 int HL_cantor_ijk(int i, int j, int k) {
150 return ijk2xy(i,j,k,0,0);
153 int HL_distance(int from, int to) {
157 HL_cantor_arrays(from, 0, fc);
158 HL_cantor_arrays(to, 0, tc);
161 dist += abs(fc[i] - tc[i]);
167 int HL_hexes_within_range(int hex, int range, int *list, int size) {
172 return HL_hexes_at_range(hex, 0, list, size);
175 for (i=1;i<=range;i++) {
176 count += HL_hexes_at_range(hex, i, count > size ? 0 : list+count, size-count);
181 int HL_hexes_at_range(int hex, int range, int *list, int size) {
182 int q; /* p and q are count/loop vars */
183 int c[3]; /* ijk coord array */
190 } else if (range < 0) {
194 /* TODO don't bother to collect if the list isn't big enough? */
195 /* i.e. if (!list || size < range * 6) */
196 if (!list || size < 1) return range * 6;
198 HL_cantor_arrays(hex, 0, c);
201 hex = HL_cantor_ijkp(c);
203 for(q=0; q<size && q < range * 6; q++) {
205 hex = HL_adjhex(hex, q/range+2);
211 /* direction 0 is positive X , counter clockwise from there */
212 int HL_adjhex(int start, int dir) {
215 HL_cantor_arrays(start, 0, c);
219 c[0]--; c[1]++; break;
221 c[1]++; c[2]--; break;
223 c[0]++; c[2]--; break;
225 c[0]++; c[1]--; break;
227 c[1]--; c[2]++; break;
229 c[0]--; ; c[2]++; break;
232 return HL_cantor_ijkp(c);
235 /* returns last hex in found path */
236 int HL_findpath(int start, int end, int *path, int size) {
240 int HL_cantor_xyp(int *xy) {
241 return HL_cantor_xy(xy[0], xy[1]);
244 int HL_cantor_ijkp(int *ijk) {
245 return HL_cantor_ijk(ijk[0], ijk[1], ijk[2]);
248 int HL_cantor_arrays(int can, int *xy, int *ijk) {
249 return HL_cantor_decode(can, xy, xy ? xy+1 : 0,
250 ijk, ijk ? ijk+1 : 0, ijk ? ijk+2 : 0);
253 int HL_cantor_decode(int can, int *x, int *y, int *i, int *j, int *k) {
256 inversecantor(can, &px, &py);
260 xy2ijk(px, py, i, j, k);
265 int HL_cantor_i(int cantor) {
268 HL_cantor_decode(cantor, 0,0, &i,0,0);
272 int HL_cantor_j(int cantor) {
275 HL_cantor_decode(cantor, 0,0, 0,&j,0);
279 int HL_cantor_k(int cantor) {
282 HL_cantor_decode(cantor, 0,0, 0,0,&k);
286 int HL_cantor_x(int cantor) {
288 inversecantor(cantor, &x, 0);
292 int HL_cantor_y(int cantor) {
294 inversecantor(cantor, 0, &y);
298 /* Determine if a map with these dimensions will overflow */
299 int HL_map_bounds_ok(int xdim, int ydim) {
301 /* return (x+y) * (x + y + 1) / 2 + y+1; */
303 if (INT_MAX - xdim - 1 < ydim) return 0;
304 if (INT_MAX / (xdim+ydim) < (xdim+ydim+1)) return 0;
305 if ( (xdim+ydim) * (xdim+ydim+1) / 2 > INT_MAX - ydim - 1)
311 int HL_map_max_dimension(void) {
314 low = 1; high = INT_MAX/2;
316 while (low != high - 1) {
317 try = (low + high) / 2;
318 if (HL_map_bounds_ok(try,try)) {
337 int open, closed; /* how many in open or closed */
338 int closedroom, openroom; /* how much is malloced */
339 struct astar_hex *openlist;
340 struct astar_hex *closedlist;
345 static void astar_init(struct astar *state) {
348 state->closedroom = 0;
351 state->closedlist = 0;
359 static void removeopen(struct astar *s, int hex) {
362 if (s->error) return;
363 if (s->open == 0) return;
365 if (s->known != hex) {
366 for (index = 0; index < s->open; index++) {
367 if (s->openlist[index].hex == hex) break;
371 s->known = 0; s->index = 0;
373 s->openlist[index] = s->openlist[open];
377 static void addopen(struct astar *s, int hex) {
378 struct astar_hex *mem;
379 if (s->error) return;
381 if (s->open + 1 > s->openroom) {
382 mem = realloc(s->openlist, s->openroom * 2 * sizeof *mem);
387 state->openlist = mem;
388 s->openroom = s->openroom * 2;
391 s->openlist[s->open].hex = hex;
392 s->openlist[s->open].f = 0;
393 s->openlist[s->open].g = 0;
394 s->openlist[s->open].h = 0;
397 s->open = s->open + 1;
400 int lowrank(struct astar *s) {
405 if (!s || s->open = 0) return 0;
407 hex = s->openlist[0].hex;
408 f = s->openlist[0].f;
410 for(i=1; i < s->open; i++) {
411 if (s->openlist[i].f < f) {
412 hex = s->openlist[i].hex;
413 f = s->openlist[i].f;
415 /* TODO check s->openlist[i].tiebreak */
421 static int default_metric(int a, int b) {
426 * find a path from start to end. we use A*
428 int HL_findpath(int start, int end, int psize, int *path,
429 double (*metric)(int,int)) {
436 if (start == end) return 0;
437 if (!metric) metric = default_metric;
440 addopen(&state, start);
443 cur = lowrank(&state);
447 addclosed(&state, cur);
448 count = HL_hexes_at_range(cur->hex, 1, neighbors, 6);
449 for (i=0;i<count;i++) {
450 neighbor = neighbors[i];
451 cost = g(&state, current) + metric(current, neighbor);
452 if (inopen(&state, neighbor) && cost < g(&state, neighbor)) {
453 removeopen(&state, neighbor);
455 if (inclosed(&state, neighbor) && cost < g(&state, neighbor)) {
456 /* should never happen with
457 * admissible heuristic
459 removeclosed(&state, neighbor);
461 if (!inopen(&state, neighbor) && !inclosed(&state, neighbor)) {
462 addopen(&state, neighbor);
463 setg(&state, neighbor, cost);
464 setrank(&state, neighbor, cost + h(neighbor,end));
465 setparent(&state, neighbor, current);
473 while (parent(&state, cur) != start) {
475 cur = parent(&state, cur);
478 while (parent(&state, cur) != start) {
480 cur = parent(&state, cur);
487 static int inversenatcantor(int cantor, int *x, int *y) {
492 w = (int)floor((sqrt(8.0 * cantor + 1.0) - 1.0)/2.0);
504 * map non negative integer pairs to their cantor pairing function
505 * number, plus one. We add one so that the result is never zero,
506 * leaving zero to be "invalid" or "none" or what have you.
509 static int natcantor(int x, int y) {
510 return (x+y) * (x + y + 1) / 2 + y+1;
513 /* See http://en.wikipedia.org/wiki/Cantor_pairing_function */
514 /* see also http://szudzik.com/ElegantPairing.pdf */
516 * if either coordinate is negative, map the integers onto the
517 * whole numbers, and then return the negative of the adjusted
518 * cantor number. As for most grids negative coordinates will
519 * be invalid, this will allow for a <= 0 test for invalid
520 * or out of bounds (on the negative side anyway, you'll
521 * still have to test for out of range on the positive side).
523 * TODO figure out what the maximum supported coordinates are
524 * for given integer sizes.
526 int HL_cantor_xy(int x, int y) {
527 if (x < 0 || y < 0) {
528 x = abs(2 * x) - (x < 0);
529 y = abs(2 * y) - (y < 0);
530 return -natcantor(x, y);
532 return natcantor(x,y);
535 static int inversecantor(int cantor, int *x, int *y) {
537 inversenatcantor(-cantor, x, y);
553 inversenatcantor(cantor, x, y);
564 /* y *must* be positive down as the xy /iso conversion assumes this */
565 static int hex_xy(struct hex *h) {
566 if (!h->iso) return 1;
568 h->y = -h->y - (h->x+1)/2;
570 /* need to round toward -inf, not toward zero, so x-1 */
571 h->y = -h->y - h->x/2;
578 static int hex_iso(struct hex *h) {
579 if (h->iso) return 1;
582 h->y = (-h->y - (h->x+1)/2);
584 /* need to round toward -inf, not toward zero, so x-1 */
585 h->y = (-h->y - (h->x)/2);
593 int HL_hexbin(double width, double x, double y, int *i, int *j) {
594 double z, rx, ry, rz;
595 double abs_dx, abs_dy, abs_dz;
599 /* TODO just hard-code this cosine */
600 x = x / cos(30 * M_PI / 180.0); /* rotated X coord */
601 y = y - x / 2.0; /* adjustment for rotated X */
603 /* adjust for actual hexwidth */
609 ix = rx = floor(x + 0.5);
610 iy = ry = floor(y + 0.5);
611 iz = rz = floor(z + 0.5);
616 abs_dx = fabs(rx - x);
617 abs_dy = fabs(ry - y);
618 abs_dz = fabs(rz - z);
620 if (abs_dx >= abs_dy && abs_dx >= abs_dz) {
622 } else if (abs_dy >= abs_dx && abs_dy >= abs_dz) {
636 return HL_cantor_xy(h.x, h.y);