Conversation
Giszmo
force-pushed
the
feat/pathfinding-round-trip
branch
from
September 10, 2026 20:09
931367a to
6d75cc9
Compare
Units record the direction they step in, per cell (one counter per cell and direction, halved every 1024 ticks). Building a gradient charges an extra cost, per edge, for entering a passage against its prevailing direction, in proportion to the excess of opposing over same-way units, up to three tiles; directionByGradient sees the same cost. The first units through a gap set its direction and later units heading the other way take another gap; on open ground and beside a single wall nothing changes. Derived state, not saved. A passage is a cell in a channel at most two cells wide across one axis: walls on both sides, or a wall on one side and a wall right behind the free cell on the other. Each column of a 2-wide channel is its own passage, so the two take opposite directions on their own. Rebased onto the merged weighted pathfinder: the penalty is applied per edge inside the optimised propagation loop, which otherwise shares the two terrain costs of a cell across its eight reverse edges. Fable 5.1 helped authoring this commit.
Giszmo
force-pushed
the
feat/pathfinding-traffic-lanes
branch
from
September 10, 2026 20:39
6fbf26d to
dc5eb8a
Compare
Contributor
Author
|
Rebased onto #244 (the round-trip successor of #193): the branch is now the single lanes commit dc5eb8a on top of 62aa2dc. On Leo's petri map (no walled passages) it measures identical to #244, as expected; the choke-point evidence from the #193 thread still stands as the only case where the lane rule fires. |
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.
Stacked on #193 (round trip); one commit. Split out of the old #193 so it can be judged on its own evidence.
What it does. Units record the direction they step in, per cell (one Uint8 per cell and direction, halved every 1024 ticks). Building a gradient charges an extra cost, per edge, for entering a passage against its prevailing direction, in proportion to the excess of opposing over same-way units (full penalty at 16 units of excess, worth three tiles);
directionByGradientsees the same cost. The first units through a gap set its direction and later units heading the other way take another gap; on open ground and beside a single wall nothing changes. Derived state, not saved; one shared traffic layer for all teams.A passage is a cell in a channel at most two cells wide across one axis: walls on both sides, or a wall on one side and a wall right behind the free cell on the other (new since the old #193, which only knew 1-wide gaps). Each column of a 2-wide channel is its own passage, so the two take opposite directions on their own. That is the typical human layout: paired buildings that will merge after an upgrade leave 2-wide channels between them until then, and inns north of other buildings leave 1-wide ones.
Evidence. Nicowar never builds such layouts, so Nicowar-vs-Nicowar games cannot show the effect (they were flat within noise in the old #193, and are unchanged here). The fixture is a mid-game save of exactly such a base by @Giszmo (
FourSquares1_testing.game, team 0 human with a base of 2-wide channels, teams 1 and 2 Nicowar), run headlessly for about 16 000 ticks after the save point with the human team working its existing orders. A loaded game is deterministic, so the synchronous random generator was reseeded after loading with 12 different seeds per build (different sidestep and AI dice, same layout and state); means ± standard error over the 12, per 1000 ticks of play. "Blocked" counts non-strictdirectionByGradientcalls that found no step at all.Reading: on the human base the lanes cut blocked ticks by a third against master (and by a quarter against #193), with trips and deliveries unchanged; on the two AI teams blocking drops by a quarter to a third and trips get a few percent shorter. Output does not move: the units were blocked for a fraction of a tick per trip, so unblocking them shows in smoothness, not in deliveries. The old scripted choke fixture (3-thick wall, 1/2/4 one-wide gaps) from the previous #193 description still applies: two gaps, blocked ticks −64 %, deliveries +4.5 %; one or four gaps, no change.
Cost, and why this is a draft. Whole-game wall time on top of #193 (bash
time, alternated runs): 128² Mazury, 2 Nicowars, 15360 ticks: 3.97 s → 4.39 s (+11 %); 512² Mazury tiled 4x4, 8 Nicowars, 9216 ticks: 46.9 s → 57.4 s (+22 %). That is far more than the 3 to 5 % measured before #184's optimised propagation loop, because the lane check now runs per popped cell inside that loop (anyTrafficload plus up to eight gradient lookups inisPassage) for every field of every tick, and the traffic layer is 8 bytes per cell (2 MB on 512²) that the loop touches. Plan before asking for review: keep a passage bitmap per map, maintained incrementally where cases change (buildings, resources), so the loop tests one bit and one 8-byte load, and touch the traffic counters only for passage cells. If that does not bring the cost under a few percent on 512², this stays a draft.Known limits. One traffic layer for all teams (an enemy's traffic through a gap counts). The three constants (half-life 1024 ticks, full penalty at 16 excess units, three tiles) are first values. Traffic is not saved, so a loaded game starts with no lanes and re-learns them within a few hundred ticks.
Determinism: two runs of the same seed give identical checksum sidecars (the traffic counters are simulation state derived from unit steps, so they are the same on every peer). Tests: the three GradientTest cases from the old #193 (seeds beyond the bucket window, cost bound, lane penalty) plus the existing suites and harnesses.