Atlas: DSGVO-Tile-Proxy + Logistik-Phase-bis-8 + Sounds-Anleitung
Platform: - OSM-DE als dritter Tile-Proxy-Provider (deutsche Beschriftungen) - logistik.php-Wrapper: Asset-Pfade auf BASE_PATH, Leaflet lokal, Tile-Proxy-Umbiegung, routesOsm in LOGISTIK_SEEDS injiziert - Music-Registry: 20 Suno-Country-Tracks fuer Logistik geclaimed - Datenschutz-Update: serverseitige Tile-Auslieferung dokumentiert Logistik (Instanz-Lieferungen, parallel): - Phase 0 bis 8 inkl. Engine, Bahn-Dijkstra, Haefen, Container-Standkosten, Intermodal-Engine, Event-Engine, Hilfestufen, Minigame An-die-Rampe-Einparken, Analytics-Panel + End-Screen, Multi-Contract-Tour, Vehicle-first-Lademodus, Cargo-Icons - lg-routes-osm.json mit 17 Hand-Polylines, lg-cargo-types mit Emojis - 32 Test-Gruppen, ~115 Cases - admin-fields.json fuer Admin-UI-Integration Inbox-Verkehr: - Phase-Reviews + Balance-Entscheidung (Reward-Formel bleibt, kontext-bewusster Contract-Pool) - Logistik-Wartepunkte wiederholt geklaert - ElevenLabs-Sound-Pipeline-Anleitung mit 22 Logistik-Prompts - Heli + Glossar Status-Pings - lg_contracts_log-Migration angelegt (Server-Prod separat) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -129,29 +129,130 @@
|
||||
|
||||
/**
|
||||
* `naive` — erstes Fahrzeug, nächster Auftrag, FIFO-Reihenfolge.
|
||||
* Phase 2: aktiviert sobald engine.tick / assignContract /
|
||||
* calculateRoute existieren. Bis dahin kontrollierter Stub.
|
||||
* Phase 2 (aktiv): nimmt den ersten OPEN-Auftrag, weist ihn dem
|
||||
* ersten IDLE-Fahrzeug zu, lässt dann ticken bis Limit oder
|
||||
* alle Aufträge fertig.
|
||||
*/
|
||||
naive: {
|
||||
description: 'Erstes Fahrzeug, nächster Auftrag, FIFO.',
|
||||
run(ctx) {
|
||||
throw new Error(
|
||||
'Strategy "naive" benötigt engine.tick / assignContract / ' +
|
||||
'calculateRoute (Phase 2 — noch nicht implementiert).'
|
||||
);
|
||||
const { game, engine, log, seeds } = ctx;
|
||||
const cfg = game._config || {};
|
||||
const limitHours = cfg.timeLimitHours || 24;
|
||||
const E = engine;
|
||||
|
||||
// Seeds + Lifecycle
|
||||
E.loadContent(game, seeds);
|
||||
E.seedInitialVehicles(game);
|
||||
E.seedInitialContracts(game);
|
||||
E.startPlanning(game);
|
||||
E.startSimulation(game);
|
||||
|
||||
// Phase-2-Tick-Step: 5 Min Sim-Zeit pro Iteration (entspricht
|
||||
// ~5000 ms real bei 1×; im Headless egal, da deterministisch)
|
||||
const stepMinutes = 5;
|
||||
const stepRealMs = stepMinutes * 1000; // (1×: 1 sec real = 1 min sim → 5 min = 5000 ms)
|
||||
let safety = 100000;
|
||||
|
||||
while (game.state === E.STATE.RUNNING && safety-- > 0) {
|
||||
// Naive Disposition: erstes OPEN ↔ erstes IDLE.
|
||||
// Intermodal-Aufträge werden in dieser Strategie noch übersprungen
|
||||
// (Phase 6c: separate Strategie-Anpassung mit Mode-Match).
|
||||
const open = (game.activeContracts || []).filter(c => c.state === E.CONTRACT_STATE.OPEN && !c.intermodal);
|
||||
const free = (game.vehicles || []).filter(v => v.state === E.VEHICLE_STATE.IDLE);
|
||||
if (open.length && free.length) {
|
||||
try {
|
||||
E.assignContract(game, open[0].id, free[0].id);
|
||||
log.push({ simTime: game.simulationTime, action: 'assign', contract: open[0].id, vehicle: free[0].id });
|
||||
} catch (e) {
|
||||
log.push({ simTime: game.simulationTime, action: 'assign_failed', error: e.message });
|
||||
}
|
||||
}
|
||||
E.tick(game, stepRealMs);
|
||||
if (game.state !== E.STATE.RUNNING) break;
|
||||
if (E.getSimHoursElapsed(game) >= limitHours) break;
|
||||
}
|
||||
|
||||
const startBudget = cfg.startBudget || 5000;
|
||||
const profit = game.balance - startBudget;
|
||||
const minTarget = cfg.minTargetEarnings || 0;
|
||||
return {
|
||||
successful: profit >= minTarget,
|
||||
endBalance: game.balance,
|
||||
completedContracts: (game.completedContracts || []).length,
|
||||
lateDeliveries: (game.analytics && game.analytics.lateDeliveries) || 0,
|
||||
durationHours: E.getSimHoursElapsed(game),
|
||||
hintUsages: 0,
|
||||
log,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* `greedy` — höchster Auftragswert zuerst, größtes Fahrzeug.
|
||||
* `greedy` — höchster Auftragswert zuerst, fähigstes verfügbares
|
||||
* Fahrzeug. „Fähig" = Kapazität ≥ Container-Bedarf, sonst egal.
|
||||
* Phase 3 aktiv.
|
||||
*/
|
||||
greedy: {
|
||||
description: 'Höchster Auftragswert zuerst, größtes Fahrzeug.',
|
||||
description: 'Höchster Auftragswert zuerst, größtes passendes Fahrzeug.',
|
||||
run(ctx) {
|
||||
throw new Error(
|
||||
'Strategy "greedy" benötigt engine.tick / assignContract / ' +
|
||||
'calculateRoute (Phase 2 — noch nicht implementiert).'
|
||||
);
|
||||
const { game, engine, log, seeds } = ctx;
|
||||
const cfg = game._config || {};
|
||||
const limitHours = cfg.timeLimitHours || 24;
|
||||
const E = engine;
|
||||
|
||||
E.loadContent(game, seeds);
|
||||
E.seedInitialVehicles(game);
|
||||
E.seedInitialContracts(game);
|
||||
E.startPlanning(game);
|
||||
E.startSimulation(game);
|
||||
|
||||
const stepRealMs = 5 * 1000; // 5 min sim
|
||||
let safety = 100000;
|
||||
|
||||
while (game.state === E.STATE.RUNNING && safety-- > 0) {
|
||||
// Aufträge nach Wert sortiert (descending), Fahrzeuge nach Kapazität descending.
|
||||
// Intermodal-Aufträge werden hier noch übersprungen (Phase 6c).
|
||||
const open = (game.activeContracts || [])
|
||||
.filter(c => c.state === E.CONTRACT_STATE.OPEN && !c.intermodal)
|
||||
.slice()
|
||||
.sort((a, b) => (b.rewardBase || 0) - (a.rewardBase || 0));
|
||||
const free = (game.vehicles || [])
|
||||
.filter(v => v.state === E.VEHICLE_STATE.IDLE)
|
||||
.slice()
|
||||
.sort((a, b) => (b.capacityUnits || 0) - (a.capacityUnits || 0));
|
||||
// Pro Auftrag das passendste Fahrzeug nehmen
|
||||
for (const c of open) {
|
||||
if (!free.length) break;
|
||||
// Erstes free, das genug Kapazität hat (wenn keines, das größte)
|
||||
let pick = free.find(v => (v.capacityUnits || 0) >= (c.quantityContainers || 1));
|
||||
if (!pick) pick = free[0];
|
||||
try {
|
||||
E.assignContract(game, c.id, pick.id);
|
||||
log.push({ simTime: game.simulationTime, action: 'assign', contract: c.id, vehicle: pick.id });
|
||||
const idx = free.indexOf(pick);
|
||||
if (idx >= 0) free.splice(idx, 1);
|
||||
} catch (e) {
|
||||
log.push({ simTime: game.simulationTime, action: 'assign_failed', error: e.message });
|
||||
}
|
||||
}
|
||||
E.tick(game, stepRealMs);
|
||||
if (game.state !== E.STATE.RUNNING) break;
|
||||
if (E.getSimHoursElapsed(game) >= limitHours) break;
|
||||
}
|
||||
|
||||
const startBudget = cfg.startBudget || 5000;
|
||||
const profit = game.balance - startBudget;
|
||||
const minTarget = cfg.minTargetEarnings || 0;
|
||||
return {
|
||||
successful: profit >= minTarget,
|
||||
endBalance: game.balance,
|
||||
completedContracts: (game.completedContracts || []).length,
|
||||
lateDeliveries: (game.analytics && game.analytics.lateDeliveries) || 0,
|
||||
durationHours: E.getSimHoursElapsed(game),
|
||||
hintUsages: 0,
|
||||
log,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
@@ -192,11 +293,14 @@
|
||||
' (verfügbar: ' + Object.keys(STRATEGIES).join(', ') + ')');
|
||||
}
|
||||
|
||||
const game = engine.createGame(levelNum);
|
||||
const game = engine.createGame(levelNum, { deterministic: true, seed });
|
||||
const rng = makeRng(seed);
|
||||
const log = [];
|
||||
|
||||
const ctx = { game, rng, engine, log, level: levelNum, seed };
|
||||
const ctx = {
|
||||
game, rng, engine, log, level: levelNum, seed,
|
||||
seeds: (opts && opts.seeds) || null, // optional override
|
||||
};
|
||||
const result = await strategy.run(ctx);
|
||||
|
||||
// Vertrag-Anreicherung — alle Felder garantieren
|
||||
|
||||
Reference in New Issue
Block a user