Professional City Advisor rewrite + wall-clock simulation

Advisor v2:
- Phased policy (founding/village/town/city) with scaling reserves
- Maximal-coverage siting: services score candidate spots by count of
  previously-uncovered developed buildings in radius
- RCI gradient genesis: homes north, commerce buffering, industry
  set back 2 extra tiles; per-tile separation filters on new districts
- District placement scored by runway length and distance from housing
- Power sized to PROJECTED demand (history-smoothed growth x14 months)
  with tech diversity cap (<=3 per type) and home-distance scoring
- Collector roads: cluster orphaned plots, one straight L-path
- Budget discipline: one big-ticket purchase max per pass

Simulation core:
- City clock now advances in wall time (tick-guard bounded), decoupled
  from render fps — slow devices no longer freeze the city
- Smoke test polls in game-time (monthIndex targets), not wall time
This commit is contained in:
PolyCity
2026-08-23 04:59:48 +00:00
parent 1b6b31732b
commit 209d8efdf5
7 changed files with 442 additions and 192 deletions
+7 -3
View File
@@ -149,13 +149,17 @@ await safe('shot-built', () => shot(join(SHOTS,'x') || { path: join(SHOTS, '02-b
// ---- simulate ~14 months at fast speed ----
await safe('speed2', () => page.evaluate(() => window.POLYCITY.setSpeed(2)));
for (let k = 0; k < 11; k++) {
// wait in GAME time, not wall time: environments render at wildly
// different speeds, so poll until the city has lived >= 8 months
for (let k = 0; k < 24; k++) {
await sleep(2000);
const s = await safe('probe' + k, () => page.evaluate(() => ({
pop: window.POLYCITY.city.stats.pop,
dev: [...window.POLYCITY.city.grid.level].filter(v => v > 0).length
dev: [...window.POLYCITY.city.grid.level].filter(v => v > 0).length,
m: window.POLYCITY.city.monthIndex
})), 8000);
LOG(`t+${(k + 1) * 2}s pop=${s?.pop ?? '?'} dev=${s?.dev ?? '?'}`);
LOG(`probe${k}: month=${s?.m ?? '?'} pop=${s?.pop ?? '?'} dev=${s?.dev ?? '?'}`);
if (s && s.m >= 8 && s.pop > 40) { LOG('sim target reached'); break; }
}
const state = await safe('state', () => page.evaluate(() => {