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;
}
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, routes: 0 };
return;
}
emergencyStartCity = nearestEmergencyCity();
var sec = carGeo.secondary;
var targetKm = (EMERGENCY_MIN_KM + EMERGENCY_MAX_KM) / 2;
var candidates = [];
function emergencyCollectCandidates(sec, startCity, minKm, maxKm, nearLimit) {
var targetKm = (minKm + maxKm) / 2;
var out = [];
var k = 0;
for (var ci = 0; ci < sec.cnts.length; 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 len = Math.max(0, lastD - firstD);
var lenKm = len * KM_PER_TILE;
var dStart = Math.hypot(firstX - emergencyStartCity.x, firstZ - emergencyStartCity.z);
var dEnd = Math.hypot(lastX - emergencyStartCity.x, lastZ - emergencyStartCity.z);
var dStart = Math.hypot(firstX - startCity.x, firstZ - startCity.z);
var dEnd = Math.hypot(lastX - startCity.x, lastZ - startCity.z);
var near = Math.min(dStart, dEnd);
if (near < 1.2 && lenKm >= EMERGENCY_MIN_KM * 0.55 && lenKm <= EMERGENCY_MAX_KM * 1.45) {
candidates.push({
if (near <= nearLimit && lenKm >= minKm && lenKm <= maxKm) {
out.push({
ci: ci, len: len, lenKm: lenKm, near: near,
score: Math.abs(lenKm - targetKm) + near * 18,
reverse: dEnd < dStart
@@ -3567,35 +3557,58 @@ function selectEmergencyRoutes() {
}
k += n * 3;
}
candidates.sort(function (a, b) { return a.score - b.score; });
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;
return out;
}
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;
}
if (best) candidates.push(best);
return arr;
}
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;
}
for (var r = 0; r < Math.min(EMERGENCY_COUNT, candidates.length); r++) {
var route = emergencyChainAt(sec, candidates[r].ci);
if (candidates[r].reverse) route.reverse();
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;
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++) {
emergencyVehicles.push({
route: v,
d: emergencyRoutes[v].len * (0.08 + 0.72 * ((v * 0.371) % 1)),
dir: ((v % 2) === 0) ? 1 : -1,
seed: (v * 0.6180339887) % 1
d: emergencyRoutes[v].len * (0.05 + 0.85 * Math.random()),
dir: Math.random() < 0.5 ? 1 : -1,
seed: Math.random()
});
}
emergencyCount = emergencyVehicles.length;
@@ -3608,6 +3621,8 @@ function selectEmergencyRoutes() {
pop: emergencyStartCity.pop,
km: +(emergencyStartCity.dist * KM_PER_TILE).toFixed(1)
} : null,
poolMode: poolMode,
candidates: pool.length,
routes: emergencyRoutes.map(function (r) { return { km: +r.lenKm.toFixed(1), nearKm: +r.nearKm.toFixed(1) }; })
};
}