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}