code wiki / _hdl_build / nx_collide2d_gate.nx

nx_collide2d_gate.nx source

↩ module page · 260 lines · 11193 B

1// nx_collide2d_gate.nx -- liar-kill gate for the swept-collision part. Teeth map 1:1 onto the board's 2// named bar for a physics-collision HAVE (nx_gamebench.nx bit-5 comment): 3// T1 TUNNELING KILLED (swept/continuous): a mover faster than a thin wall per tick must STOP AT the 4// wall, never appear beyond it. A discrete endpoint test passes straight through -- the mutation. 5// T2 SLIDE: an oblique hit with rest=0 kills ONLY the normal component; motion continues along the 6// surface (not stopped dead, not bounced). 7// T3 RESTITUTION: a drop onto the floor with e=1/2 rebounds to ~e^2 of the drop height. 8// T4 DETERMINISM: two identical 500-tick runs produce the identical independent position checksum. 9// T5 BOUNDED: 10000 ticks of LCG-kicked flight inside a closed box NEVER escape it. 10// T6 SAVE TRANSPARENCY: gs_save mid-flight -> ZEROED state -> gs_load -> resume; every later tick's 11// independent ck identical to the uninterrupted run (GX-9 law: the walker is independent of the 12// save path, so a save that forgets a field cannot vouch for itself). 13// T7 ANTI-VACUITY: the mover actually moved and actually hit things (a frozen world passes the 14// invariants above while simulating nothing). 15// T8 CORNER: a diagonal shot into a corner resolves BOTH walls in ONE step (iterative TOI). 16// license_tier: ORIGINAL expect_exit: 0 17import "nx_syscalls.nx" 18import "nx_collide2d.nx" 19import "nx_gamesave.nx" 20const CG_BOXW: i64 = 20000 // closed test box edge 21const CG_GRAV: i64 = 4 // gravity impulse per tick 22const CG_DROPH: i64 = 18000 // restitution drop height 23const CG_BIG: i64 = 100000 // "infinite" wall extent 24const CG_LCGA: i64 = 1103515245 // LCG multiplier (glibc constants -- reproducible kicks) 25const CG_LCGC: i64 = 12345 26const CG_LCGM: i64 = 2147483648 27const CG_STAMP: i64 = 20260729 // caller-supplied save stamp (no hidden clock) 28const CG_SCHEMA: i64 = 77 29 30func gw2(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 31func gn2(v: i64) -> i64 { 32 let t: *u8 = sys_mmap(32) 33 var m: i64 = v 34 if m == 0 { sys_write(1, "0" as *u8, 1); return 0 } 35 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 36 var k: i64 = 0 37 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m/10; k = k + 1 } 38 while k > 0 { k = k - 1; sys_write(1, (t as i64 + k) as *u8, 1) } 39 return 0 40} 41// closed box: floor, ceiling, left, right (thin AABBs framing the interior 0..CG_BOXW) 42func mkbox(walls: *i64) -> i64 { 43 walls[0] = 0 - 100; walls[1] = 0 - 100; walls[2] = CG_BOXW + 100; walls[3] = 0 44 walls[4] = 0 - 100; walls[5] = CG_BOXW; walls[6] = CG_BOXW + 100; walls[7] = CG_BOXW + 100 45 walls[8] = 0 - 100; walls[9] = 0 - 100; walls[10] = 0; walls[11] = CG_BOXW + 100 46 walls[12] = CG_BOXW; walls[13] = 0 - 100; walls[14] = CG_BOXW + 100; walls[15] = CG_BOXW + 100 47 return 4 48} 49func st_init(st: *i64, px: i64, py: i64, vx: i64, vy: i64, r: i64) -> i64 { 50 st[0] = px; st[1] = py; st[2] = vx; st[3] = vy; st[4] = r; st[5] = 0; st[6] = 0 51 return 0 52} 53 54func main() -> i64 { 55 gw2("=== nx_collide2d_gate: swept collision + slide + impulse -- real, or a rubber stamp? ===\n\n" as *u8) 56 var pass: i64 = 0 57 var checks: i64 = 0 58 let nrm: *i64 = sys_mmap(16) as *i64 59 let walls: *i64 = sys_mmap(64*8) as *i64 60 let st: *i64 = sys_mmap(16*8) as *i64 61 62 // ---------- T1 tunneling killed ---------- 63 checks = checks + 1 64 // thin wall 4 units thick at half-box; mover r=10 covering 400/tick: far more than wall+2r per tick 65 // start x=50 so a discrete endpoint test would sample 450,850,...,9650,10050 -- every endpoint 66 // OUTSIDE the 24-unit inflated wall [9990..10014]: the mutation genuinely tunnels 67 walls[0] = CG_BOXW/2; walls[1] = 0 - CG_BIG; walls[2] = CG_BOXW/2 + 4; walls[3] = CG_BIG 68 st_init(st, 50, 0, 400, 0, 10) 69 var i: i64 = 0 70 var beyond: i64 = 0 71 while i < 100 { 72 c2_step(st, walls, 1, 0, 0, nrm) 73 if st[0] > CG_BOXW/2 { beyond = 1 } 74 i = i + 1 75 } 76 var t1ok: i64 = 0 77 if beyond == 0 { if st[5] >= 1 { if st[0] > CG_BOXW/2 - 20 { t1ok = 1 } } } 78 if t1ok == 1 { 79 gw2("T1 GREEN swept: 400/tick mover STOPPED AT the 4-unit wall (x=" as *u8); gn2(st[0]) 80 gw2(", contacts=" as *u8); gn2(st[5]); gw2(") -- an endpoint test would have tunneled\n" as *u8) 81 pass = pass + 1 82 } else { 83 gw2("T1 RED tunneling: mover ended beyond the wall (x=" as *u8); gn2(st[0]); gw2(")\n" as *u8) 84 } 85 86 // ---------- T2 slide preserves the tangent ---------- 87 checks = checks + 1 88 walls[0] = 0 - CG_BIG; walls[1] = 0 - CG_BIG; walls[2] = CG_BIG; walls[3] = 0 89 st_init(st, 0, 50, 300, 0 - 200, 10) 90 let x0: i64 = st[0] 91 i = 0 92 while i < 10 { c2_step(st, walls, 1, 0, 0, nrm); i = i + 1 } 93 var t2ok: i64 = 0 94 if st[3] == 0 { if st[2] == 300 { if st[0] - x0 >= 300*9 { if st[5] >= 1 { t2ok = 1 } } } } 95 if t2ok == 1 { 96 gw2("T2 GREEN slide: normal velocity killed (vy=0), tangent PRESERVED (vx=300), dx=" as *u8) 97 gn2(st[0] - x0); gw2(" over 10 ticks along the surface\n" as *u8) 98 pass = pass + 1 99 } else { 100 gw2("T2 RED slide broken: vx=" as *u8); gn2(st[2]); gw2(" vy=" as *u8); gn2(st[3]) 101 gw2(" dx=" as *u8); gn2(st[0] - x0); gw2("\n" as *u8) 102 } 103 104 // ---------- T3 restitution ~ e^2 on bounce height ---------- 105 checks = checks + 1 106 walls[0] = 0 - CG_BIG; walls[1] = 0 - CG_BIG; walls[2] = CG_BIG; walls[3] = 0 107 st_init(st, 0, CG_DROPH, 0, 0, 10) 108 var peak: i64 = 0 109 var phase: i64 = 0 110 i = 0 111 while i < 400 { 112 c2_step(st, walls, 1, 0 - CG_GRAV, 128, nrm) 113 if phase == 0 { if st[5] >= 1 { phase = 1 } } 114 if phase == 1 { if st[5] < 2 { if st[1] > peak { peak = st[1] } } } 115 i = i + 1 116 } 117 var t3ok: i64 = 0 118 let lo: i64 = CG_DROPH/4 - CG_DROPH/10 119 let hi: i64 = CG_DROPH/4 + CG_DROPH/10 120 if peak >= lo { if peak <= hi { t3ok = 1 } } 121 if t3ok == 1 { 122 gw2("T3 GREEN restitution: e=1/2 drop from " as *u8); gn2(CG_DROPH) 123 gw2(" rebounds to " as *u8); gn2(peak); gw2(" (~h*e^2=" as *u8); gn2(CG_DROPH/4); gw2(")\n" as *u8) 124 pass = pass + 1 125 } else { 126 gw2("T3 RED restitution: rebound peak " as *u8); gn2(peak) 127 gw2(" outside [" as *u8); gn2(lo); gw2("," as *u8); gn2(hi); gw2("]\n" as *u8) 128 } 129 130 // ---------- T4 determinism ---------- 131 checks = checks + 1 132 var run: i64 = 0 133 var ckA: i64 = 0 134 var ckB: i64 = 0 135 while run < 2 { 136 let nw: i64 = mkbox(walls) 137 st_init(st, CG_BOXW*3/20, CG_BOXW*3/4, 137, 0 - 60, 25) 138 var ck: i64 = 0 139 i = 0 140 while i < 500 { 141 c2_step(st, walls, nw, 0 - CG_GRAV, 90, nrm) 142 ck = c2_ck(ck, st[0]) 143 ck = c2_ck(ck, st[1]) 144 i = i + 1 145 } 146 if run == 0 { ckA = ck } 147 if run == 1 { ckB = ck } 148 run = run + 1 149 } 150 if ckA == ckB { 151 gw2("T4 GREEN deterministic: two 500-tick runs, identical position ck " as *u8); gn2(ckA); gw2("\n" as *u8) 152 pass = pass + 1 153 } else { 154 gw2("T4 RED nondeterministic: ck " as *u8); gn2(ckA); gw2(" vs " as *u8); gn2(ckB); gw2("\n" as *u8) 155 } 156 157 // ---------- T5 bounded under LCG kicks ---------- 158 checks = checks + 1 159 let nw5: i64 = mkbox(walls) 160 st_init(st, CG_BOXW/2, CG_BOXW/2, 250, 190, 25) 161 var esc: i64 = 0 162 var rng: i64 = CG_LCGC 163 i = 0 164 while i < 10000 { 165 rng = (rng*CG_LCGA + CG_LCGC) % CG_LCGM 166 if rng < 0 { rng = 0 - rng } 167 if rng % 97 == 0 { 168 st[2] = st[2] + (rng % 401) - 200 169 st[3] = st[3] + ((rng/1000) % 401) - 200 170 } 171 c2_step(st, walls, nw5, 0 - CG_GRAV, 110, nrm) 172 if st[0] < 0 - 200 { esc = 1 } 173 if st[0] > CG_BOXW + 200 { esc = 1 } 174 if st[1] < 0 - 200 { esc = 1 } 175 if st[1] > CG_BOXW + 200 { esc = 1 } 176 i = i + 1 177 } 178 if esc == 0 { 179 gw2("T5 GREEN bounded: 10000 LCG-kicked ticks never left the closed box (contacts=" as *u8) 180 gn2(st[5]); gw2(")\n" as *u8) 181 pass = pass + 1 182 } else { 183 gw2("T5 RED ESCAPED the closed box\n" as *u8) 184 } 185 186 // ---------- T6 save transparency ---------- 187 checks = checks + 1 188 let nw6: i64 = mkbox(walls) 189 st_init(st, CG_BOXW/5, CG_BOXW*3/5, 210, 0 - 45, 25) 190 var ckref: i64 = 0 191 i = 0 192 while i < 300 { 193 c2_step(st, walls, nw6, 0 - CG_GRAV, 100, nrm) 194 if i >= 150 { 195 ckref = c2_ck(ckref, st[0]) 196 ckref = c2_ck(ckref, st[1]) 197 ckref = c2_ck(ckref, st[3]) 198 } 199 i = i + 1 200 } 201 st_init(st, CG_BOXW/5, CG_BOXW*3/5, 210, 0 - 45, 25) 202 i = 0 203 while i < 150 { c2_step(st, walls, nw6, 0 - CG_GRAV, 100, nrm); i = i + 1 } 204 let sret: i64 = gs_save("knowledge/nx_collide2d_traj.sav" as *u8, CG_SCHEMA, st, 7, CG_STAMP) 205 var z: i64 = 0 206 while z < 7 { st[z] = 0; z = z + 1 } 207 let atp: *i64 = sys_mmap(32) as *i64 208 let lret: i64 = gs_load("knowledge/nx_collide2d_traj.sav" as *u8, st, 7, atp) 209 var cksv: i64 = 0 210 i = 150 211 while i < 300 { 212 c2_step(st, walls, nw6, 0 - CG_GRAV, 100, nrm) 213 cksv = c2_ck(cksv, st[0]) 214 cksv = c2_ck(cksv, st[1]) 215 cksv = c2_ck(cksv, st[3]) 216 i = i + 1 217 } 218 var t6ok: i64 = 0 219 if sret > 0 { if lret >= 7 { if cksv == ckref { t6ok = 1 } } } 220 if t6ok == 1 { 221 gw2("T6 GREEN save-transparent: save@150 -> ZEROED -> load -> resume; ck " as *u8); gn2(cksv) 222 gw2(" == uninterrupted " as *u8); gn2(ckref); gw2("\n" as *u8) 223 pass = pass + 1 224 } else { 225 gw2("T6 RED save NOT transparent: resumed ck " as *u8); gn2(cksv) 226 gw2(" vs reference " as *u8); gn2(ckref); gw2(" (save rc=" as *u8); gn2(sret) 227 gw2(" load rc=" as *u8); gn2(lret); gw2(")\n" as *u8) 228 } 229 230 // ---------- T7 anti-vacuity ---------- 231 checks = checks + 1 232 var t7ok: i64 = 0 233 if st[5] >= 3 { if st[0] != CG_BOXW/5 { t7ok = 1 } } 234 if t7ok == 1 { 235 gw2("T7 GREEN anti-vacuity: the mover moved and contacted (contacts=" as *u8); gn2(st[5]); gw2(")\n" as *u8) 236 pass = pass + 1 237 } else { 238 gw2("T7 RED vacuous: a frozen world would have passed the invariants above\n" as *u8) 239 } 240 241 // ---------- T8 corner: two walls in ONE step ---------- 242 checks = checks + 1 243 let nw8: i64 = mkbox(walls) 244 st_init(st, 300, 300, 0 - 900, 0 - 900, 25) 245 c2_step(st, walls, nw8, 0, 0, nrm) 246 var t8ok: i64 = 0 247 if st[5] == 2 { if st[2] == 0 { if st[3] == 0 { if st[0] >= 0 { if st[1] >= 0 { t8ok = 1 } } } } } 248 if t8ok == 1 { 249 gw2("T8 GREEN corner: both walls resolved in one step (contacts=2), rest=0 kills both axes, stays inside\n" as *u8) 250 pass = pass + 1 251 } else { 252 gw2("T8 RED corner: contacts=" as *u8); gn2(st[5]); gw2(" vx=" as *u8); gn2(st[2]) 253 gw2(" vy=" as *u8); gn2(st[3]); gw2("\n" as *u8) 254 } 255 256 gw2("\n=== nx_collide2d_gate " as *u8); gn2(pass); gw2("/" as *u8); gn2(checks) 257 if pass == checks { gw2(" GREEN ===\n" as *u8); return 0 } 258 gw2(" RED ===\n" as *u8) 259 return 1 260}