Closed CyberiaResurrection closed 1 year ago
@tjoneslo , that the scale of checking you were thinking of?
Current star.distance code that generated those straight distances (as at this writing):
def distance(self, star, diagnostic=False):
# If star.x and self.x are both even or both odd (implying dx must be even), they have no net effect on dy's value
# If both even, y1 and y2 each get 1 added, which drops out in subtraction
# If both odd, y1 and y2 each get nothing added.
y1 = self.y * 2
y2 = star.y * 2
dx = abs(star.x - self.x)
raw_dy = y2 - y1
raw_dx = star.x - self.x
# Only look at the following if dx is odd, implying exactly one of self.x and star.x is even
# If star.x is even and self.x is odd, raw value of dy is += 1 (y2 gets increased, y1 stays same)
# If self.x is even and star.x is odd, raw value of dy is -= 1 (y1 gets increased, y2 stays same)
if dx % 2:
# If self.x is even, bump y1 up by 1
if not self.x % 2:
y1 += 1
# If self.x is odd, then star.x _MUST_ be even, bump y2 up by 1
else:
y2 += 1
# The hexagons we're using have 3 axes of symmetry
# - The 12 o'clock-6 o'clock line
# - The 10 o'clock-4 o'clock line
# - The 8 o'clock-2'o'clock line
# Let's tackle those special cases _first_, to try to simplify the residual cases
dy = abs(y2 - y1)
# 12 o'clock-6 o'clock line
if 0 == dx:
return dy//2 if not diagnostic else (dy//2, raw_dx, raw_dy, dx, dy)
# 10 o'clock-4 o'clock line
if dx * 2 == dy:
return dx if not diagnostic else (dx, raw_dx, raw_dy, dx, dy)
# 8 o'clock-2 o'clock line
if 0 == raw_dy:
return dx if not diagnostic else (dx, raw_dx, raw_dy, dx, dy)
# connecting segment is between 12 o'clock and 2 o'clock exclusive,
# xor between 6 o'clock and 8 o'clock exclusive
if (0 < raw_dx) == (0 < raw_dy):
if (dx // 2) > dy:
return dx + (dy // 2) if not diagnostic else (dx + (dy // 2), raw_dx, raw_dy, dx, dy)
if (dy // 2) > dx and abs(raw_dy) == dy:
return dx + (dy // 2) if not diagnostic else (dx + (dy // 2), raw_dx, raw_dy, dx, dy)
if dy > dx and not (dy // 2) > dx:
return dx + (dy // 2) if not diagnostic else (dx + (dy // 2), raw_dx, raw_dy, dx, dy)
# if we haven't found a definitive category yet, drop through to the remaining segment
pass
# connecting segment is in the bowtie
# between 8 o'clock and 10 o'clock exclusive, xor between 2 o'clock and 4 o'clock exclusive
if dx > (dy // 2):
return dx if not diagnostic else (dx, raw_dx, raw_dy, dx, dy)
# by exhaustion, connecting segment is between 10 o'clock and 12 o'clock exclusive,
# xor 4 o'clock and 6 o'clock exclusive
if (dy // 2) > dx:
return ((dy + 1) // 2) if not diagnostic else (((dy + 1) // 2), raw_dx, raw_dy, dx, dy)
return dx + (dy // 2) if not diagnostic else (dx + (dy // 2), raw_dx, raw_dy, dx, dy)
Breaking that down by category (counting "bad" as more than 1 parsec difference between straight and hex distances) updating totals, and adding in what I've learned:
dy // 2 > dx category: Raw dx and raw dy have opposite signs: 9 good, 0 bad, 9 total Raw dx and raw dy have same signs, dx even: 2 good, 0 bad, 2 total Raw dx and raw dy have same signs, dx odd: 2 good, 3 bad, 5 total
dy > dx category: Raw dx and raw dy have opposite signs: 2 good, 0 bad, 2 total Raw dx and raw dy have same signs, dx even: 0 good, 0 bad, 0 total Raw dx and raw dy have same signs, dx odd: 3 good, 0 bad, 3 total
dx//2 >= dy category: Raw dx and raw dy have opposite signs: 3 good, 0 bad, 3 total Raw dx and raw dy have same signs, dx even: 0 good, 0 bad, 0 total Raw dx and raw dy have same signs, dx odd: 1 good, 0 bad, 1 total
Over all 25 inter-sector straight distance comparisons: Raw dx and raw dy have opposite signs: 14 good, 0 bad, 14 total Raw dx and raw dy have same signs, dx even: 2 good, 0 bad, 2 total Raw dx and raw dy have same signs, dx odd: 6 good, 3 bad, 9 total
@tjoneslo , zooming in further on the dy //2 > dx case, with same raw_dx and raw_dy signs, without confusing myself in the previous comment:
Abs(raw_dy) > dy: 0 good, 3 bad, 3 total Abs(raw_dy) == dy: 2 good, 0 bad, 2 total Abs(raw_dy) < dy: 2 good, 0 bad, 2 total
@tjoneslo, more progress.
Good rows now have straight distance equal to hex distance. Bad rows don't (in practice, differing by +1 or -1 only). I've combined both blocks of distances for this analysis.
42 good rows, 7 bad rows, 49 total
0 = dx: 2 good, 0 bad, 2 total same dy and dx signs: 9 good, 2 bad, 11 total different dy and dx signs: 31 good, 5 bad, 36 total
abs(raw_dy) > dy: 12 good, 1 bad, 13 total abs(raw_dy) == dy: 18 good, 0 bad, 18 total abs(raw_dy) < dy: 12 good, 6 bad, 18 total
https://www.redblobgames.com/grids/hexagons/ - This is the original source of the distance calculations. One concern would be I copied the formula's wrong. So that would be the first thing I would double check. Second would be the conversion of the sector/hex id to the coordinates used by the distance calculations. Does the conversion for the coreward row of Spinward Marches end up being 1 hex to the rimward row of Gvurrdon sector?
@tjoneslo - good point. Is what Amit Patel called "col" equal to what you've called "col", or is that x? (likewise for row and y).
What were you aiming to implement? distance over doubled-for-the-occasion offset co-ords?
To make sure I'm grokking you, you want me to:
As I remember it, it should be:
or should I just do what redblob recommend and thin out straight distance to a wrapper around axial?
Sod it, straight distance is now a wrapper. Works out a hell of a lot simpler.
@tjoneslo , while I was waiting, I tried a full-charted-space run, which blew up with something like this:
2023-08-30 14:20:24,905 - INFO - Total number of worlds: 51190
Traceback (most recent call last):
File "/home/alex/gitstuf/traveller_pyroute/PyRoute/route.py", line 147, in <module>
process()
File "/home/alex/gitstuf/traveller_pyroute/PyRoute/route.py", line 89, in process
galaxy.read_sectors(sectors_list, args.pop_code, args.ru_calc)
File "/home/alex/gitstuf/traveller_pyroute/PyRoute/Galaxy.py", line 331, in read_sectors
self.set_positions()
File "/home/alex/gitstuf/traveller_pyroute/PyRoute/Galaxy.py", line 352, in set_positions
assert map_len == shadow_len, "Mismatch between shadow stars and stars mapping, " + str(shadow_len) + " and " + str(map_len)
AssertionError: Mismatch between shadow stars and stars mapping, 51190 and 52140
"Dedupe input file list" and "Dedupe sectors on loading" are simple efforts to robustify the parser against such straight-up duplication. "Dedupe input file list" guards against including the same sector file twice. "Dedupe sectors on loading" guards against situations like Zhodane/Zhdant as separate files referencing the same sector.
This looks great
Companion PR to #50 .
Probably need to be merged after #49