126 行
4.0 KiB
Python
126 行
4.0 KiB
Python
import json, math, urllib.request, sys
|
|
sys.dont_write_bytecode = True
|
|
|
|
URL = "http://bgjq.simpfun.cn/tiles/minecraft_overworld/markers.json"
|
|
data = urllib.request.urlopen(
|
|
urllib.request.Request(URL, headers={"User-Agent": "Mozilla/5.0 autostore/1.0"}),
|
|
timeout=20).read()
|
|
root = json.loads(data.decode("utf-8"))
|
|
|
|
CLAIM_PATTERN_prefix = "疆土归属:"
|
|
|
|
def extract_polygons(points):
|
|
result = []
|
|
if points is None or not isinstance(points, list):
|
|
return result
|
|
if len(points) == 0:
|
|
return result
|
|
if isinstance(points[0], dict) and "x" in points[0] and "z" in points[0]:
|
|
poly = [(p["x"], p["z"]) for p in points]
|
|
if len(poly) >= 3:
|
|
result.append(poly)
|
|
else:
|
|
for el in points:
|
|
result.extend(extract_polygons(el))
|
|
return result
|
|
|
|
def point_in_polygon(x, z, poly):
|
|
inside = False
|
|
j = len(poly) - 1
|
|
for i in range(len(poly)):
|
|
xi, zi = poly[i]
|
|
xj, zj = poly[j]
|
|
if (zi > z) != (zj > z) and x < (xj - xi) * (z - zi) / (zj - zi) + xi:
|
|
inside = not inside
|
|
j = i
|
|
return inside
|
|
|
|
def fill_polygon(out, poly):
|
|
minx = min(math.floor(p[0]/16) for p in poly)
|
|
maxx = max(math.floor(p[0]/16) for p in poly)
|
|
minz = min(math.floor(p[1]/16) for p in poly)
|
|
maxz = max(math.floor(p[1]/16) for p in poly)
|
|
area = (maxx - minx + 1) * (maxz - minz + 1)
|
|
if area > 6_000_000:
|
|
return
|
|
for cx in range(minx, maxx+1):
|
|
for cz in range(minz, maxz+1):
|
|
if point_in_polygon(cx*16+8, cz*16+8, poly):
|
|
out.add((cx, cz))
|
|
|
|
# Polygon count per marker
|
|
poly_counts = {}
|
|
for layer in root:
|
|
if layer.get("id") != "union_claims":
|
|
continue
|
|
for marker in layer.get("markers", []):
|
|
popup = marker.get("popup", "")
|
|
idx = popup.find(CLAIM_PATTERN_prefix)
|
|
if idx < 0:
|
|
continue
|
|
rest = popup[idx+len(CLAIM_PATTERN_prefix):].lstrip()
|
|
name = ""
|
|
for ch in rest:
|
|
if ch in "<\r\n":
|
|
break
|
|
name += ch
|
|
name = name.strip()
|
|
if not name:
|
|
continue
|
|
polys = extract_polygons(marker.get("points"))
|
|
poly_counts.setdefault(name, 0)
|
|
poly_counts[name] += len(polys)
|
|
|
|
print("=== markers with multiple polygons (potential holes as inner rings) ===")
|
|
for name, cnt in poly_counts.items():
|
|
if cnt > 1:
|
|
print(f" {name}: {cnt} polygons")
|
|
|
|
# Also report how many total markers
|
|
print(f"\nTotal markers: {sum(poly_counts.values())}, distinct countries: {len(poly_counts)}")
|
|
|
|
claims = {}
|
|
for layer in root:
|
|
if layer.get("id") != "union_claims":
|
|
continue
|
|
for marker in layer.get("markers", []):
|
|
popup = marker.get("popup", "")
|
|
idx = popup.find(CLAIM_PATTERN_prefix)
|
|
if idx < 0:
|
|
continue
|
|
rest = popup[idx+len(CLAIM_PATTERN_prefix):].lstrip()
|
|
name = ""
|
|
for ch in rest:
|
|
if ch in "<\r\n":
|
|
break
|
|
name += ch
|
|
name = name.strip()
|
|
if not name:
|
|
continue
|
|
s = claims.setdefault(name, set())
|
|
for poly in extract_polygons(marker.get("points")):
|
|
fill_polygon(s, poly)
|
|
|
|
print(f"Total countries parsed: {len(claims)}")
|
|
print(f"Total claimed chunks: {sum(len(v) for v in claims.values())}")
|
|
|
|
print("\n=== Flying chunks (holes) per country ===")
|
|
total_holes = 0
|
|
for name, chunks in claims.items():
|
|
if not chunks:
|
|
continue
|
|
xs = [c[0] for c in chunks]
|
|
zs = [c[1] for c in chunks]
|
|
minx, maxx = min(xs), max(xs)
|
|
minz, maxz = min(zs), max(zs)
|
|
holes = []
|
|
for cx in range(minx, maxx+1):
|
|
for cz in range(minz, maxz+1):
|
|
if (cx, cz) in chunks:
|
|
continue
|
|
if all(((cx+dx, cz+dz) in chunks) for dx, dz in [(1,0),(-1,0),(0,1),(0,-1)]):
|
|
holes.append((cx, cz))
|
|
if holes:
|
|
total_holes += len(holes)
|
|
print(f" {name}: {len(holes)} holes, e.g. {holes[:8]}")
|
|
print(f"\n=== TOTAL flying chunks: {total_holes} ===") |