code wiki / _hdl_build / nx_game_depth.nx

nx_game_depth.nx source

↩ module page · 91 lines · 4540 B

1// nx_game_depth.nx -- the MECHANICAL-DEPTH critic. nx_game_critic measures whether a frame LOOKS rich; 2// this measures whether the GAME PLAYS deep -- because a beautiful frame on a trivial click-loop is still 3// a toy. Depth is not asserted from the rules; it is MEASURED from OUTCOMES: run K distinct strategies and 4// see whether they DIVERGE. A shallow game funnels every strategy to the same win (spread ~0, nothing is 5// at stake). A deep game rewards good play and punishes bad -- strategies spread out, and a careless one 6// can LOSE. That divergence is depth you can measure, and it is exactly what the current click-to-sell 7// loop LACKS (you always win). Verdict SHALLOW/BASIC/DEEP. LIB. license_tier: ORIGINAL 8import "nx_syscalls.nx" 9 10const GD_N: i64 = 4 11const GD_M_SPREAD: i64 = 0 // outcome spread across strategies (permil of the best) 12const GD_M_STAKES: i64 = 1 // are BOTH win and loss reachable? (real consequence) 13const GD_M_DIVERSE: i64 = 2 // distinct outcome buckets / K (strategies genuinely differ) 14const GD_M_DET: i64 = 3 // determinism: fraction of strategies that REPLAY identically. Skill games 15 // are deterministic (same strategy -> same outcome); a coin-flip is not. 16 // This is what stops random luck from scoring DEEP (the red-team finding). 17const GD_SHALLOW: i64 = 300 18const GD_BASIC: i64 = 550 19 20// scores1[k]/scores2[k] = TWO independent replays of each strategy's final score; results[k] = 1 win / 21// 0 loss (from run 1). Two runs let the critic MEASURE skill-vs-luck: a deterministic skill game gives 22// scores1==scores2; a coin-flip does not. Writes GD_N dims to out. 23func gd_score(scores1: *i64, scores2: *i64, results: *i64, k: i64, out: *i64) -> i64 { 24 if k<1 { out[0]=0; out[1]=0; out[2]=0; out[3]=0; return 0 } 25 var mn: i64 = scores1[0] 26 var mx: i64 = scores1[0] 27 var wins: i64 = 0 28 var losses: i64 = 0 29 var detmatch: i64 = 0 30 var i: i64 = 0 31 while i<k { 32 if scores1[i]<mn { mn=scores1[i] } 33 if scores1[i]>mx { mx=scores1[i] } 34 if results[i]==1 { wins=wins+1 } 35 if results[i]==0 { losses=losses+1 } 36 if scores1[i]==scores2[i] { detmatch=detmatch+1 } 37 i=i+1 38 } 39 var sp: i64 = 0 40 if mx>0 { sp = (mx-mn)*1000/mx } 41 out[GD_M_SPREAD] = sp 42 out[GD_M_DET] = detmatch*1000/k 43 // stakes: 1000 when BOTH a win and a loss are reachable (choices carry real consequence), 44 // 300 when everything wins (no downside), 100 when everything loses (unwinnable/broken) 45 var stakes: i64 = 100 46 if wins>0 { stakes=300 } 47 if wins>0 { if losses>0 { stakes=1000 } } 48 out[GD_M_STAKES] = stakes 49 // diversity: distinct outcome buckets (quantize scores to 10% of max) / K 50 var buckets: i64 = 0 51 let seen: *i64 = sys_mmap(64*8) as *i64 52 var z: i64=0 53 while z<64 { seen[z]=0; z=z+1 } 54 i=0 55 while i<k { 56 var b: i64 = 0 57 if mx>0 { b = scores1[i]*20/mx } 58 if b<0 { b=0 } 59 if b>63 { b=63 } 60 if seen[b]==0 { seen[b]=1; buckets=buckets+1 } 61 i=i+1 62 } 63 out[GD_M_DIVERSE] = buckets*1000/k 64 return 0 65} 66func gd_cap(v: i64, target: i64, weight: i64) -> i64 { 67 var c: i64=v 68 if c>target { c=target } 69 return c*weight/target 70} 71// composite 0..1000: stakes dominate (a game with real win/lose consequence is the core of depth), 72// spread + diversity confirm strategies actually differ. 73// ★PRINCIPLE: a game you CANNOT LOSE is SHALLOW by definition -- if both win AND loss are not reachable 74// (stakes<1000), the score is capped below the SHALLOW line no matter how the outcomes vary. Strategy 75// only matters when it can go wrong. This is what makes the always-win click-loop score SHALLOW. 76func gd_quality(out: *i64) -> i64 { 77 let st: i64 = gd_cap(out[GD_M_STAKES], 1000, 520) 78 let sp: i64 = gd_cap(out[GD_M_SPREAD], 350, 300) 79 let dv: i64 = gd_cap(out[GD_M_DIVERSE], 600, 180) 80 var total: i64 = st+sp+dv 81 if out[GD_M_STAKES] < 1000 { if total > GD_SHALLOW-1 { total = GD_SHALLOW-1 } } 82 // ★RED-TEAM HARDENING: if strategies do NOT replay identically (det<1000), the divergence is LUCK, 83 // not SKILL -- a coin-flip. Depth requires deterministic, skill-driven outcomes: cap it below SHALLOW. 84 if out[GD_M_DET] < 1000 { if total > GD_SHALLOW-1 { total = GD_SHALLOW-1 } } 85 return total 86} 87func gd_verdict(score: i64) -> *u8 { 88 if score < GD_SHALLOW { return "SHALLOW" as *u8 } 89 if score < GD_BASIC { return "BASIC" as *u8 } 90 return "DEEP" as *u8 91}