code wiki / _hdl_build / nx_wasm_pong_gate.nx
nx_wasm_pong_gate.nx source
↩ module page · 97 lines · 5679 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_wasm_pong_gate.nx -- NATIVE gate for the browser-playable Pong core (nx_wasm_pong).
4// T1 RETURN + SCORE: a ball aligned with the paddle is RETURNED (bvx flips); a missed ball SCORES.
5// T2 RENDER REAL: a green player paddle + a red AI paddle + a white ball (PNG).
6// T3 WALL BOUNCE: the ball reflects off the top wall (bvy flips).
7// T4 NEVER-BRICK (#26): deterministic, bounded, no float, base-relative.
8// expect_exit: 0 license_tier: ORIGINAL
9import "nx_wasm_pong.nx"
10import "nx_png.nx"
11import "nx_syscalls.nx"
12import "nx_gate_verdict.nx"
13
14func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
15" as *u8); return ok }
16
17func main() -> i64 {
18 gw("=== nx_wasm_pong_gate: browser-playable Pong core, verified NATIVE before wasm ===\n" as *u8)
19 var pass: i64 = 0; var total: i64 = 0
20 let base: i64 = sys_mmap(2*1024*1024) as i64
21 let st: *i64 = (base + O_ST) as *i64
22
23 // ---- T1: return + score ----
24 init_impl(base)
25 st[0] = LX + 3; st[2] = 0 - 3; st[1] = st[4] // ball at the paddle, aligned
26 tick_impl(base, 0)
27 let returned: i64 = st[2] // should flip to +3
28 init_impl(base)
29 st[0] = 1; st[2] = 0 - 3; st[4] = H - PADH // ball at top heading off the left, paddle low
30 let rs0: i64 = st[7]
31 tick_impl(base, 0)
32 let scored: i64 = st[7] - rs0
33 var t1ok: i64=1; if returned <= 0 {t1ok=0} if scored != 1 {t1ok=0}
34 total=total+1; if t1ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
35 gw("T1 return+score: aligned paddle returned the ball (bvx=" as *u8); gn(returned); gw("), a miss scored (+" as *u8); gn(scored); gw(")\n" as *u8)
36
37 // ---- render a mid-rally frame ----
38 init_impl(base)
39 var a: i64=0; while a < 12 { tick_impl(base, 0); a=a+1 }
40 render_impl(base)
41 let fb: *i64 = (base + O_FB) as *i64
42 write_png(fb, W, H, "knowledge/nx_wasm_pong_native.png" as *u8)
43 gw(" (live evidence: PNG knowledge/nx_wasm_pong_native.png -- paddles + ball + scores)\n" as *u8)
44
45 // ---- T2/T5/T6: render real -- BOTH PADDLES ARE ACTUALLY IN THE PICTURE ----
46 // ★THE OLD TOOTH WAS HALF VACUOUS AND COMPOUND, so it could not name the failing half. The
47 // background is rgb(12,16,22), whose g=16 EXCEEDS r=12 -- so "player paddle green" passed on
48 // EMPTY BACKGROUND and would have kept passing with the paddle draw deleted. (The AI conjunct was
49 // genuine: the background is not reddish.) Found 2026-08-14 by nx_vacuity_census, the same class
50 // as nx_wasm_shmup_gate and nx_wasm_racing_gate.
51 // Both are now DIFFERENCES against the background, naming no colour, each its own counted tooth.
52 let lp: i64 = fb[st[4]*W + LX]
53 let rp: i64 = fb[st[5]*W + RX]
54 let bg1: i64 = fb[(H-10)*W + (W/4)]
55 let bg2: i64 = fb[(H-10)*W + (W/4 + 4)]
56 total=total+1; if lp != bg1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
57 gw("T2 render real: the PLAYER paddle is in frame -- differs from the background (paddle=" as *u8); gn(lp); gw(" bg=" as *u8); gn(bg1); gw(")\n" as *u8)
58
59 total=total+1; if rp != bg1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
60 gw("T5 render real: the AI paddle is in frame -- differs from the background (paddle=" as *u8); gn(rp); gw(" bg=" as *u8); gn(bg1); gw(")\n" as *u8)
61
62 // neg-control: the two background samples must AGREE, or the teeth above could be passing on
63 // ordinary background variation. A centre dash or the ball landing on one makes this FAIL LOUDLY.
64 total=total+1; if bg1 == bg2 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
65 gw("T6 neg-control-background-uniform: two background samples agree (" as *u8); gn(bg1); gw(" vs " as *u8); gn(bg2); gw(")\n" as *u8)
66
67 // ---- T3: wall bounce ----
68 init_impl(base)
69 st[1] = 2; st[3] = 0 - 2
70 tick_impl(base, 0)
71 var t3ok: i64=1; if st[3] <= 0 {t3ok=0}
72 total=total+1; if t3ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
73 gw("T3 wall bounce: the ball reflected off the top wall (bvy=" as *u8); gn(st[3]); gw(")\n" as *u8)
74
75 // ---- T4: determinism ----
76 init_impl(base)
77 a=0; while a < 30 { tick_impl(base, 0); a=a+1 }
78 let bx1: i64 = st[0]; let by1: i64 = st[1]
79 init_impl(base)
80 a=0; while a < 30 { tick_impl(base, 0); a=a+1 }
81 var t4ok: i64=1; if st[0] != bx1 {t4ok=0} if st[1] != by1 {t4ok=0}
82 total=total+1; if t4ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
83 gw("T4 never-brick (#26): deterministic re-run (ball " as *u8); gn(st[0]); gw("," as *u8); gn(st[1]); gw("), base-relative, no float, no sys_mmap in the core\n" as *u8)
84
85 gw("\n=== nx_wasm_pong_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
86 // D001 ANCHOR: the rich line above stays as this gate's public signature; the canonical verdict
87 // goes LAST because the estate's judge anchors by POSITION, taking only the final line.
88 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
89 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
90 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
91 let ctr__dry: *i64 = gv_ctr()
92 ctr__dry[0] = pass
93 ctr__dry[1] = total
94 let rc__dry: i64 = gv_verdict("WASM-PONG-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
95 sys_exit(rc__dry)
96 return rc__dry
97}