code wiki / _hdl_build / nx_platformer_play_gate.nx
nx_platformer_play_gate.nx source
↩ module page · 111 lines · 6753 B
1// nx_platformer_play_gate.nx -- GATE for the native, pure-Nishi terminal platformer. Verifies the sovereign ANSI
2// render WITHOUT a live terminal: a frame carries the hero/coin/foe/exit truecolor cells; the rendered bytes are
3// PURE ANSI -- NO blit, NO <script, NO WebAssembly (zero browser surface, the whole point of the pivot); a
4// scripted playthrough reaches the exit (win banner rendered); the hero MOVES between frames; and the render is
5// DETERMINISTIC (two identical runs -> byte-identical final frame). license_tier: ORIGINAL expect_exit: 0
6import "nx_platformer_term.nx"
7import "nx_wasm_platformer.nx"
8import "nx_syscalls.nx"
9import "nx_gate_verdict.nx"
10
11func g_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
12func g_i(v: i64) -> i64 { let t: *u8 = sys_mmap(24); var m: i64 = v; var k: i64 = 0; if m == 0 { t[0]=48 as u8; k=1 } while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } let o: *u8=sys_mmap(24); var w: i64=0; var q: i64=k-1; while q>=0 { o[w]=t[q]; w=w+1; q=q-1 } sys_write(1,o,w); return 0 }
13func gc_has(hay: *u8, n: i64, needle: *u8) -> i64 {
14 var nl: i64 = 0; while needle[nl] != (0 as u8) { nl = nl + 1 }
15 if nl == 0 { return 1 }
16 var i: i64 = 0
17 while i + nl <= n { var k: i64 = 0; var hit: i64 = 1; while k < nl { if hay[i+k] != needle[k] { hit = 0; k = nl } else { k = k + 1 } } if hit == 1 { return 1 } i = i + 1 }
18 return 0
19}
20func gb_eq(a: *u8, na: i64, b: *u8, nb: i64) -> i64 { if na != nb { return 0 } var i: i64 = 0; while i < na { if a[i] != b[i] { return 0 } i = i + 1 } return 1 }
21func has_esc(buf: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { if buf[i] == (27 as u8) { return 1 } i = i + 1 } return 0 }
22
23// scripted jump-AI playthrough (reuses the SAME integer logic the wasm/native game runs).
24func play(base: i64, dojump: i64) -> i64 {
25 init_impl(base)
26 var run: i64 = 1
27 while run == 1 {
28 if sget(base, 7) == 1 { run = 0 }
29 if sget(base, 8) > 400 { run = 0 }
30 if run == 1 {
31 var cmd: i64 = 2
32 if dojump == 1 { if sget(base, 3) == 1 { var i: i64 = 0; while i < NCOIN { if cget(base, i) == 0 { let d: i64 = coin_x(i) - sget(base, 0); if d > 10 { if d < 24 { cmd = 0 } } } i = i + 1 } } }
33 tick_impl(base, cmd)
34 }
35 }
36 return sget(base, 8)
37}
38func render_to(base: i64, grid: *i64, buf: *u8) -> i64 { pt_frame(base, grid); return pt_emit(base, grid, buf) }
39
40func main(argc: i64, argv: *i64) -> i64 {
41 g_p("=== nx_platformer_play_gate (native pure-Nishi terminal render; no blit/JS/browser) ===\n" as *u8)
42 let base: i64 = sys_mmap(2097152) as i64
43 let grid: *i64 = sys_mmap(8 * ROWS * COLS) as *i64
44 let bufA: *u8 = sys_mmap(131072); let bufB: *u8 = sys_mmap(131072); let bufC: *u8 = sys_mmap(131072)
45 var pass: i64 = 0; var tot: i64 = 0
46
47 // early frame: hero mid-jump near the first coin, all entities on-screen (jump-AI for 16 frames)
48 init_impl(base)
49 var f: i64 = 0
50 while f < 16 {
51 var cmd: i64 = 2
52 if sget(base, 3) == 1 { var i: i64 = 0; while i < NCOIN { if cget(base, i) == 0 { let d: i64 = coin_x(i) - sget(base, 0); if d > 10 { if d < 24 { cmd = 0 } } } i = i + 1 } }
53 tick_impl(base, cmd); f = f + 1
54 }
55 let nA: i64 = render_to(base, grid, bufA)
56 // sovereign, viewable ASCII dump of this frame (no terminal needed) -> a file
57 let ab: *u8 = sys_mmap(8192)
58 let an: i64 = pt_ascii(base, grid, ab)
59 sys_mkdir("knowledge/staging/game" as *u8, 0x1ed)
60 let afd: i64 = sys_openat_wr("knowledge/staging/game/platformer_frame.txt" as *u8, 420); if afd >= 0 { sys_write(afd, ab, an); sys_close(afd) }
61
62 // T1 truecolor cells present (hero green, coin gold, foe red, exit cyan)
63 tot = tot + 1; var ok1: i64 = 1
64 if gc_has(bufA, nA, "48;2;90;210;122m" as *u8) != 1 { ok1 = 0 }
65 if gc_has(bufA, nA, "48;2;255;210;70m" as *u8) != 1 { ok1 = 0 }
66 if gc_has(bufA, nA, "48;2;224;80;58m" as *u8) != 1 { ok1 = 0 }
67 if gc_has(bufA, nA, "48;2;60;200;210m" as *u8) != 1 { ok1 = 0 }
68 if ok1 == 1 { pass = pass + 1; g_p("PASS T1 render: ANSI truecolor cells present (green hero, gold coin, red foe, cyan exit)\n" as *u8) } else { g_p("FAIL T1\n" as *u8) }
69
70 // T2 NO blit / NO browser surface: pure ANSI, never JS/wasm/putImageData
71 tot = tot + 1; var ok2: i64 = 1
72 if has_esc(bufA, nA) != 1 { ok2 = 0 }
73 if gc_has(bufA, nA, "putImageData" as *u8) != 0 { ok2 = 0 }
74 if gc_has(bufA, nA, "<script" as *u8) != 0 { ok2 = 0 }
75 if gc_has(bufA, nA, "WebAssembly" as *u8) != 0 { ok2 = 0 }
76 if gc_has(bufA, nA, "canvas" as *u8) != 0 { ok2 = 0 }
77 if ok2 == 1 { pass = pass + 1; g_p("PASS T2 bottom-up: frame is pure terminal ANSI -- 0 blit, 0 <script, 0 wasm, 0 canvas\n" as *u8) } else { g_p("FAIL T2\n" as *u8) }
78
79 // T3 scripted playthrough WINS; the win banner renders
80 play(base, 1)
81 let nWin: i64 = render_to(base, grid, bufB)
82 tot = tot + 1; var ok3: i64 = 1
83 if sget(base, 7) != 1 { ok3 = 0 }
84 if gc_has(bufB, nWin, "YOU WIN" as *u8) != 1 { ok3 = 0 }
85 if ok3 == 1 { pass = pass + 1; g_p("PASS T3 playthrough: jump-AI reaches the exit, win banner rendered\n" as *u8) } else { g_p("FAIL T3 won=" as *u8); g_i(sget(base,7)); g_p("\n" as *u8) }
86
87 // T4 the hero MOVES: a later frame differs from the early frame
88 init_impl(base)
89 f = 0
90 while f < 44 { tick_impl(base, 2); f = f + 1 }
91 let nC: i64 = render_to(base, grid, bufC)
92 tot = tot + 1
93 if gb_eq(bufA, nA, bufC, nC) == 0 { pass = pass + 1; g_p("PASS T4 motion: a later frame differs from the early frame (the render tracks live state)\n" as *u8) } else { g_p("FAIL T4 frames identical\n" as *u8) }
94
95 // T5 DETERMINISM: two identical scripted runs -> byte-identical final frame
96 play(base, 1); let d1: i64 = render_to(base, grid, bufA)
97 play(base, 1); let d2: i64 = render_to(base, grid, bufB)
98 tot = tot + 1
99 if gb_eq(bufA, d1, bufB, d2) == 1 { pass = pass + 1; g_p("PASS T5 determinism: two runs -> byte-identical final frame (" as *u8); g_i(d1); g_p("B)\n" as *u8) } else { g_p("FAIL T5\n" as *u8) }
100
101 g_p("nx_platformer_play_gate pass=" as *u8); g_i(pass); g_p("/" as *u8); g_i(tot)
102 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
103 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
104 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
105 let ctr__dry: *i64 = gv_ctr()
106 ctr__dry[0] = pass
107 ctr__dry[1] = tot
108 let rc__dry: i64 = gv_verdict("PLATFORMER-PLAY-GATE" as *u8, ctr__dry, "native sovereign terminal platformer; pure Nishi bottom-up, no blit)" as *u8)
109 sys_exit(rc__dry)
110 return rc__dry
111}