code wiki / _hdl_build / nx_platformer_play_gate.nx

nx_platformer_play_gate.nx source

↩ module page · 103 lines · 6372 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" 9 10func 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 } 11func 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 } 12func gc_has(hay: *u8, n: i64, needle: *u8) -> i64 { 13 var nl: i64 = 0; while needle[nl] != (0 as u8) { nl = nl + 1 } 14 if nl == 0 { return 1 } 15 var i: i64 = 0 16 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 } 17 return 0 18} 19func 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 } 20func 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 } 21 22// scripted jump-AI playthrough (reuses the SAME integer logic the wasm/native game runs). 23func play(base: i64, dojump: i64) -> i64 { 24 init_impl(base) 25 var run: i64 = 1 26 while run == 1 { 27 if sget(base, 7) == 1 { run = 0 } 28 if sget(base, 8) > 400 { run = 0 } 29 if run == 1 { 30 var cmd: i64 = 2 31 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 } } } 32 tick_impl(base, cmd) 33 } 34 } 35 return sget(base, 8) 36} 37func render_to(base: i64, grid: *i64, buf: *u8) -> i64 { pt_frame(base, grid); return pt_emit(base, grid, buf) } 38 39func main(argc: i64, argv: *i64) -> i64 { 40 g_p("=== nx_platformer_play_gate (native pure-Nishi terminal render; no blit/JS/browser) ===\n" as *u8) 41 let base: i64 = sys_mmap(2097152) as i64 42 let grid: *i64 = sys_mmap(8 * ROWS * COLS) as *i64 43 let bufA: *u8 = sys_mmap(131072); let bufB: *u8 = sys_mmap(131072); let bufC: *u8 = sys_mmap(131072) 44 var pass: i64 = 0; var tot: i64 = 0 45 46 // early frame: hero mid-jump near the first coin, all entities on-screen (jump-AI for 16 frames) 47 init_impl(base) 48 var f: i64 = 0 49 while f < 16 { 50 var cmd: i64 = 2 51 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 } } 52 tick_impl(base, cmd); f = f + 1 53 } 54 let nA: i64 = render_to(base, grid, bufA) 55 // sovereign, viewable ASCII dump of this frame (no terminal needed) -> a file 56 let ab: *u8 = sys_mmap(8192) 57 let an: i64 = pt_ascii(base, grid, ab) 58 sys_mkdir("knowledge/staging/game" as *u8, 0x1ed) 59 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) } 60 61 // T1 truecolor cells present (hero green, coin gold, foe red, exit cyan) 62 tot = tot + 1; var ok1: i64 = 1 63 if gc_has(bufA, nA, "48;2;90;210;122m" as *u8) != 1 { ok1 = 0 } 64 if gc_has(bufA, nA, "48;2;255;210;70m" as *u8) != 1 { ok1 = 0 } 65 if gc_has(bufA, nA, "48;2;224;80;58m" as *u8) != 1 { ok1 = 0 } 66 if gc_has(bufA, nA, "48;2;60;200;210m" as *u8) != 1 { ok1 = 0 } 67 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) } 68 69 // T2 NO blit / NO browser surface: pure ANSI, never JS/wasm/putImageData 70 tot = tot + 1; var ok2: i64 = 1 71 if has_esc(bufA, nA) != 1 { ok2 = 0 } 72 if gc_has(bufA, nA, "putImageData" as *u8) != 0 { ok2 = 0 } 73 if gc_has(bufA, nA, "<script" as *u8) != 0 { ok2 = 0 } 74 if gc_has(bufA, nA, "WebAssembly" as *u8) != 0 { ok2 = 0 } 75 if gc_has(bufA, nA, "canvas" as *u8) != 0 { ok2 = 0 } 76 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) } 77 78 // T3 scripted playthrough WINS; the win banner renders 79 play(base, 1) 80 let nWin: i64 = render_to(base, grid, bufB) 81 tot = tot + 1; var ok3: i64 = 1 82 if sget(base, 7) != 1 { ok3 = 0 } 83 if gc_has(bufB, nWin, "YOU WIN" as *u8) != 1 { ok3 = 0 } 84 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) } 85 86 // T4 the hero MOVES: a later frame differs from the early frame 87 init_impl(base) 88 f = 0 89 while f < 44 { tick_impl(base, 2); f = f + 1 } 90 let nC: i64 = render_to(base, grid, bufC) 91 tot = tot + 1 92 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) } 93 94 // T5 DETERMINISM: two identical scripted runs -> byte-identical final frame 95 play(base, 1); let d1: i64 = render_to(base, grid, bufA) 96 play(base, 1); let d2: i64 = render_to(base, grid, bufB) 97 tot = tot + 1 98 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) } 99 100 g_p("nx_platformer_play_gate pass=" as *u8); g_i(pass); g_p("/" as *u8); g_i(tot) 101 if pass == tot { g_p(" verdict=GREEN (native sovereign terminal platformer; pure Nishi bottom-up, no blit)\n" as *u8); sys_exit(0); return 0 } 102 g_p(" verdict=RED\n" as *u8); sys_exit(1); return 1 103}