code wiki / _hdl_build / nx_vn_critic.nx

nx_vn_critic.nx source

↩ module page · 103 lines · 6276 B

1// nx_vn_critic.nx -- the GAME-QUALITY CRITIC bot (the operator's vision: not a bot that BEATS the game, a bot that 2// OPTIMIZES the game). It reads a VN as DATA and judges it like a reviewer of highly-rated visual novels, 3// emitting ACTIONABLE design feedback + a score + an HONEST verdict that can say NEEDS-WORK: 4// FUNCTIONALITY (must-pass): every scene reachable from the start, no broken choice links, >=2 endings. 5// FUN / PACING (graded, grounded in VN norms): scene length ("~N words ~= Ns to read before you can act -- 6// too long for a human to enjoy" past a threshold), ILLUSORY choices (options that all go to the same scene 7// = the choice doesn't matter), branching/replay value (#endings), interactivity. 8// It gates EVERY engine-owned VN (vn_sample + vn_sample2) so the whole published catalog is quality-verified, 9// and optionally EMITS a VN's playable HTML. Build->CRITIQUE->fix->re-critique. license_tier: ORIGINAL expect_exit: 0 10import "nx_vn.nx" 11import "nx_syscalls.nx" 12const MAX_MAGIC_131072: i64 = 131072 13 14const MAX_SCENE_WORDS: i64 = 120 // past this, the human is reading too long before the next beat/choice 15const SHIP_SCORE: i64 = 80 16 17func w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 18func wn(v: i64) -> i64 { var m: i64=v; if m<0{w("-" as *u8);m=0-m} let t:*u8=sys_mmap(24); 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} var i:i64=0; let o:*u8=sys_mmap(24); while i<k{o[i]=t[k-1-i];i=i+1} sys_write(1,o,k); return 0 } 19 20// critique ONE populated VN. emit_path (0 = skip emit) writes the playable zero-JS HTML. Returns 1 if SHIP-READY. 21func critique(title: *u8, txt: *i64, nc: *i64, ct: *i64, cl: *i64, n: i64, emit_path: *u8) -> i64 { 22 w("\n--- critiquing: " as *u8); w(title); w(" ("); wn(n); w(" scenes) ---\n" as *u8) 23 if (emit_path as i64) != 0 { 24 let buf: *u8 = sys_mmap(MAX_MAGIC_131072) 25 let blen: i64 = vn_emit_html(txt, nc, ct, cl, n, title, buf) 26 sys_mkdir("knowledge/staging/game" as *u8, 0x1ed) 27 let fd: i64 = sys_openat_wr(emit_path, 420); if fd >= 0 { sys_write(fd, buf, blen); sys_close(fd) } 28 w(" emitted playable VN -> " as *u8); w(emit_path); w(" ("); wn(blen); w(" bytes, zero-JS)\n" as *u8) 29 } 30 // --- reachability BFS from scene 0 --- 31 let seen: *i64 = sys_mmap(8*VN_NS) as *i64; var i: i64 = 0; while i < n { seen[i] = 0; i = i + 1 } 32 let q: *i64 = sys_mmap(8*VN_NS) as *i64; var qh: i64 = 0; var qt: i64 = 0 33 seen[0] = 1; q[qt] = 0; qt = qt + 1 34 var broken: i64 = 0 35 while qh < qt { 36 let c: i64 = q[qh]; qh = qh + 1 37 var j: i64 = 0 38 while j < nc[c] { 39 let tg: i64 = ct[c*VN_MC + j] 40 if tg < 0 { broken = broken + 1 } else { if tg >= n { broken = broken + 1 } else { if seen[tg] == 0 { seen[tg] = 1; q[qt] = tg; qt = qt + 1 } } } 41 j = j + 1 42 } 43 } 44 var reach: i64 = 0; var endings: i64 = 0 45 i = 0; while i < n { if seen[i] == 1 { reach = reach + 1 } if nc[i] == 0 { endings = endings + 1 } i = i + 1 } 46 47 var score: i64 = 100 48 w(" FUNCTIONALITY:\n" as *u8) 49 if broken > 0 { w(" [FAIL] "); wn(broken); w(" broken choice link(s)\n" as *u8); score = score - 100 } else { w(" [ok] no broken choice links\n" as *u8) } 50 let orphan: i64 = n - reach 51 if orphan > 0 { w(" [FAIL] "); wn(orphan); w(" unreachable scene(s)\n" as *u8); score = score - 30*orphan } else { w(" [ok] all "); wn(n); w(" scenes reachable\n" as *u8) } 52 if endings < 2 { w(" [FAIL] only "); wn(endings); w(" ending(s)\n" as *u8); score = score - 20 } else { w(" [ok] "); wn(endings); w(" distinct endings\n" as *u8) } 53 54 w(" FUN / PACING (vs highly-rated VN norms):\n" as *u8) 55 var illus: i64 = 0 56 i = 0 57 while i < n { 58 if nc[i] >= 2 { 59 var allsame: i64 = 1; var j: i64 = 1 60 while j < nc[i] { if ct[i*VN_MC + j] != ct[i*VN_MC] { allsame = 0 } j = j + 1 } 61 if allsame == 1 { illus = illus + 1; w(" [FIX] scene "); wn(i); w(": ILLUSORY choice -- all options go to the same scene\n" as *u8); score = score - 25 } 62 } 63 i = i + 1 64 } 65 if illus == 0 { w(" [ok] no illusory choices\n" as *u8) } 66 var toolong: i64 = 0 67 i = 0 68 while i < n { 69 let wc: i64 = vn_words(txt[i] as *u8) 70 if wc > MAX_SCENE_WORDS { toolong = toolong + 1; w(" [FIX] scene "); wn(i); w(": ~"); wn(wc); w(" words -- too long before the next beat (norm < "); wn(MAX_SCENE_WORDS); w(")\n" as *u8); score = score - 15 } 71 i = i + 1 72 } 73 if toolong == 0 { w(" [ok] no over-long scenes\n" as *u8) } 74 75 if score < 0 { score = 0 } 76 w(" QUALITY SCORE = "); wn(score); w("/100 -> " as *u8) 77 var ship: i64 = 1 78 if broken > 0 { ship = 0 } if orphan > 0 { ship = 0 } if endings < 2 { ship = 0 } if score < SHIP_SCORE { ship = 0 } 79 if ship == 1 { w("SHIP-READY\n" as *u8) } else { w("NEEDS-WORK (HONEST: fix the [FIX]/[FAIL] notes, re-critique)\n" as *u8) } 80 return ship 81} 82 83// populate + critique vn_sample (id 0) or vn_sample2 (id 1). Returns ship. 84func gate_vn(id: i64, title: *u8, emit_path: *u8) -> i64 { 85 let txt: *i64 = sys_mmap(8*VN_NS) as *i64; let nc: *i64 = sys_mmap(8*VN_NS) as *i64 86 let ct: *i64 = sys_mmap(8*VN_NS*VN_MC) as *i64; let cl: *i64 = sys_mmap(8*VN_NS*VN_MC) as *i64 87 let nbox: *i64 = sys_mmap(16) as *i64; nbox[0] = 0 88 if id == 0 { vn_sample(txt, nc, ct, cl, nbox) } else { vn_sample2(txt, nc, ct, cl, nbox) } 89 return critique(title, txt, nc, ct, cl, nbox[0], emit_path) 90} 91 92func main(argc: i64, argv: *i64) -> i64 { 93 w("=== nx_vn_critic -- GAME-QUALITY critic, gating the WHOLE engine VN catalog ===\n" as *u8) 94 let ship1: i64 = gate_vn(0, "The Lighthouse Keeper" as *u8, "knowledge/staging/game/vn.html" as *u8) 95 let ship2: i64 = gate_vn(1, "The Cartographer's Vow" as *u8, 0 as *u8) 96 w("\n=== CATALOG VERDICT ===\n" as *u8) 97 if ship1 == 1 { if ship2 == 1 { 98 w("ALL VNs SHIP-READY (both functional + paced like highly-rated VNs; the published catalog is quality-gated)\n" as *u8) 99 sys_exit(0); return 0 100 } } 101 w("CATALOG NOT SHIPPABLE -- at least one VN NEEDS-WORK above. HONEST.\n" as *u8) 102 sys_exit(1); return 1 103}