Repository navigation
Longer solve attempts, kept per-island solves, and a faster engine - #8
Merged
Merged
Conversation
The two-class bound under a terrain bonus credited every generator with the eight-neighbour cap at the shore rating, as if each were ringed by boosted reactors and coolers. Only tiles one step from the coast can be. Once the cap binds - generator7 over any reactor short of the top tiers, where a ring of eight feeds about 65% of its rating - that was slack. Each generator is now held to what its own neighbours can feed, counted by class (shore or inland). On a late roster (full unlocks less cooler8 and ecto_compressor, precursor_pyramid tier 3) the Tidal bound drops 0.1-1.8% across the shipped maps; full unlocks and weaker rosters do not move. A binding-cap island with hand-built and 300 arbitrary layouts pins it. With intake no longer linear the inland reactor split had to be found by bisection, for every shore split of every engine split: ~100ms a call on Event Horizon and Entropy Isles, read several times per render. Each shore reactor added raises the heat side and lowers the intake side, so the crossing only moves down; it is now carried from one shore split to the next and galloped down from there. Both sides stay monotone in floating point, so it finds the same count a fresh bisection did and every map's bound is bit-identical. 946ms to 18.5ms across all maps, faster than before the cap was added.
Deep is now 5 x 20s and Max 25 x 20s, at the same cost as 10 x 10s and 50 x 10s. A walk on a large island is still climbing well past 10s on a late roster: over all eight maps the search reaches 91.7% of the bound at 10s, 92.9% at 20s and 93.6% at 40s (late roster, no anomaly), 95.3% and 96.1% at full unlocks, and one 20s walk matches the best of three 10s ones at two-thirds of the time. Both Tidals gain no more than the base rules, so they take no attempt factor; Singularity keeps its 2x. The mode dialog's note now gives each anomaly's own reason. Islands run side by side, so a run whose every task has a worker of its own lasts as long as its largest slice, not the 30s Quick advertises - 16-24s on boards of two large islands. fitBudgetsToPool, now in the solver package beside islandBudgetsS, stretches the slices until the largest is the whole budget when the run fits the pool; a run that queues keeps the summed split. The coordinator, the run estimate and the CLI's pooled run all use it, so the CLI's figures match what the app's Quick gets on the same board. The survey keeps the summed split - it measures one attempt's slices, which is what a queued Deep or Max spends. The mode dialog, README, CLI docstring and docs/SOLVER.md are brought up to the new figures.
"Keep the better layout" compared whole boards, so on a board of several islands a re-run that found a better large island won on the total and brought a worse small island with it. Islands never interact, so composeIslandBests now builds boards from each island's best answer across the held and fresh shortlists, and those stand in for the fresh run before the whole-board comparison. It returns null when one board already holds every best (and under a shared cooling pool, which is one island). Under an upgrade plan islands are compared on the power after the plan. Only held layouts still standing on grass are offered, so terrain painted since cannot carry a building onto rock. A two-island board driven through runOptimizer pins the merge. A game import changes the roster, the research and usually the terrain, all in a solve's signature, so every island's solve was discarded though most were still buildable. carryOverSolves now runs before restore() on a game import and decides per island: a solve is dropped for an island still locked in the game or searched under another anomaly; a layout is dropped if an imported obstacle covers one of its buildings or the roster no longer unlocks one. Everything else is re-tiered, re-scored on its new board and re-filed under its new signature. restore() does the same when only the roster, research or anomaly differ, so an island opened after a Setup change keeps its solve, re-rated. Changed terrain is still discarded. settleOptimizer stops a run in flight and waits for it to file, so a late result cannot land over the carried-over record. A pre-anomaly record's unknown anomaly id now resolves to the base rules. Every worker reports on its own clock, so a pool of eight handed the main thread up to eight full boards a second. On a page slowed 6x a Deep run kept the main thread busy 9.5s of 11s, and a main thread that falls behind stops updating the board and never forwards Stop. The coordinator now hands the page at most one update per report interval, still drawing the best anything has reported, and cancels a pending update when the run settles: 4.3s busy, 22 long tasks instead of 87. "Discard this layout" now removes it from the board and from storage as the run starts, so a run stopped before it reports cannot hand it back.
…arity Seed construction re-simulated every generator combination for every stale tile on every round; a shared fit depends only on the neighbourhood's shape under a uniform or role-wide rating, so it is memoised by that shape and the seed is 3.5x faster, bit for bit. greedyPolish re-sweeps only tiles within two of an applied move and re-simulates a cached winner before applying it: a wash at 15s per map, +5-9% under Tidal and +16% on Shadowspire under Singularity at 5s, where the polish share binds. The distribution's repair ends each search when the first consumer with room is enqueued rather than dequeued (the same path, the queue being FIFO) and keeps a per-component list of suppliers with supply left: 17% off a Cryo whole-board simulation, 9% off the base rules, bit-identical over 5054 random instances and the fixtures. The collector's tie check drops a redundant key string, targetCompositions keeps only its top three while enumerating, Singularity's layout copy folds into the scan loop, and the post-deadline cleanup yields between alternates. Under Singularity the seed now sizes each hub at the generator's isolated rating and claims no hub whose generator would stand beside another, and solveIsland starts from whichever of that seed and the plain one repairs higher: a wash at 15s, +14% and +18% on the two largest maps at 5s, nothing lost at generator7 tier 3 or under any other rule. Reheating reclaim rounds to a tenth of the walk temperature and an un-crowding move in the walk were both measured as noise and left out; the comments record them. `npm run profile` is the stage-cost instrument behind all of this. goldenLayoutsFullTier.test.ts is reformatted.
A pure move: every line of the old file lands verbatim in exactly one of search/placement, stability, seed, anneal, composition, repair, rightSize and pooledCoolers, or stays in placementSearch.ts with solveIsland, the budget split, the deterministic replay and `internals`. That module still exports exactly what it did, so no import site changes. Imports and exports were derived from what each body uses, and the new modules form no cycle. The one edit is a doc comment, "Solves one island", which sat above replayIslandDeterministic and now sits on solveIsland. The fixtures reproduce byte for byte and the stage profiler cannot tell the two trees apart. The worker-safety layering rule read `../x` as leaving src/solver/, which holds only for a module directly inside it: a subfolder importing `../constants` would have been refused. Each specifier is now resolved against the importing file's own folder, and the cases a subfolder raises are pinned.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Five commits, each passing
npm run checkandnpm teston its own:fitBudgetsToPoolmoves into the solver package so the app's Quick and the CLI's pooled run both use the full budget. Copy and docs updated.npm run profile.solver/search/, plus the worker-safety layering test resolving imports relative to each file.Fixtures reproduce byte for byte across the engine refactors; golden-layout optima do not go down.