e25a00175a68724e92f7de5e44d078fcbbfff9f7
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
10723ab5f3 | strafe: default range 200 -> 325 (mid of the owner's 300-350 band), with the j107 evidence noted | ||
|
|
ccff7e3e4a |
STRAFE: curved wings + guaranteed wall/corner escape; shipped TFIL default untouched
Task j112. Two changes to the TR_MOVEMENT=strafe engine, both OFF the shipped tfil path; the binary default is still tfil. CURVED WINGS: the candidate set was the straight 1-D line through the bot, which a bounded segment always terminates at a wall. It is now an adaptive parabola with the vertex on the bot: point(y) = bot + yhat*y + xhat*kappa(y)*y^2 xhat is the unit vector away from the nearest wall(s) (summed inward normals, so a corner yields the diagonal). kappa grows as the wall approaches and saturates at TR_STRAFE_KAPPA; every wing point is clamped inside TR_STRAFE_WALL_SAFE, so the wing FLATTENS and runs parallel to the wall instead of touching it. In open space kappa == 0 and the wing is exactly the old straight line. The wing chord at the reach tilts the heading band toward the interior by atan(kappa*reach) (capped by TR_STRAFE_WING_MAX); the body still only turns slowly to follow that tangent, never to face the target, and reversals are still setForward sign flips. GUARANTEED ESCAPE: with every candidate over threshold the old fallback minimised pathMaxHeat, whose gradient points AT the wall (the shortest path has the least wall exposure), so the least-hot tile was the adjacent one and led further along the wall. Near a wall the picker now ranks by the DESTINATION (farthest from the wall, then coolest tile) and commands the sign whose velocity has a positive component along the wall-away normal. That sign is re-asserted EVERY tick, so speed*heading . away >= 0 while escape is active: the clearance cannot fall. mode=escape reaches the [strafe] log. A mild wall-margin bias (TR_STRAFE_WALL_BIAS) prefers higher-clearance tiles when near a wall. GUI/log: the curved wings are drawn as an orange polyline (candidates follow the curve), a white ray + ESCAPE label marks the escape, and the [strafe] line now carries wall=<dist> kappa=<..> mode=<pick|fallback|escape|radial>. Gates (offline, kinematic replay of the DrussGT fixtures; see common_libs/tests/measure_strafe_wings.nim, plus the reused j108/j111 gates): wall occupancy (within 54 px) falls 25.6->4.3 / 18.3->4.1 / 23.8->4.3 / 27.8->4.7 percent and the longest continuous wall run 191->31 / 49->25 / 208->47 / 246->27 ticks; corner-region occupancy 4.7->0.0 percent with the longest corner run 71->7. The escape sweep (3520 start x heading x enemy runs, 110k escape ticks) shows ZERO per-tick guarantee violations and a worst corner run of 21 ticks. Open-space parity is bit-identical (kappa == 0), reversals are still sign flips (0 non-sign commands), and mean turn/speed are unchanged (OFF 4.42 deg/tick, 31.3 percent no-turn vs ON 4.45 / 30.7; reversal-interval entropy 5.309 -> 5.311 bits). The fixtures are OPEN-LOOP, so these are veto-capable checks, not a live win claim. |
||
|
|
ed25ce29ad |
STRAFE: range control (tilt) + corner-stall escape; shipped TFIL default untouched
Task j111. Two changes to the TR_MOVEMENT=strafe engine, both OFF the shipped tfil path; the binary default is still tfil. RANGE CONTROL (a hypothesis under test, no default changed elsewhere): the body is still pinned ~perpendicular to the threat, but the line is tilted by the range error: lineAngle = threat + 90 + appliedTilt, with the tilt zero inside +/-TR_STRAFE_RANGE_TOL around TR_STRAFE_RANGE (200 px, chosen because it is exactly TR_POWER_FAR_DIST) and clamped to +/-TR_STRAFE_TILT_MAX. A tilt alone cannot change range (the picker chooses both ends at random), so the picker also PREFERS the end that reduces |distance - target| with a probability that grows with |tilt|; both ends stay possible. The tilt sign is aligned to the ENEMY bearing, since is the bullet direction (roughly its opposite) when a bullet is in flight. Knobs: TR_STRAFE_RANGE (200), TR_STRAFE_RANGE_TOL (25), TR_STRAFE_TILT_MAX (15), TR_STRAFE_TILT_GAIN (0.10), all registered in env_report.nim (emit + knownEnvNames). NOT claimed to be better: j107 measured that drifting 25-30 px closer made damage/run and wins WORSE. CORNER STALL (a real defect): a line whose in-arena candidate set was empty set targetValid=false and kept driving on the last sign, so the bot could oscillate inside a corner tile forever. Three defenses: (1) a deterministic corner guard projects the outward component off the line whenever BOTH ends are outside, so the line becomes wall-parallel and a candidate always exists; (2) a degenerate line (<=1 candidate) falls back to a radial search for the coolest in-arena tile and commits the sign; (3) a commanded move with no displacement for StuckFlipTicks (5) ticks flips the sign. Both warnings now reach the [strafe] log. GUI/log: the tilt is drawn as the existing strafe line (it is lineForward), plus a green/red ray toward the enemy (length = |distance-target|) and white text d=.. tgt=.. tilt=..; a red disc marks a stuck tick. The existing overlays and the j110 heat grid are unchanged. Gates (offline, kinematic replay of the DrussGT fixtures; see common_libs/tests/measure_strafe_range_stall.nim): on the j110 field all four corners that were 100% confined inside 72 px / 22.6 px max before now escape (<=2.6% confined, 209-741 px); the achieved |distance-200| falls on 3 of 4 fixtures (mean -16% to -30%); mean |turnRate| and the 8.00 px/tick speed are essentially unchanged (no-turn property survives). Reversal-interval entropy falls 5.85 -> 5.31 bits (still above TFIL's 5.09): the range bias costs some reversal randomness while closing. |
||
|
|
1ea84f5b6e |
STRAFE: draw the heat field, real bullet danger, corrected ring comment
Three defects the owner hit as "no heat tiles anymore" under TR_MOVEMENT=strafe. 1. The strafe overlay drew ONLY the tiles on its strafe line, so the computed heat field was essentially invisible. It now draws the WHOLE field exactly as TFIL does (every non-zero tile, yellow->orange->red ramp by field max, integer value label) behind the same debugGraphics flag, with TR_STRAFE_HEAT_GRID=0 to hide it. The strafe overlays draw on top, unchanged. 2. STRAFE carried the SHIPPED bullet constants (core 10 / aura 5), so a bullet's own heat sat exactly ON PathDangerThreshold (10.0) and a bullet was never dangerous on its own in this mover; it only ever bit through its corridor. Defaults are now the retune's 20/10, exposed as TR_STRAFE_BULLET_CORE / TR_STRAFE_BULLET_AURA. 3. The ring mover's header documented CorridorHeat 5.0 / WallHotness 10.0 while the code has always been 10.0 / 15.0. A job read the comment and handed out sub-threshold heat values, which emptied the field. The comment now states the real values and their actual behaviour; no code values changed. Also sets strafe's heat defaults to the retune shape (bullet 20/10, corridor 10, wall 15/5, pillar 0), documented with the reason. Gate A re-run (j110, offline DrussGT fixture, measure_strafe_gates.nim): corrected DEFAULT : 24.6% of picks with ZERO safe tile, mean 11.17 safe j108 shipped field: 63.4% / 3.70 (reproduced exactly) j108 ring retune : 8.1% / 18.41 (reproduced exactly) bullet isolated : 11.4% / 17.07 The corrected default beats the shipped field but is WORSE than j108's retune row: the bullet retune alone costs 8.1 -> 11.4, the corridor/wall retune accounts for the rest. That is the deliberate price of making a bullet dangerous. Guards green: test_env_report 24 PASS, test_tfil_commit_env 30 PASS (shipped TFIL default untouched, byte-for-byte), test_tfil_ring_weights 24 PASS. The three new knobs are registered in the boot env report so the tree-scan guard stays clean. |
||
|
|
a50c0125d5 |
STRAFE movement: body pinned perpendicular to the threat, reversals by sign flip
New engine movements/strafe.nim, selected by TR_MOVEMENT=strafe (default stays tfil, byte-identical — test_tfil_commit_env.nim's 30 checks still pass). Design (the owner's): - AXIS = incoming bullet's direction when a bullet is in flight, else the perpendicular of the enemy bearing. The body heading is kept inside a band (TR_STRAFE_BAND, default 20 deg) around the perpendicular LINE; it turns only when outside the band, and never turns to face a movement target. - Candidate tiles on the perpendicular line through our position, both forward and backward, within TR_STRAFE_REACH px, with a perpendicular jitter of +/- TR_STRAFE_SPREAD tiles. A tile is acceptable when its path max heat is <= PathDangerThreshold, the SAME safety rule TFIL uses. - Move by SIGN only: setForward(+/-MaxSpeed>). Dwell is re-picked after a random number of ticks in [TR_STRAFE_DWELL_MIN, TR_STRAFE_DWELL_MAX], on arrival, or on a serious threat spike. - Heat machinery is REUSED from the shipped mover, not re-implemented: the exported heatDecay()/bulletMagScale() (j105 time-indexed model) and the PillarHotness/PillarRadiance globals (j106 pillar-free default). The heat shape is overridable via TR_STRAFE_CORRIDOR_HEAT/WALL_HOTNESS/WALL_RADIANCE (defaults = the shipped TFIL field). - GUI overlay: strafe line, threat axis, candidate tiles (safe/unsafe), chosen target, sign-coloured movement ray, and the heading band. Gates (offline, recorded DrussGT fixture, 20026 ticks): - A TILE AVAILABILITY: shipped heat field -> a safe tile exists on only 36.6% of picks (63.4% fall back to the least-hot tile); the ring retune (corridor 5, wall 10/5) raises it to 91.9%. - B PREDICTABILITY: reversal-interval entropy 5.84 bits vs TFIL 5.09; direction entropy 1.00 both; long-lag autocorrelation ~0 for both (no periodic component). Fewer reversals (710 vs 1453) and more full-speed ticks. measurements: common_libs/tests/measure_strafe_gates.nim Also registers TR_STRAFE_* in the boot env report (ModularBot_garage/src/ env_report.nim) and wires the engine into ModularBot.nim (hold -> strafe, ram trigger -> rammer). |