code wiki / _hdl_build / nx_game_shmup_gate.nx
nx_game_shmup_gate.nx source
↩ module page · 109 lines · 6385 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_game_shmup_gate.nx -- GENRE: Shoot 'em up (catalog genre, was ABSENT). A real integer/no-float shmup
4// CORE -- player ship, a bullet, an enemy formation, aim+shoot+collision -- with a SCRIPTED PLAYTHROUGH that
5// clears the wave (live evidence the ecosystem builds a playable of this genre), a rendered frame (the games'
6// packed-RGB fb, display-path-ready per SF5), a neg-control (aiming matters) + liar-kill (collision is real).
7// T1 PLAYTHROUGH: aim+shoot each enemy column -> the whole wave is cleared (score == N = WIN). PNG.
8// T2 NEG-CONTROL: firing from an empty column (mis-aimed) clears NOTHING (score == 0) -- aiming is real.
9// T3 COLLISION REAL: one aligned shot kills EXACTLY the aligned enemy (the others survive).
10// T4 NEVER-BRICK (#26): deterministic (re-run -> identical), bounded, no float, zero hardware writes.
11// expect_exit: 0 license_tier: ORIGINAL
12import "nx_game_raster.nx"
13import "nx_png.nx"
14import "nx_syscalls.nx"
15
16func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
17" as *u8); return ok }
18
19// st[0]=sx st[1]=sy st[2]=bx st[3]=by st[4]=bullet_active st[5]=score
20func sh_reset(st: *i64, alive: *i64, n: i64, sy: i64) -> i64 {
21 st[0]=64; st[1]=sy; st[2]=0; st[3]=0; st[4]=0; st[5]=0
22 var i: i64=0; while i<n { alive[i]=1; i=i+1 }
23 return 0
24}
25func sh_shoot(st: *i64) -> i64 { if st[4]==0 { st[2]=st[0]; st[3]=st[1]-8; st[4]=1 } return 0 }
26func sh_step(st: *i64, ex: *i64, alive: *i64, n: i64, ey: i64) -> i64 {
27 if st[4]==1 {
28 st[3]=st[3]-6
29 if st[3]<0 { st[4]=0 } else {
30 var i: i64=0
31 while i<n {
32 if alive[i]==1 {
33 var dx: i64=st[2]-ex[i]; if dx<0 {dx=0-dx}
34 var dy: i64=st[3]-ey; if dy<0 {dy=0-dy}
35 if dx<7 { if dy<8 { alive[i]=0; st[4]=0; st[5]=st[5]+1 } }
36 }
37 i=i+1
38 }
39 }
40 }
41 return 0
42}
43// move ship to a column, fire, and resolve the bullet to completion (scripted aim+shoot).
44func sh_fire_at(st: *i64, ex: *i64, alive: *i64, n: i64, ey: i64, col: i64) -> i64 {
45 st[0]=col
46 sh_shoot(st)
47 var guard: i64=0
48 while st[4]==1 { if guard>=48 { st[4]=0 } else { sh_step(st, ex, alive, n, ey) } guard=guard+1 }
49 return 0
50}
51func sh_render(fb: *i64, w: i64, h: i64, st: *i64, ex: *i64, alive: *i64, n: i64, ey: i64, sy: i64) -> i64 {
52 gr_clear(fb, w, h, gr_pack(8, 10, 24))
53 gr_px(fb, w, h, 12, 18, gr_pack(120,120,150)); gr_px(fb, w, h, 100, 30, gr_pack(120,120,150)) // stars
54 gr_px(fb, w, h, 60, 50, gr_pack(120,120,150)); gr_px(fb, w, h, 30, 64, gr_pack(120,120,150))
55 var i: i64=0
56 while i<n { if alive[i]==1 { gr_rect(fb, w, h, ex[i]-6, ey-5, ex[i]+6, ey+5, gr_pack(224,80,58)); gr_rect(fb, w, h, ex[i]-3, ey+5, ex[i]+3, ey+8, gr_pack(150,50,40)) } i=i+1 }
57 if st[4]==1 { gr_rect(fb, w, h, st[2]-1, st[3]-4, st[2]+2, st[3]+3, gr_pack(250,240,120)) }
58 gr_rect(fb, w, h, st[0]-7, sy-3, st[0]+8, sy+5, gr_pack(90,210,122))
59 gr_rect(fb, w, h, st[0]-2, sy-7, st[0]+3, sy-3, gr_pack(120,230,150))
60 return 0
61}
62
63func main() -> i64 {
64 gw("=== nx_game_shmup_gate: GENRE Shoot-em-up -- a real integer/no-float playable (live evidence) ===\n" as *u8)
65 var pass: i64 = 0; var total: i64 = 0
66 let W: i64=128; let H: i64=96; let N: i64=6; let EY: i64=14; let SY: i64=84
67 let ex: *i64=sys_mmap(8*8) as *i64; let alive: *i64=sys_mmap(8*8) as *i64; let st: *i64=sys_mmap(8*8) as *i64
68 ex[0]=14; ex[1]=34; ex[2]=54; ex[3]=74; ex[4]=94; ex[5]=114
69
70 // ---- T1: full scripted playthrough clears the wave ----
71 sh_reset(st, alive, N, SY)
72 var i: i64=0; while i<N { sh_fire_at(st, ex, alive, N, EY, ex[i]); i=i+1 }
73 let won: i64 = st[5]
74 total=total+1; if won==N { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
75 gw("T1 playthrough: aim+shoot cleared the wave, score=" as *u8); gn(won); gw("/" as *u8); gn(N); gw(" (WIN)\n" as *u8)
76
77 // ---- render a mid-game frame for live evidence ----
78 let fb: *i64=sys_mmap(8*(W*H+8)) as *i64
79 sh_reset(st, alive, N, SY)
80 sh_fire_at(st, ex, alive, N, EY, ex[0]); sh_fire_at(st, ex, alive, N, EY, ex[1]); sh_fire_at(st, ex, alive, N, EY, ex[2]) // 3 down
81 st[0]=ex[3]; sh_shoot(st); sh_step(st, ex, alive, N, EY); sh_step(st, ex, alive, N, EY); sh_step(st, ex, alive, N, EY) // bullet mid-flight
82 sh_render(fb, W, H, st, ex, alive, N, EY, SY)
83 write_png(fb, W, H, "knowledge/nx_game_shmup.png" as *u8)
84 gw(" (live evidence: PNG knowledge/nx_game_shmup.png -- ship + bullet in flight + 3 enemies down)\n" as *u8)
85
86 // ---- T2: neg-control -- firing from an empty column clears nothing ----
87 sh_reset(st, alive, N, SY)
88 i=0; while i<N { sh_fire_at(st, ex, alive, N, EY, 4); i=i+1 } // column 4 has no enemy (first is at 14)
89 let missed: i64 = st[5]
90 total=total+1; if missed==0 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
91 gw("T2 neg-control: mis-aimed shots (empty column) cleared " as *u8); gn(missed); gw(" (=0, aiming is real)\n" as *u8)
92
93 // ---- T3: collision real -- one aligned shot kills exactly the aligned enemy ----
94 sh_reset(st, alive, N, SY)
95 sh_fire_at(st, ex, alive, N, EY, ex[2])
96 var t3ok: i64=1; if alive[2]!=0 {t3ok=0} if alive[0]!=1 {t3ok=0} if alive[5]!=1 {t3ok=0} if st[5]!=1 {t3ok=0}
97 total=total+1; if t3ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
98 gw("T3 collision real: an aligned shot killed exactly enemy 2 (others alive), score=" as *u8); gn(st[5]); gw("\n" as *u8)
99
100 // ---- T4: never-brick / determinism ----
101 sh_reset(st, alive, N, SY); i=0; while i<N { sh_fire_at(st, ex, alive, N, EY, ex[i]); i=i+1 }
102 let run2: i64 = st[5]
103 total=total+1; if run2==won { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
104 gw("T4 never-brick (#26): deterministic (re-run score=" as *u8); gn(run2); gw("==" as *u8); gn(won); gw("), bounded, no float\n" as *u8)
105
106 gw("\n=== nx_game_shmup_gate " as *u8); gn(pass); gw("/" as *u8); gn(total)
107 if pass == total { gw(" GREEN (Shoot-em-up: a real playable wave-clear with aim/shoot/collision, rendered, sovereign)\n" as *u8); sys_exit(0); return 0 }
108 gw(" RED\n" as *u8); sys_exit(1); return 1
109}