emergency: randomize route selection near start city

This commit is contained in:
Richard Zink committed 2026-10-13 06:52:39 +02:00
1 parent a6c0418153
commit 8f085e0db0
1 file changed
+53 -38
+53 -38
View File
@@ -3533,19 +3533,9 @@ function nearestEmergencyCity() {
return best; return best;
} }
function selectEmergencyRoutes() { function emergencyCollectCandidates(sec, startCity, minKm, maxKm, nearLimit) {
emergencyRoutes = []; var targetKm = (minKm + maxKm) / 2;
emergencyVehicles = []; var out = [];
emergencyCount = 0;
emergencyLastT = null;
if (!EMERGENCY_ON || !carGeo || !carGeo.secondary || !carGeo.secondary.cnts || !carGeo.secondary.cnts.length) {
window.__emergencyDbg = { enabled: EMERGENCY_ON, startCity: null, routes: 0 };
return;
}
emergencyStartCity = nearestEmergencyCity();
var sec = carGeo.secondary;
var targetKm = (EMERGENCY_MIN_KM + EMERGENCY_MAX_KM) / 2;
var candidates = [];
var k = 0; var k = 0;
for (var ci = 0; ci < sec.cnts.length; ci++) { for (var ci = 0; ci < sec.cnts.length; ci++) {
var n = sec.cnts[ci]; var n = sec.cnts[ci];
@@ -3555,11 +3545,11 @@ function selectEmergencyRoutes() {
var lastX = sec.pts[last], lastZ = sec.pts[last + 1], lastD = sec.pts[last + 2]; var lastX = sec.pts[last], lastZ = sec.pts[last + 1], lastD = sec.pts[last + 2];
var len = Math.max(0, lastD - firstD); var len = Math.max(0, lastD - firstD);
var lenKm = len * KM_PER_TILE; var lenKm = len * KM_PER_TILE;
var dStart = Math.hypot(firstX - emergencyStartCity.x, firstZ - emergencyStartCity.z); var dStart = Math.hypot(firstX - startCity.x, firstZ - startCity.z);
var dEnd = Math.hypot(lastX - emergencyStartCity.x, lastZ - emergencyStartCity.z); var dEnd = Math.hypot(lastX - startCity.x, lastZ - startCity.z);
var near = Math.min(dStart, dEnd); var near = Math.min(dStart, dEnd);
if (near < 1.2 && lenKm >= EMERGENCY_MIN_KM * 0.55 && lenKm <= EMERGENCY_MAX_KM * 1.45) { if (near <= nearLimit && lenKm >= minKm && lenKm <= maxKm) {
candidates.push({ out.push({
ci: ci, len: len, lenKm: lenKm, near: near, ci: ci, len: len, lenKm: lenKm, near: near,
score: Math.abs(lenKm - targetKm) + near * 18, score: Math.abs(lenKm - targetKm) + near * 18,
reverse: dEnd < dStart reverse: dEnd < dStart
@@ -3567,35 +3557,58 @@ function selectEmergencyRoutes() {
} }
k += n * 3; k += n * 3;
} }
candidates.sort(function (a, b) { return a.score - b.score; }); return out;
if (!candidates.length) {
var best = null, k2 = 0;
for (var ci2 = 0; ci2 < sec.cnts.length; ci2++) {
var n2 = sec.cnts[ci2];
if (n2 < 2) { k2 += n2 * 3; continue; }
var f2 = k2, l2 = k2 + (n2 - 1) * 3;
var len2 = Math.max(0, sec.pts[l2 + 2] - sec.pts[f2 + 2]);
var near2 = Math.min(
Math.hypot(sec.pts[f2] - emergencyStartCity.x, sec.pts[f2 + 1] - emergencyStartCity.z),
Math.hypot(sec.pts[l2] - emergencyStartCity.x, sec.pts[l2 + 1] - emergencyStartCity.z));
if (near2 < 2.5 && (!best || len2 > best.len)) best = { ci: ci2, len: len2, lenKm: len2 * KM_PER_TILE, near: near2, reverse: false };
k2 += n2 * 3;
} }
if (best) candidates.push(best);
function emergencyShuffle(arr) {
for (var i = arr.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var t = arr[i]; arr[i] = arr[j]; arr[j] = t;
} }
for (var r = 0; r < Math.min(EMERGENCY_COUNT, candidates.length); r++) { return arr;
var route = emergencyChainAt(sec, candidates[r].ci); }
if (candidates[r].reverse) route.reverse();
function selectEmergencyRoutes() {
emergencyRoutes = [];
emergencyVehicles = [];
emergencyCount = 0;
emergencyLastT = null;
if (!EMERGENCY_ON || !carGeo || !carGeo.secondary || !carGeo.secondary.cnts || !carGeo.secondary.cnts.length) {
window.__emergencyDbg = { enabled: EMERGENCY_ON, startCity: null, candidates: 0, routes: 0 };
return;
}
emergencyStartCity = nearestEmergencyCity();
var sec = carGeo.secondary;
var pool = emergencyCollectCandidates(sec, emergencyStartCity, EMERGENCY_MIN_KM, EMERGENCY_MAX_KM, 1.2);
var poolMode = 'strict';
if (!pool.length) {
pool = emergencyCollectCandidates(sec, emergencyStartCity, EMERGENCY_MIN_KM * 0.55, EMERGENCY_MAX_KM * 1.45, 1.8);
poolMode = 'relaxed';
}
if (!pool.length) {
pool = emergencyCollectCandidates(sec, emergencyStartCity, 10, 160, 3.0);
poolMode = 'fallback';
}
pool.sort(function (a, b) { return a.score - b.score; });
var top = pool.slice(0, Math.max(EMERGENCY_COUNT * 8, 24));
emergencyShuffle(top);
var used = {};
for (var r = 0; r < top.length && emergencyRoutes.length < EMERGENCY_COUNT; r++) {
var cand = top[r];
if (used[cand.ci]) continue;
used[cand.ci] = true;
var route = emergencyChainAt(sec, cand.ci);
if (cand.reverse) route.reverse();
var len = route.length ? route[route.length - 1].d - route[0].d : 0; var len = route.length ? route[route.length - 1].d - route[0].d : 0;
if (len <= 0) continue; if (len <= 0) continue;
emergencyRoutes.push({ pts: route, len: len, lenKm: len * KM_PER_TILE, nearKm: candidates[r].near * KM_PER_TILE }); emergencyRoutes.push({ pts: route, len: len, lenKm: len * KM_PER_TILE, nearKm: cand.near * KM_PER_TILE });
} }
for (var v = 0; v < emergencyRoutes.length; v++) { for (var v = 0; v < emergencyRoutes.length; v++) {
emergencyVehicles.push({ emergencyVehicles.push({
route: v, route: v,
d: emergencyRoutes[v].len * (0.08 + 0.72 * ((v * 0.371) % 1)), d: emergencyRoutes[v].len * (0.05 + 0.85 * Math.random()),
dir: ((v % 2) === 0) ? 1 : -1, dir: Math.random() < 0.5 ? 1 : -1,
seed: (v * 0.6180339887) % 1 seed: Math.random()
}); });
} }
emergencyCount = emergencyVehicles.length; emergencyCount = emergencyVehicles.length;
@@ -3608,6 +3621,8 @@ function selectEmergencyRoutes() {
pop: emergencyStartCity.pop, pop: emergencyStartCity.pop,
km: +(emergencyStartCity.dist * KM_PER_TILE).toFixed(1) km: +(emergencyStartCity.dist * KM_PER_TILE).toFixed(1)
} : null, } : null,
poolMode: poolMode,
candidates: pool.length,
routes: emergencyRoutes.map(function (r) { return { km: +r.lenKm.toFixed(1), nearKm: +r.nearKm.toFixed(1) }; }) routes: emergencyRoutes.map(function (r) { return { km: +r.lenKm.toFixed(1), nearKm: +r.nearKm.toFixed(1) }; })
}; };
} }