code wiki / _hdl_build / nx_breeder_arena_gate.nx
nx_breeder_arena_gate.nx source
↩ module page · 214 lines · 11381 B
1// nx_breeder_arena_gate.nx -- proves the COMPOSED loop is a game: a player moving in a real world with
2// collision, wilds that hunt him, duels that resolve, capture that preserves identity, and breeding that
3// pays off -- winnable AND losable, bit-deterministic, with the world's invariants intact all run.
4// This is the gate that EARNS the gamebench physics-collision flip; without it that flip would be a claim.
5// MUTATION TARGET (documented): make the player invulnerable (BA_LOSS_HP=0) => the reckless policy can no
6// longer lose => stakes collapse => nx_game_depth caps the score below SHALLOW => T2 and T6 RED.
7// license_tier: ORIGINAL
8import "nx_syscalls.nx"
9import "nx_breeder_arena.nx"
10import "nx_game_depth.nx"
11
12func p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
13func pn(v: i64) -> i64 {
14 let t: *u8 = sys_mmap(32) as *u8
15 var m: i64 = v
16 var w: i64 = 0
17 if m < 0 { t[w] = 45 as u8; w = w + 1; m = 0 - m }
18 if m == 0 { t[w] = 48 as u8; sys_write(1, t, w + 1); return 0 }
19 let d: *u8 = sys_mmap(32) as *u8
20 var k: i64 = 0
21 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
22 var j: i64 = 0
23 while j < k { t[w] = d[k - 1 - j]; w = w + 1; j = j + 1 }
24 sys_write(1, t, w)
25 return 0
26}
27func nl() -> i64 { p("\n" as *u8); return 0 }
28
29const K: i64 = 4 // strategies scored by the depth critic (2 hunt, 2 reckless)
30
31func newG() -> *i64 { return sys_mmap(ba_words() * 8) as *i64 }
32func newBT() -> *i64 { let b: *i64 = sys_mmap((1 + 512*BRD_BEAT_STRIDE) * 8) as *i64; b[0] = 0; return b }
33func newEV() -> *i64 { let e: *i64 = sys_mmap((1 + 512*EV_STRIDE) * 8) as *i64; e[0] = 0; return e }
34
35func main() -> i64 {
36 p("=== nx_breeder_arena_gate (the composed loop IS a game) ===\n" as *u8)
37 var pass: i64 = 0
38 let checks: i64 = 7
39
40 // ---------- T1 WINNABLE: the hunt-and-breed policy reaches a BIRTH ----------
41 var wins: i64 = 0
42 var best_captures: i64 = 0
43 var best_births: i64 = 0
44 var best_duels: i64 = 0
45 var winseed: i64 = 0-1
46 var sd: i64 = 1
47 while sd <= 24 {
48 let G: *i64 = newG()
49 let rc: i64 = ba_run(sd * 1013, 0, G, newBT(), 512, newEV(), 512)
50 if rc == 1 {
51 wins = wins + 1
52 if winseed < 0 { winseed = sd * 1013; best_captures = G[2]; best_duels = G[3]; best_births = G[4] }
53 }
54 sd = sd + 1
55 }
56 var t1: i64 = 0
57 if wins > 0 { if best_births > 0 { if best_captures >= BA_NEED_CAPTURES { t1 = 1 } } }
58 if t1 == 1 { pass = pass + 1; p("T1 GREEN WINNABLE: " as *u8); pn(wins); p("/24 seeds won under hunt-and-breed; the first win took " as *u8); pn(best_duels); p(" duels -> " as *u8); pn(best_captures); p(" captures -> " as *u8); pn(best_births); p(" birth\n" as *u8) }
59 if t1 == 0 { p("T1 RED wins=" as *u8); pn(wins); p(" births=" as *u8); pn(best_births); p(" captures=" as *u8); pn(best_captures); nl() }
60
61 // ---------- T2 LOSABLE: the reckless policy genuinely dies (a game you cannot lose is not a game) ----
62 var losses: i64 = 0
63 var loss_duels: i64 = 0
64 var sd2: i64 = 1
65 while sd2 <= 24 {
66 let G: *i64 = newG()
67 let rc: i64 = ba_run(sd2 * 1013, 1, G, newBT(), 512, newEV(), 512)
68 if rc == 0-1 { losses = losses + 1; if loss_duels == 0 { loss_duels = G[3] } }
69 sd2 = sd2 + 1
70 }
71 var t2: i64 = 0
72 if losses > 0 { t2 = 1 }
73 if t2 == 1 { pass = pass + 1; p("T2 GREEN LOSABLE: " as *u8); pn(losses); p("/24 reckless runs ended in DEFEAT (player HP hit zero after " as *u8); pn(loss_duels); p(" duels)\n" as *u8) }
74 if t2 == 0 { p("T2 RED losses=" as *u8); pn(losses); nl() }
75
76 // ---------- T3 DETERMINISM: same seed+policy replays bit-exact (lockstep/replay/repro are free) ----
77 let Ga: *i64 = newG()
78 let Gb: *i64 = newG()
79 let ra: i64 = ba_run(777001, 0, Ga, newBT(), 512, newEV(), 512)
80 let rb: i64 = ba_run(777001, 0, Gb, newBT(), 512, newEV(), 512)
81 var t3: i64 = 0
82 if Ga[5] == Gb[5] { if ra == rb { if Ga[3] == Gb[3] { if Ga[5] != 0 { if Ga[3] > 0 { t3 = 1 } } } } }
83 if t3 == 1 { pass = pass + 1; p("T3 GREEN deterministic: replay chain " as *u8); pn(Ga[5]); p(" bit-identical, same outcome, same " as *u8); pn(Ga[3]); p(" duels (non-vacuous: the world actually ran)\n" as *u8) }
84 if t3 == 0 { p("T3 RED cka=" as *u8); pn(Ga[5]); p(" ckb=" as *u8); pn(Gb[5]); nl() }
85
86 // ---------- T4 DIVERGENCE: different seeds produce genuinely different runs (not one scripted path) --
87 let Gc: *i64 = newG()
88 ba_run(31337, 0, Gc, newBT(), 512, newEV(), 512)
89 var t4: i64 = 0
90 if Gc[5] != Ga[5] { t4 = 1 }
91 if t4 == 1 { pass = pass + 1; p("T4 GREEN seeds diverge: chain " as *u8); pn(Ga[5]); p(" vs " as *u8); pn(Gc[5]); p(" -- the world is generated, not replayed from one script\n" as *u8) }
92 if t4 == 0 { p("T4 RED seeds did not diverge\n" as *u8) }
93
94 // ---------- T5 BEATS ARE CAUSAL through the whole composed loop ----------
95 // every SUBMIT must be preceded by a DOMINATE, every BIRTH by a MATE -- across a REAL run, not a unit test
96 let bt5: *i64 = newBT()
97 let G5: *i64 = newG()
98 ba_run(winseed, 0, G5, bt5, 512, newEV(), 512)
99 var causal: i64 = 1
100 var sawSub: i64 = 0
101 var sawBirth: i64 = 0
102 var sawWin: i64 = 0
103 var i5: i64 = 0
104 let nb: i64 = brd_beats(bt5)
105 while i5 < nb {
106 let k: i64 = brd_beat_kind(bt5, i5)
107 if k == BEAT_WIN { sawWin = 1 }
108 if k == BEAT_SUBMIT {
109 sawSub = 1
110 if i5 == 0 { causal = 0 }
111 if i5 > 0 { if brd_beat_kind(bt5, i5 - 1) != BEAT_DOMINATE { causal = 0 } }
112 }
113 if k == BEAT_BIRTH {
114 sawBirth = 1
115 if i5 == 0 { causal = 0 }
116 if i5 > 0 { if brd_beat_kind(bt5, i5 - 1) != BEAT_MATE { causal = 0 } }
117 }
118 i5 = i5 + 1
119 }
120 var t5: i64 = 0
121 if causal == 1 { if sawSub == 1 { if sawBirth == 1 { if sawWin == 1 { if nb > 4 { t5 = 1 } } } } }
122 if t5 == 1 { pass = pass + 1; p("T5 GREEN beats causal in a REAL run: " as *u8); pn(nb); p(" beats, every SUBMIT preceded by DOMINATE and every BIRTH by MATE\n" as *u8) }
123 if t5 == 0 { p("T5 RED causal=" as *u8); pn(causal); p(" sub=" as *u8); pn(sawSub); p(" birth=" as *u8); pn(sawBirth); p(" beats=" as *u8); pn(nb); nl() }
124
125 // ---------- T6 MECHANICAL DEPTH, measured by the hardened critic (not by my opinion) ----------
126 // nx_game_depth needs TWO replays per strategy and CAPS to SHALLOW if they diverge (luck != skill)
127 // or if both a win and a loss are not reachable (unlosable == shallow by definition).
128 let s1: *i64 = sys_mmap(K * 8) as *i64
129 let s2: *i64 = sys_mmap(K * 8) as *i64
130 let res: *i64 = sys_mmap(K * 8) as *i64
131 // ★HONESTY GUARD (added after a mutation test caught this tooth being HOLLOW): gd_score only sees
132 // 1/0, so feeding it "timeout" as 0 would let an UNLOSABLE game still report stakes=1000. The tooth
133 // must therefore independently require a genuine DEFEAT (rc == -1) and a genuine WIN (rc == 1) among
134 // the scored strategies. Proven necessary: with BA_LOSS_HP=0 the old tooth stayed GREEN at 741.
135 var real_wins: i64 = 0
136 var real_defeats: i64 = 0
137 var pi: i64 = 0
138 while pi < K {
139 var policy: i64 = 0
140 if pi >= 2 { policy = 1 }
141 let seed: i64 = 4001 + pi * 977
142 let A: *i64 = newG()
143 let B: *i64 = newG()
144 let rA: i64 = ba_run(seed, policy, A, newBT(), 512, newEV(), 512)
145 let rB: i64 = ba_run(seed, policy, B, newBT(), 512, newEV(), 512)
146 // score a run by what it achieved: captures and births are the objective
147 s1[pi] = A[2] * 100 + A[4] * 500 + A[3] * 10
148 s2[pi] = B[2] * 100 + B[4] * 500 + B[3] * 10
149 res[pi] = 0
150 if rA == 1 { res[pi] = 1; real_wins = real_wins + 1 }
151 if rA == 0-1 { real_defeats = real_defeats + 1 }
152 pi = pi + 1
153 }
154 let dout: *i64 = sys_mmap(GD_N * 8) as *i64
155 gd_score(s1, s2, res, K, dout)
156 let depth: i64 = gd_quality(dout)
157 var t6: i64 = 0
158 if depth >= GD_SHALLOW { if dout[GD_M_DET] == 1000 { if dout[GD_M_STAKES] == 1000 {
159 if real_wins > 0 { if real_defeats > 0 { t6 = 1 } }
160 } } }
161 if t6 == 1 { pass = pass + 1; p("T6 GREEN mechanical depth MEASURED: " as *u8); pn(depth); p(" = " as *u8); p(gd_verdict(depth)); p(" (determinism " as *u8); pn(dout[GD_M_DET]); p(", stakes " as *u8); pn(dout[GD_M_STAKES]); p("; " as *u8); pn(real_wins); p(" genuine wins and " as *u8); pn(real_defeats); p(" genuine DEFEATS -- not timeouts)\n" as *u8) }
162 if t6 == 0 { p("T6 RED depth=" as *u8); pn(depth); p(" det=" as *u8); pn(dout[GD_M_DET]); p(" stakes=" as *u8); pn(dout[GD_M_STAKES]); p(" real_wins=" as *u8); pn(real_wins); p(" real_defeats=" as *u8); pn(real_defeats); nl() }
163
164 // ---------- T7 WORLD INVARIANT + ANTI-VACUITY: occupancy consistent, and the world actually MOVED ----
165 // Re-run one game step-by-step so we can assert ac_occ_check after every tick, not just at the end.
166 let wd7: *i64 = sys_mmap(wd_bytes(BA_W, BA_H)) as *i64
167 ba_world_build(wd7)
168 let ar7: *i64 = sys_mmap(en_bytes(32, AC_NC)) as *i64
169 en_init(ar7, 32, AC_NC)
170 let rosP7: *i64 = sys_mmap(en_bytes(64, COMP_NC)) as *i64
171 en_init(rosP7, 64, COMP_NC)
172 let rosW7: *i64 = sys_mmap(en_bytes(64, COMP_NC)) as *i64
173 en_init(rosW7, 64, COMP_NC)
174 let tbl7: *i64 = sys_mmap(64 * 8) as *i64
175 ag_species_default(tbl7)
176 let btbl7: *i64 = sys_mmap(64 * 8) as *i64
177 brd_species_default(btbl7)
178 let scr7: *i64 = sys_mmap(ag_scratch_words(BA_W, BA_H) * 8) as *i64
179 let buf7: *u8 = sys_mmap(65536) as *u8
180 let out7: *i64 = sys_mmap(64) as *i64
181 let G7: *i64 = newG()
182 var gi: i64 = 0
183 while gi < ba_words() { G7[gi] = 0; gi = gi + 1 }
184 G7[5] = 1469598103
185 G7[6] = ac_spawn(wd7, ar7, 12, 13, 0, BA_PLAYER_HP, 0, 5, 5150)
186 let sh7: i64 = en_spawn(rosP7)
187 en_set(rosP7, sh7, C_SPEC, 1)
188 en_set(rosP7, sh7, C_IV0, 22); en_set(rosP7, sh7, C_IV1, 24)
189 en_set(rosP7, sh7, C_IV2, 20); en_set(rosP7, sh7, C_IV3, 23)
190 en_set(rosP7, sh7, C_XP, 0); en_set(rosP7, sh7, C_LVL, 6); en_set(rosP7, sh7, C_NICK, 0)
191 G7[7] = sh7
192 ba_seed_wilds(wd7, ar7, rosW7, G7, 5150)
193 let px0: i64 = en_get(ar7, G7[6], A_X)
194 let py0: i64 = en_get(ar7, G7[6], A_Y)
195 var violations: i64 = 0
196 var moved_player: i64 = 0
197 var t7t: i64 = 0
198 while t7t < 200 {
199 ba_tick(wd7, ar7, rosP7, rosW7, G7, tbl7, scr7, newEV(), 512, newBT(), 512, buf7, 0, out7)
200 if ac_occ_check(wd7, ar7) != 0 { violations = violations + 1 }
201 if en_get(ar7, G7[6], A_X) != px0 { moved_player = 1 }
202 if en_get(ar7, G7[6], A_Y) != py0 { moved_player = 1 }
203 t7t = t7t + 1
204 }
205 var t7: i64 = 0
206 if violations == 0 { if moved_player == 1 { if G7[3] > 0 { t7 = 1 } } }
207 if t7 == 1 { pass = pass + 1; p("T7 GREEN world invariant held every tick of 200 (0 occupancy violations) and the run was non-vacuous: player moved, " as *u8); pn(G7[3]); p(" duels fought\n" as *u8) }
208 if t7 == 0 { p("T7 RED violations=" as *u8); pn(violations); p(" moved=" as *u8); pn(moved_player); p(" duels=" as *u8); pn(G7[3]); nl() }
209
210 p("nx_breeder_arena_gate: " as *u8); pn(pass); p("/" as *u8); pn(checks); nl()
211 if pass == checks { p("VERDICT GREEN\n" as *u8); return 0 }
212 p("VERDICT RED\n" as *u8)
213 return 1
214}