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}