code wiki / _hdl_build / nx_wasm_physlab_gate.nx

nx_wasm_physlab_gate.nx source

↩ module page · 141 lines · 6249 B

1// nx_wasm_physlab_gate.nx -- gate for PHYSLAB (the visible consumer of phys3d+softjiggle; reuse-census W2). 2// T1 the crate stack settles and SLEEPS in the composed world; spheres come to rest 3// T2 the chain follows a moving mouse anchor with jiggle lag (never rigid-locked to it) 4// T3 the chain dragged across the pillar NEVER penetrates the capsule 5// T4 determinism: two labs, same scripted mouse -> byte-identical physics + jiggle state 6// T5 render: frame draws (nonblack majority) + PNG knowledge/nx_physlab.png (the eyeball) 7// T6 click-spawn adds a crate; it lands and eventually sleeps 8// license_tier: ORIGINAL expect_exit: 0 9import "nx_syscalls.nx" 10import "nx_png.nx" 11import "nx_wasm_physlab.nx" 12 13func hw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 14func pn(v: i64) -> i64 { 15 let b: *u8 = sys_mmap(32) as *u8 16 var x: i64 = v 17 var neg: i64 = 0 18 if x < 0 { neg = 1; x = 0 - x } 19 var i: i64 = 31 20 if x == 0 { b[i] = 48 as u8; i = i - 1 } 21 while x > 0 { b[i] = (48 + x % 10) as u8; x = x / 10; i = i - 1 } 22 if neg == 1 { b[i] = 45 as u8; i = i - 1 } 23 sys_write(1, (b as i64 + i + 1) as *u8, 31 - i) 24 return 0 25} 26func gabs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } 27func isq(v: i64) -> i64 { if v <= 0 { return 0 } var x: i64 = v; var y: i64 = (x + 1) / 2; while y < x { x = y; y = (x + v / x) / 2 } return x } 28 29func main() -> i64 { 30 var fails: i64 = 0 31 32 // T1 settle + sleep (mouse parked far away, no clicks) 33 let L: i64 = sys_mmap(mem_bytes()) as i64 34 start_at(L) 35 var t: i64 = 0 36 while t < 900 { tick_at(L, 40, 40, 0); t = t + 1 } 37 let bodies: i64 = body_count_at(L) 38 let asleep: i64 = asleep_count_at(L) 39 var t1: i64 = 1 40 if bodies != 8 { t1 = 0 } // ground + 5 crates + 2 spheres 41 if asleep != 7 { t1 = 0 } // all 7 dynamics asleep 42 if t1 == 1 { hw("T1 PASS composed world settles: 7/7 dynamic bodies ASLEEP after 900 ticks (crates stacked, spheres rested)\n" as *u8) } 43 else { hw("T1 FAIL bodies=" as *u8); pn(bodies); hw(" asleep=" as *u8); pn(asleep); hw("\n" as *u8); fails = fails + 1 } 44 45 // T2 chain lag: sweep the mouse; the chain tip must trail the anchor (jiggle, not rigid) 46 var lagticks: i64 = 0 47 t = 0 48 while t < 120 { 49 tick_at(L, 60 + t * 2, 60, 0) 50 let tip: *i64 = sj_node(L + 721024, 4) 51 let st2: *i64 = (L + 739584) as *i64 52 if gabs(tip[0] - st2[4]) > 200 { lagticks = lagticks + 1 } 53 t = t + 1 54 } 55 if lagticks > 60 { hw("T2 PASS chain trails the moving anchor (lag on " as *u8); pn(lagticks); hw("/120 sweep ticks = secondary motion, not rigid)\n" as *u8) } 56 else { hw("T2 FAIL lagticks=" as *u8); pn(lagticks); hw("\n" as *u8); fails = fails + 1 } 57 58 // T3 drag the chain across the pillar: nodes never inside the capsule (r=300 at x=1800, y 0..1500) 59 var minr: i64 = 99999 60 t = 0 61 while t < 260 { 62 var mx: i64 = 260 - t // sweep the mouse right-to-left across the pillar 63 tick_at(L, mx, 130, 0) 64 var c: i64 = 0 65 while c < 5 { 66 let n: *i64 = sj_node(L + 721024, c) 67 if n[1] >= 0 { if n[1] <= 1500 { 68 let dx: i64 = n[0] - 1800 69 let dz: i64 = n[2] 70 let d: i64 = isq(dx * dx + dz * dz) 71 if d < minr { minr = d } 72 } } 73 c = c + 1 74 } 75 t = t + 1 76 } 77 if minr >= 296 { hw("T3 PASS chain dragged across the pillar: min node distance " as *u8); pn(minr); hw("/300 -- capsule NEVER penetrated\n" as *u8) } 78 else { hw("T3 FAIL minr=" as *u8); pn(minr); hw("\n" as *u8); fails = fails + 1 } 79 80 // T4 determinism: two fresh labs, same script 81 let A: i64 = sys_mmap(mem_bytes()) as i64 82 let B: i64 = sys_mmap(mem_bytes()) as i64 83 start_at(A) 84 start_at(B) 85 t = 0 86 while t < 400 { 87 var mx2: i64 = 80 + (t * 3) % 160 88 var bt: i64 = 0 89 if (t % 97) == 50 { bt = 1 } 90 tick_at(A, mx2, 90, bt) 91 tick_at(B, mx2, 90, bt) 92 t = t + 1 93 } 94 var diff: i64 = 0 95 var k: i64 = 0 96 while k < 8256 / 8 { 97 let pa: *i64 = (A + 614400) as *i64 98 let pb: *i64 = (B + 614400) as *i64 99 if pa[k] != pb[k] { diff = diff + 1 } 100 k = k + 1 101 } 102 k = 0 103 while k < 18496 / 8 { 104 let sa: *i64 = (A + 721024) as *i64 105 let sb: *i64 = (B + 721024) as *i64 106 if sa[k] != sb[k] { diff = diff + 1 } 107 k = k + 1 108 } 109 if diff == 0 { hw("T4 PASS determinism: 400 scripted ticks incl clicks -> physics+jiggle state IDENTICAL\n" as *u8) } 110 else { hw("T4 FAIL diff-slots=" as *u8); pn(diff); hw("\n" as *u8); fails = fails + 1 } 111 112 // T5 render + PNG 113 render_at(A) 114 let fb: *i64 = (A + fb_off()) as *i64 115 var nonblack: i64 = 0 116 var pi: i64 = 0 117 while pi < ww() * hh() { 118 if fb[pi] != 0 { nonblack = nonblack + 1 } 119 pi = pi + 1 120 } 121 write_png(fb, ww(), hh(), "knowledge/nx_physlab.png" as *u8) 122 if nonblack * 10 >= ww() * hh() * 9 { hw("T5 PASS render draws the lab (nonblack=" as *u8); pn(nonblack); hw(") + PNG knowledge/nx_physlab.png\n" as *u8) } 123 else { hw("T5 FAIL nonblack=" as *u8); pn(nonblack); hw("\n" as *u8); fails = fails + 1 } 124 125 // T6 click-spawn on a fresh lab: body appears, then sleeps 126 let C: i64 = sys_mmap(mem_bytes()) as i64 127 start_at(C) 128 tick_at(C, 200, 80, 0) 129 tick_at(C, 200, 80, 1) // click edge 130 var t6: i64 = 1 131 if body_count_at(C) != 9 { t6 = 0 } 132 t = 0 133 while t < 900 { tick_at(C, 40, 40, 0); t = t + 1 } 134 if asleep_count_at(C) != 8 { t6 = 0 } 135 if t6 == 1 { hw("T6 PASS click spawns a crate (9 bodies) and the world re-settles ALL ASLEEP (8/8)\n" as *u8) } 136 else { hw("T6 FAIL bodies=" as *u8); pn(body_count_at(C)); hw(" asleep=" as *u8); pn(asleep_count_at(C)); hw("\n" as *u8); fails = fails + 1 } 137 138 if fails == 0 { hw("VERDICT GREEN: physlab 6/6 -- phys3d+softjiggle WIRED into a visible surface (reuse W2), deterministic, capsule-safe (PNG knowledge/nx_physlab.png)\n" as *u8) } 139 else { hw("VERDICT RED fails=" as *u8); pn(fails); hw("\n" as *u8) } 140 return fails 141}