Special remote airports + isRemote curation (ISS-097, v0.61.0)
CI / build + unit + e2e (pull_request) Successful in 15m31s
CI / build + unit + e2e (pull_request) Successful in 15m31s
This commit is contained in:
+27
-3
@@ -1,5 +1,6 @@
|
||||
import { promises as fs } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { haversineKm } from './geo';
|
||||
|
||||
export type CsvRow = Record<string, string>;
|
||||
|
||||
@@ -52,15 +53,38 @@ export function parseCsv(text: string): CsvRow[] {
|
||||
// The 2026 schema splits "airport" into small/medium/large_airport (older dumps used a
|
||||
// single "airport" type + category column) — both spellings are accepted. Heliports are
|
||||
// excluded — no fixed-wing transport ops; other types (closed, balloonport, ...) are
|
||||
// irrelevant to an airline-ops game. The committed dataset is pre-curated to large_airport
|
||||
// only (scripts/build-world-airports.mjs); this check stays as a cheap guard against an
|
||||
// uncurated dump being swapped in.
|
||||
// irrelevant to an airline-ops game. The committed dataset is pre-curated by
|
||||
// scripts/build-world-airports.mjs: every large_airport plus the small/medium/seaplane rows
|
||||
// that are REMOTE (see isRemote) — this check stays as a cheap guard against an uncurated
|
||||
// dump being swapped in.
|
||||
const INCLUDED_TYPES = new Set(['airport', 'small_airport', 'medium_airport', 'large_airport', 'seaplane_base']);
|
||||
|
||||
export function filterWorldAirports(rows: CsvRow[]): CsvRow[] {
|
||||
return rows.filter((r) => INCLUDED_TYPES.has(r.type));
|
||||
}
|
||||
|
||||
// v0.61.0 (ISS-097): "special" remote airports — the issue's loneliness test: an airport is
|
||||
// remote when no other member of `airports` sits within this radius, so it stands alone in a
|
||||
// genuinely empty region (Antarctica, high Arctic, far islands) rather than being one of many.
|
||||
export const REMOTE_RADIUS_KM = 1000;
|
||||
|
||||
export interface RemoteAirport {
|
||||
icao: string;
|
||||
lat: number;
|
||||
lon: number;
|
||||
}
|
||||
|
||||
// True when the airport with this ICAO has no OTHER member of `airports` within REMOTE_RADIUS_KM
|
||||
// (haversine). Unknown ICACOs are not remote — callers only pass rows they intend to include.
|
||||
export function isRemote(airports: readonly RemoteAirport[], icao: string): boolean {
|
||||
const a = airports.find((x) => x.icao === icao);
|
||||
if (!a) return false;
|
||||
for (const b of airports) {
|
||||
if (b.icao !== a.icao && haversineKm(a.lat, a.lon, b.lat, b.lon) <= REMOTE_RADIUS_KM) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export interface AirportProperties {
|
||||
name: string;
|
||||
icao: string;
|
||||
|
||||
Reference in New Issue
Block a user