code wiki / _hdl_build / nx_worldsim_gate.nx
nx_worldsim_gate.nx source
↩ module page · 226 lines · 9336 B
1// nx_worldsim_gate.nx -- CERTIFICATION of nx_worldsim (gamebench rank 1, hard GAP, Strive:Conquest keystone).
2// T1 ★CONSERVATION -- 500 randomised trades move wealth without minting or burning a single unit
3// T2 ★SYMMETRIC RELATIONS -- rel(A,B) and rel(B,A) can never disagree, after arbitrary one-sided edits
4// T3 ACCOUNTED PRODUCTION -- a tick adds EXACTLY ws_production(), no more, no less
5// T4 DETERMINISM -- two worlds, same seed, 200 ticks -> identical state
6// T5 BOUNDED -- relations clamp to [-1000,1000]; resources never go negative; overdraw is refused
7// T6 NO SELF-DEALING -- a faction cannot trade with itself or edit its own relation
8// T7 ★ANTI-VACUITY -- the world actually EVOLVES (wealth grows, relations move). A frozen world would
9// satisfy conservation, symmetry and determinism perfectly while simulating nothing.
10// T8 composes with nx_gamesave: a whole world arena round-trips through save/load
11// license_tier: ORIGINAL expect_exit: 0
12import "nx_syscalls.nx"
13import "nx_worldsim.nx"
14import "nx_gamesave.nx"
15import "nx_gate_verdict.nx"
16
17func ww(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 {
19 if v==0 { sys_write(1,"0" as *u8,1); return 0 }
20 var m: i64=v; if m<0 { sys_write(1,"-" as *u8,1); m=0-m }
21 let t: *u8=sys_mmap(32); var k: i64=0
22 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
23 let o: *u8=sys_mmap(32); var q: i64=k-1; var i: i64=0
24 while q>=0 { o[i]=t[q]; i=i+1; q=q-1 }
25 sys_write(1,o,i); return 0
26}
27func seedworld(a: *i64, n: i64, seed: i64) -> i64 {
28 ws_init(a, n, seed)
29 var i: i64 = 0
30 while i < n {
31 ws_set_res(a, i, 1000 + i*250)
32 ws_set_pop(a, i, 500 + i*100)
33 ws_set_terr(a, i, 3 + i)
34 i = i + 1
35 }
36 return 0
37}
38
39func main() -> i64 {
40 ww("=== nx_worldsim_gate: is the faction/economy world sim safe to build a campaign on? ===\n\n")
41 var pass: i64 = 0
42 var checks: i64 = 0
43 let N: i64 = 6
44 let a: *i64 = sys_mmap(ws_bytes(N)) as *i64
45
46 // ---------- T1 conservation ----------
47 checks = checks + 1
48 seedworld(a, N, 12345)
49 let before: i64 = ws_total_res(a)
50 var moved: i64 = 0
51 var t: i64 = 0
52 while t < 500 {
53 let f: i64 = ws_rng(a) % N
54 let g: i64 = ws_rng(a) % N
55 let amt: i64 = ws_rng(a) % 400
56 moved = moved + ws_trade(a, f, g, amt)
57 t = t + 1
58 }
59 let after: i64 = ws_total_res(a)
60 var neg: i64 = 0
61 var i: i64 = 0
62 while i < N { if ws_res(a,i) < 0 { neg = neg + 1 } i = i + 1 }
63 if before==after { if neg==0 {
64 ww("T1 GREEN conservation: 500 trades moved "); wn(moved); wn(0)
65 ww(" units, total "); wn(before); ww(" -> "); wn(after); ww(" (exact, 0 negative balances)\n")
66 pass=pass+1
67 } }
68 if before!=after { ww("T1 RED wealth leaked/minted: "); wn(before); ww(" -> "); wn(after); ww("\n") }
69 if before==after { if neg>0 { ww("T1 RED negative balances: "); wn(neg); ww("\n") } }
70
71 // ---------- T2 symmetric relations ----------
72 checks = checks + 1
73 seedworld(a, N, 999)
74 ws_adjust_rel(a, 0, 3, 250)
75 ws_adjust_rel(a, 3, 0, 0-100) // opposite direction, same pair
76 ws_adjust_rel(a, 1, 4, 0-400)
77 ws_adjust_rel(a, 2, 5, 700)
78 var sym: i64 = 1
79 i = 0
80 while i < N {
81 var j: i64 = 0
82 while j < N {
83 if ws_rel(a,i,j) != ws_rel(a,j,i) { sym = 0 }
84 j = j + 1
85 }
86 i = i + 1
87 }
88 if sym==1 { if ws_rel(a,0,3)==150 {
89 ww("T2 GREEN relations symmetric by construction: rel(0,3)=rel(3,0)="); wn(ws_rel(a,0,3))
90 ww(" after opposing one-sided edits -- diplomacy cannot desync\n")
91 pass=pass+1
92 } }
93 if sym==0 { ww("T2 RED asymmetric relation found\n") }
94 if sym==1 { if ws_rel(a,0,3)!=150 { ww("T2 RED edits did not accumulate: "); wn(ws_rel(a,0,3)); ww("\n") } }
95
96 // ---------- T3 accounted production ----------
97 checks = checks + 1
98 seedworld(a, N, 4242)
99 let RATE: i64 = 7
100 let pre: i64 = ws_total_res(a)
101 let expect: i64 = ws_production(a, RATE)
102 ws_tick(a, RATE)
103 let post: i64 = ws_total_res(a)
104 if post - pre == expect { if expect > 0 {
105 ww("T3 GREEN production accounted: tick added exactly "); wn(expect)
106 ww(" (predicted == actual), total "); wn(pre); ww(" -> "); wn(post); ww("\n")
107 pass=pass+1
108 } }
109 if post - pre != expect {
110 ww("T3 RED production unaccounted: expected +"); wn(expect); ww(" got +"); wn(post-pre); ww("\n")
111 }
112
113 // ---------- T4 determinism ----------
114 checks = checks + 1
115 let w1: *i64 = sys_mmap(ws_bytes(N)) as *i64
116 let w2: *i64 = sys_mmap(ws_bytes(N)) as *i64
117 seedworld(w1, N, 777); seedworld(w2, N, 777)
118 var k: i64 = 0
119 while k < 200 { ws_tick(w1, 5); ws_tick(w2, 5); k = k + 1 }
120 var det: i64 = 1
121 i = 0
122 while i < ws_words(N) { if w1[i]!=w2[i] { det=0 } i=i+1 }
123 if det==1 {
124 ww("T4 GREEN deterministic: 2 worlds, same seed, 200 ticks -> identical arena (tick=")
125 wn(ws_tickno(w1)); ww(", total="); wn(ws_total_res(w1)); ww(")\n")
126 pass=pass+1
127 } else { ww("T4 RED worlds diverged -- campaigns would not replay\n") }
128
129 // ---------- T5 bounded ----------
130 checks = checks + 1
131 seedworld(a, N, 31)
132 ws_adjust_rel(a, 0, 1, 999999)
133 let relhi: i64 = ws_rel(a,0,1)
134 ws_adjust_rel(a, 2, 3, 0-999999)
135 let rello: i64 = ws_rel(a,2,3)
136 ws_set_res(a, 4, 100)
137 let over: i64 = ws_trade(a, 4, 5, 100000) // overdraw attempt
138 let left: i64 = ws_res(a, 4)
139 var t5: i64 = 0
140 if relhi==WS_RELMAX { if rello==WS_RELMIN { if over==100 { if left==0 { t5=1 } } } }
141 if t5==1 {
142 ww("T5 GREEN bounded: rel clamps "); wn(rello); ww("/"); wn(relhi)
143 ww("; overdraw of 100000 moved only the "); wn(over); ww(" held, balance "); wn(left); ww("\n")
144 pass=pass+1
145 } else {
146 ww("T5 RED bounds breached: relhi="); wn(relhi); ww(" rello="); wn(rello)
147 ww(" moved="); wn(over); ww(" left="); wn(left); ww("\n")
148 }
149
150 // ---------- T6 no self-dealing ----------
151 checks = checks + 1
152 seedworld(a, N, 55)
153 let r0: i64 = ws_res(a,0)
154 let self_trade: i64 = ws_trade(a, 0, 0, 500)
155 let selfrel_before: i64 = ws_rel(a,2,2)
156 ws_adjust_rel(a, 2, 2, 0-500)
157 let selfrel_after: i64 = ws_rel(a,2,2)
158 var t6: i64 = 0
159 if self_trade==0 { if ws_res(a,0)==r0 { if selfrel_before==selfrel_after { t6=1 } } }
160 if t6==1 {
161 ww("T6 GREEN no self-dealing: self-trade refused (balance unchanged "); wn(r0)
162 ww("), self-relation immutable\n"); pass=pass+1
163 } else { ww("T6 RED self-dealing permitted, moved="); wn(self_trade); ww("\n") }
164
165 // ---------- T7 anti-vacuity ----------
166 checks = checks + 1
167 seedworld(a, N, 20260720)
168 let v0_total: i64 = ws_total_res(a)
169 let v0_rel: i64 = ws_rel(a,0,1)
170 var relmoved: i64 = 0
171 k = 0
172 while k < 300 {
173 ws_tick(a, 4)
174 if ws_rel(a,0,1) != v0_rel { relmoved = 1 }
175 k = k + 1
176 }
177 let v1_total: i64 = ws_total_res(a)
178 var t7: i64 = 0
179 if v1_total > v0_total { if ws_tickno(a)==300 { if relmoved==1 { t7=1 } } }
180 if t7==1 {
181 ww("T7 GREEN anti-vacuity: 300 ticks grew wealth "); wn(v0_total); ww(" -> "); wn(v1_total)
182 ww(" and relations moved -- the world actually simulates\n"); pass=pass+1
183 } else {
184 ww("T7 RED world is frozen: total "); wn(v0_total); ww(" -> "); wn(v1_total)
185 ww(" relmoved="); wn(relmoved); ww("\n")
186 }
187
188 // ---------- T8 composes with nx_gamesave ----------
189 checks = checks + 1
190 let WP: *u8 = "knowledge/nx_worldsim_world.sav" as *u8
191 sys_unlinkat(WP)
192 let words: i64 = ws_words(N)
193 let wrote: i64 = gs_save(WP, 60613, a, words, 1784579500)
194 let rd: *i64 = sys_mmap(ws_bytes(N)) as *i64
195 let got: i64 = gs_load(WP, rd, words, 0 as *i64)
196 var t8: i64 = 1
197 if got != words { t8=0 }
198 if wrote <= 0 { t8=0 }
199 i = 0
200 while i < words { if rd[i]!=a[i] { t8=0 } i=i+1 }
201 // and the restored world must keep simulating identically
202 if t8==1 {
203 let cont: *i64 = sys_mmap(ws_bytes(N)) as *i64
204 i = 0
205 while i < words { cont[i]=rd[i]; i=i+1 }
206 ws_tick(a, 4); ws_tick(cont, 4)
207 i = 0
208 while i < words { if cont[i]!=a[i] { t8=0 } i=i+1 }
209 }
210 if t8==1 {
211 ww("T8 GREEN composes with nx_gamesave: "); wn(N); ww("-faction world ("); wn(words)
212 ww(" words, "); wn(wrote); ww("B) round-tripped AND resumed simulating identically\n")
213 pass=pass+1
214 } else { ww("T8 RED world did not survive save/load or diverged on resume, rc="); wn(got); ww("\n") }
215
216 ww("\n=== nx_worldsim_gate "); wn(pass); ww("/"); wn(checks)
217 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
218 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
219 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
220 let ctr__dry: *i64 = gv_ctr()
221 ctr__dry[0] = pass
222 ctr__dry[1] = checks
223 let rc__dry: i64 = gv_verdict("WORLDSIM-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
224 sys_exit(rc__dry)
225 return rc__dry
226}