code wiki / _hdl_build / nx_game_pong_gate.nx

nx_game_pong_gate.nx source

↩ module page · 95 lines · 6150 B

1import "nx_gate_gn.nx" 2import "nx_gate_base.nx" 3// nx_game_pong_gate.nx -- GENRE: Sport (catalog genre, was ABSENT). A real integer/no-float Pong CORE -- 4// two paddles, a ball with bounce physics + paddle return + scoring. Scripted match (a tracking paddle beats 5// a frozen one), rendered frame, neg-control (paddle control matters) + return-physics-real. 6// T1 MATCH: the player's tracking paddle returns every ball and scores to the win target. PNG. 7// T2 NEG-CONTROL: a frozen player paddle (no tracking) does NOT reach the win target (control is real). 8// T3 PHYSICS REAL: a ball at a paddle is RETURNED only when the paddle is aligned (else it passes). 9// T4 NEVER-BRICK (#26): deterministic, bounded, no float. 10// expect_exit: 0 license_tier: ORIGINAL 11import "nx_game_raster.nx" 12import "nx_png.nx" 13import "nx_syscalls.nx" 14 15func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 16" as *u8); return ok } 17func p_abs(v: i64) -> i64 { if v<0 { return 0-v } return v } 18func p_clamp(v: i64, lo: i64, hi: i64) -> i64 { if v<lo {return lo} if v>hi {return hi} return v } 19 20// s[0]=bx s[1]=by s[2]=bvx s[3]=bvy s[4]=lpy s[5]=rpy s[6]=lscore s[7]=rscore 21func pong_reset(s: *i64, dir: i64) -> i64 { s[0]=70; s[1]=48; s[2]=dir*2; s[3]=1; return 0 } 22func pong_full_reset(s: *i64) -> i64 { pong_reset(s, 1); s[4]=12; s[5]=12; s[6]=0; s[7]=0; return 0 } 23func pong_tick(s: *i64, w: i64, h: i64, padh: i64, ltrack: i64, rtrack: i64) -> i64 { 24 let lx: i64=6; let rx: i64=w-6 25 if ltrack==1 { s[4]=p_clamp(s[1], padh, h-padh) } 26 if rtrack==1 { s[5]=p_clamp(s[1], padh, h-padh) } 27 s[0]=s[0]+s[2]; s[1]=s[1]+s[3] 28 if s[1]<=2 { s[1]=2; s[3]=0-s[3] } 29 if s[1]>=h-2 { s[1]=h-2; s[3]=0-s[3] } 30 if s[2]<0 { if s[0]<=lx+2 { if p_abs(s[1]-s[4])<padh { s[2]=0-s[2]; s[0]=lx+2 } } } 31 if s[2]>0 { if s[0]>=rx-2 { if p_abs(s[1]-s[5])<padh { s[2]=0-s[2]; s[0]=rx-2 } } } 32 if s[0]<0 { s[7]=s[7]+1; pong_reset(s, 1) } 33 if s[0]>w { s[6]=s[6]+1; pong_reset(s, 0-1) } 34 return 0 35} 36func pong_render(fb: *i64, w: i64, h: i64, padh: i64, s: *i64) -> i64 { 37 gr_clear(fb, w, h, gr_pack(12, 16, 22)) 38 var y: i64=4; while y<h { gr_rect(fb, w, h, w/2-1, y, w/2+1, y+6, gr_pack(60,70,84)); y=y+12 } // center line 39 gr_rect(fb, w, h, 4, s[4]-padh, 8, s[4]+padh, gr_pack(120,220,150)) // left paddle (player, green) 40 gr_rect(fb, w, h, w-8, s[5]-padh, w-4, s[5]+padh, gr_pack(220,220,120)) // right paddle (AI, yellow) 41 gr_disc(fb, w, h, s[0], s[1], 2, gr_pack(240,240,240)) // ball 42 gr_rect(fb, w, h, w/2-2-s[6]*4, 4, w/2-2, 7, gr_pack(120,220,150)) // left score bar 43 return 0 44} 45 46func main() -> i64 { 47 gw("=== nx_game_pong_gate: GENRE Sport (Pong) -- a real integer/no-float playable (live evidence) ===\n" as *u8) 48 var pass: i64 = 0; var total: i64 = 0 49 let W: i64=140; let H: i64=96; let PADH: i64=8; let WIN: i64=3 50 let s: *i64=sys_mmap(8*8) as *i64 51 52 // ---- T1: tracking player paddle vs a frozen opponent -> the player reaches the win score ---- 53 pong_full_reset(s) 54 var tick: i64=0 55 while tick < 1200 { if s[6]>=WIN { tick=1200 } else { pong_tick(s, W, H, PADH, 1, 0); tick=tick+1 } } 56 let lwon: i64=s[6] 57 total=total+1; if lwon>=WIN { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 58 gw("T1 match: the tracking paddle scored " as *u8); gn(lwon); gw(" (>= " as *u8); gn(WIN); gw(" = WIN)\n" as *u8) 59 60 // ---- render a mid-rally frame ---- 61 let fb: *i64=sys_mmap(8*(W*H+8)) as *i64 62 pong_full_reset(s) 63 var k: i64=0; while k < 20 { pong_tick(s, W, H, PADH, 1, 0); k=k+1 } 64 pong_render(fb, W, H, PADH, s) 65 write_png(fb, W, H, "knowledge/nx_game_pong.png" as *u8) 66 gw(" (live evidence: PNG knowledge/nx_game_pong.png -- paddles + ball + score)\n" as *u8) 67 68 // ---- T2: neg-control -- a frozen player paddle never reaches the win score ---- 69 pong_full_reset(s) 70 tick=0; while tick < 1200 { if s[6]>=WIN { tick=1200 } else { pong_tick(s, W, H, PADH, 0, 1); tick=tick+1 } } 71 let lfrozen: i64=s[6] 72 total=total+1; if lfrozen < WIN { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 73 gw("T2 neg-control: a frozen player paddle scored " as *u8); gn(lfrozen); gw(" (< " as *u8); gn(WIN); gw(", opponent=" as *u8); gn(s[7]); gw("; paddle control is real)\n" as *u8) 74 75 // ---- T3: physics real -- a ball is returned only when the paddle is aligned ---- 76 pong_full_reset(s); s[0]=8; s[2]=0-2; s[1]=48; s[4]=48 // ball at left paddle, paddle aligned 77 pong_tick(s, W, H, PADH, 0, 0) 78 let aligned_vx: i64=s[2] // should be returned (>0) 79 pong_full_reset(s); s[0]=8; s[2]=0-2; s[1]=48; s[4]=10 // paddle far from ball 80 pong_tick(s, W, H, PADH, 0, 0) 81 let missed_vx: i64=s[2] // should NOT be returned (<0) 82 var t3ok: i64=1; if aligned_vx <= 0 {t3ok=0} if missed_vx >= 0 {t3ok=0} 83 total=total+1; if t3ok==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 84 gw("T3 physics real: aligned paddle returns the ball (vx=" as *u8); gn(aligned_vx); gw("), misaligned lets it pass (vx=" as *u8); gn(missed_vx); gw(")\n" as *u8) 85 86 // ---- T4: never-brick / determinism ---- 87 pong_full_reset(s); tick=0; while tick < 1200 { if s[6]>=WIN { tick=1200 } else { pong_tick(s, W, H, PADH, 1, 0); tick=tick+1 } } 88 let lwon2: i64=s[6] 89 total=total+1; if lwon2==lwon { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 90 gw("T4 never-brick (#26): deterministic re-run (score=" as *u8); gn(lwon2); gw("==" as *u8); gn(lwon); gw("), bounded, no float\n" as *u8) 91 92 gw("\n=== nx_game_pong_gate " as *u8); gn(pass); gw("/" as *u8); gn(total) 93 if pass == total { gw(" GREEN (Sport/Pong: a real playable with ball physics, paddle return, scoring, rendered, sovereign)\n" as *u8); sys_exit(0); return 0 } 94 gw(" RED\n" as *u8); sys_exit(1); return 1 95}