code wiki / _hdl_build / nx_game_actor_gate.nx
nx_game_actor_gate.nx source
↩ module page · 223 lines · 10246 B
1// nx_game_actor_gate.nx -- proves the character<->environment interaction floor (ws=game-interact).
2// Teeth follow the lane law: every equality carries a NON-VACUITY guard; the flagship tooth (T2/T5
3// occupancy) is designed so the mutation "ac_step skips the occupancy check" turns it RED while the
4// anti-vacuity tooth stays GREEN. license_tier: ORIGINAL
5import "nx_syscalls.nx"
6import "nx_game_actor.nx"
7import "nx_pathfind.nx"
8import "nx_gamesave.nx"
9
10func p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
11func pn(v: i64) -> i64 {
12 let t: *u8 = sys_mmap(32) as *u8
13 var m: i64 = v
14 var w: i64 = 0
15 if m < 0 { t[w] = 45 as u8; w = w + 1; m = 0 - m }
16 if m == 0 { t[w] = 48 as u8; sys_write(1, t, w + 1); return 0 }
17 let d: *u8 = sys_mmap(32) as *u8
18 var k: i64 = 0
19 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
20 var j: i64 = 0
21 while j < k { t[w] = d[k - 1 - j]; w = w + 1; j = j + 1 }
22 sys_write(1, t, w)
23 return 0
24}
25func nl() -> i64 { p("\n" as *u8); return 0 }
26
27const GW2: i64 = 16
28const GH2: i64 = 12
29
30// deterministic scripted walk: fold a seed into a move dir each step
31func dir_dx(d: i64) -> i64 { if d == 0 { return 1 } if d == 1 { return 0-1 } return 0 }
32func dir_dy(d: i64) -> i64 { if d == 2 { return 1 } if d == 3 { return 0-1 } return 0 }
33
34func main() -> i64 {
35 p("=== nx_game_actor_gate (character<->environment interaction floor) ===\n" as *u8)
36 var pass: i64 = 0
37 let checks: i64 = 7
38
39 let wd: *i64 = sys_mmap(wd_bytes(GW2, GH2)) as *i64
40 wd_init(wd, GW2, GH2)
41 // border walls + one interior pillar
42 var i: i64 = 0
43 while i < GW2 { wd_set_wall(wd, i, 0, 1); wd_set_wall(wd, i, GH2 - 1, 1); i = i + 1 }
44 var j: i64 = 0
45 while j < GH2 { wd_set_wall(wd, 0, j, 1); wd_set_wall(wd, GW2 - 1, j, 1); j = j + 1 }
46 wd_set_wall(wd, 8, 5, 1)
47
48 let ar: *i64 = sys_mmap(en_bytes(64, AC_NC)) as *i64
49 en_init(ar, 64, AC_NC)
50 let out: *i64 = sys_mmap(64) as *i64
51
52 // T1 wall + oob collision, with the anti-vacuity half (an open move MUST succeed)
53 let hp2: i64 = ac_spawn(wd, ar, 7, 5, 0, 30, 0, 1, 12345)
54 var t1: i64 = 0
55 if ac_step(wd, ar, hp2, 1, 0, out) == AC_WALL { // into the pillar at (8,5)
56 if en_get(ar, hp2, A_X) == 7 { // position unchanged
57 if ac_step(wd, ar, hp2, 0, 1, out) == AC_MOVED { // open move works (non-vacuous)
58 if en_get(ar, hp2, A_Y) == 6 { t1 = 1 }
59 }
60 }
61 }
62 if t1 == 1 { pass = pass + 1; p("T1 GREEN wall stops, open passes: pillar blocked pos held, open cell entered\n" as *u8) }
63 if t1 == 0 { p("T1 RED wall/open\n" as *u8) }
64
65 // T2 entity collision = BUMP with the right handle, nobody moves (the interaction primitive)
66 let he: i64 = ac_spawn(wd, ar, 7, 7, 1, 20, 1, 1, 777)
67 var t2: i64 = 0
68 let rc2: i64 = ac_step(wd, ar, hp2, 0, 1, out) // player at (7,6) -> into enemy (7,7)
69 if rc2 == AC_BUMP {
70 if out[0] == he {
71 if en_get(ar, hp2, A_Y) == 6 {
72 if en_get(ar, he, A_Y) == 7 { t2 = 1 }
73 }
74 }
75 }
76 if t2 == 1 { pass = pass + 1; p("T2 GREEN bump-to-interact: moving into an occupied cell returns the occupant, positions held\n" as *u8) }
77 if t2 == 0 { p("T2 RED bump\n" as *u8) }
78
79 // T3 oob refused (walls are the border here, so drive to a corner via a fresh open-map world)
80 let wd3: *i64 = sys_mmap(wd_bytes(4, 4)) as *i64
81 wd_init(wd3, 4, 4)
82 let ar3: *i64 = sys_mmap(en_bytes(8, AC_NC)) as *i64
83 en_init(ar3, 8, AC_NC)
84 let h3: i64 = ac_spawn(wd3, ar3, 0, 0, 0, 10, 0, 1, 1)
85 var t3: i64 = 0
86 if ac_step(wd3, ar3, h3, 0-1, 0, out) == AC_OOB {
87 if ac_step(wd3, ar3, h3, 1, 0, out) == AC_MOVED { t3 = 1 }
88 }
89 if t3 == 1 { pass = pass + 1; p("T3 GREEN oob refused at the true edge, in-bounds move fine\n" as *u8) }
90 if t3 == 0 { p("T3 RED oob\n" as *u8) }
91
92 // T4 determinism: 400-step scripted walk replayed twice -> identical ck; non-vacuity: ck must MOVE
93 var rep: i64 = 0
94 var ck1: i64 = 0
95 var ck2: i64 = 0
96 var moved_total: i64 = 0
97 while rep < 2 {
98 let wdr: *i64 = sys_mmap(wd_bytes(GW2, GH2)) as *i64
99 wd_init(wdr, GW2, GH2)
100 var bi: i64 = 0
101 while bi < GW2 { wd_set_wall(wdr, bi, 0, 1); wd_set_wall(wdr, bi, GH2 - 1, 1); bi = bi + 1 }
102 var bj: i64 = 0
103 while bj < GH2 { wd_set_wall(wdr, 0, bj, 1); wd_set_wall(wdr, GW2 - 1, bj, 1); bj = bj + 1 }
104 wd_set_wall(wdr, 8, 5, 1)
105 let arr: *i64 = sys_mmap(en_bytes(64, AC_NC)) as *i64
106 en_init(arr, 64, AC_NC)
107 let ha: i64 = ac_spawn(wdr, arr, 3, 3, 0, 30, 0, 1, 5)
108 let hb: i64 = ac_spawn(wdr, arr, 12, 8, 1, 20, 1, 1, 9)
109 let ck0: i64 = ac_ck(wdr, arr)
110 var s: i64 = 424242
111 var st: i64 = 0
112 while st < 400 {
113 s = s * 1103515245 + 12345
114 var d: i64 = (s >> 16) & 3
115 if d < 0 { d = 0 - d }
116 let rc: i64 = ac_step(wdr, arr, ha, dir_dx(d), dir_dy(d), out)
117 if rc == AC_MOVED { moved_total = moved_total + 1 }
118 s = s * 1103515245 + 12345
119 var d2: i64 = (s >> 16) & 3
120 if d2 < 0 { d2 = 0 - d2 }
121 ac_step(wdr, arr, hb, dir_dx(d2), dir_dy(d2), out)
122 st = st + 1
123 }
124 var ckf: i64 = ac_ck(wdr, arr)
125 if ckf == ck0 { ckf = 0 } // frozen world would be vacuous
126 if rep == 0 { ck1 = ckf }
127 if rep == 1 { ck2 = ckf }
128 rep = rep + 1
129 }
130 var t4: i64 = 0
131 if ck1 == ck2 { if ck1 != 0 { if moved_total > 100 { t4 = 1 } } }
132 if t4 == 1 { pass = pass + 1; p("T4 GREEN deterministic: 2x400-step replay ck identical ck=" as *u8); pn(ck1); p(" moved=" as *u8); pn(moved_total); nl() }
133 if t4 == 0 { p("T4 RED determinism ck1=" as *u8); pn(ck1); p(" ck2=" as *u8); pn(ck2); nl() }
134
135 // T5 occupancy invariant under churn: spawn/walk/remove cycles, then the invariant walker
136 var t5: i64 = 0
137 var churn_moves: i64 = 0
138 var s5: i64 = 31337
139 var c: i64 = 0
140 while c < 30 {
141 s5 = s5 * 1103515245 + 12345
142 var px: i64 = ((s5 >> 16) & 32767) % (GW2 - 2) + 1
143 s5 = s5 * 1103515245 + 12345
144 var py: i64 = ((s5 >> 16) & 32767) % (GH2 - 2) + 1
145 let hn: i64 = ac_spawn(wd, ar, px, py, 1, 10, 2, 1, s5)
146 if hn > 0 {
147 var mv: i64 = 0
148 while mv < 12 {
149 s5 = s5 * 1103515245 + 12345
150 var dd: i64 = (s5 >> 16) & 3
151 if dd < 0 { dd = 0 - dd }
152 if ac_step(wd, ar, hn, dir_dx(dd), dir_dy(dd), out) == AC_MOVED { churn_moves = churn_moves + 1 }
153 mv = mv + 1
154 }
155 if (c % 3) == 0 { ac_remove(wd, ar, hn) }
156 }
157 c = c + 1
158 }
159 if ac_occ_check(wd, ar) == 0 { if churn_moves > 20 { if en_count(ar) > 2 { t5 = 1 } } }
160 if t5 == 1 { pass = pass + 1; p("T5 GREEN occupancy invariant held through churn: moves=" as *u8); pn(churn_moves); p(" actors=" as *u8); pn(en_count(ar)); nl() }
161 if t5 == 0 { p("T5 RED occupancy violations=" as *u8); pn(ac_occ_check(wd, ar)); nl() }
162
163 // T6 the shared grid REALLY drives pf_astar: path around the pillar exists and every path cell is open
164 var t6: i64 = 0
165 let n6: i64 = GW2 * GH2
166 let g6: *i64 = sys_mmap(n6 * 8) as *i64
167 let f6: *i64 = sys_mmap(n6 * 8) as *i64
168 let cm6: *i64 = sys_mmap(n6 * 8) as *i64
169 let of6: *i64 = sys_mmap(n6 * 8) as *i64
170 let cl6: *i64 = sys_mmap(n6 * 8) as *i64
171 let pa6: *i64 = sys_mmap(n6 * 8) as *i64
172 let plen: i64 = pf_astar(wd_grid(wd), GW2, GH2, 1, 5, 14, 5, g6, f6, cm6, of6, cl6, pa6)
173 if plen > 0 {
174 var okcells: i64 = 1
175 var pi: i64 = 0
176 while pi < plen {
177 let cell: i64 = pa6[pi]
178 if wd_wall(wd, cell % GW2, cell / GW2) != 0 { okcells = 0 }
179 pi = pi + 1
180 }
181 if okcells == 1 { if plen >= 13 { t6 = 1 } } // straight line is 13; pillar may force more
182 }
183 if t6 == 1 { pass = pass + 1; p("T6 GREEN pf_astar consumes the live world grid: path len=" as *u8); pn(plen); p(" all cells open\n" as *u8) }
184 if t6 == 0 { p("T6 RED astar-on-world plen=" as *u8); pn(plen); nl() }
185
186 // T7 gamesave transparency (GX-9): save world+actors, load into ZEROED arenas, ck equal + non-vacuous
187 var t7: i64 = 0
188 let wn: i64 = wd_words(GW2, GH2)
189 let an: i64 = en_words(64, AC_NC)
190 let S: *i64 = sys_mmap((wn + an) * 8) as *i64
191 var si: i64 = 0
192 while si < wn { S[si] = wd[si]; si = si + 1 }
193 var sj: i64 = 0
194 while sj < an { S[wn + sj] = ar[sj]; sj = sj + 1 }
195 let ckpre: i64 = ac_ck(wd, ar)
196 let rcs: i64 = gs_save("knowledge/nx_actor_t7.sav" as *u8, 9101, S, wn + an, 1000)
197 let L: *i64 = sys_mmap((wn + an) * 8) as *i64
198 let meta: *i64 = sys_mmap(64) as *i64
199 let rcl: i64 = gs_load("knowledge/nx_actor_t7.sav" as *u8, L, wn + an, meta)
200 if rcs > 0 { if rcl >= 0 {
201 let wd7: *i64 = sys_mmap(wn * 8) as *i64
202 let ar7: *i64 = sys_mmap(an * 8) as *i64
203 var li: i64 = 0
204 while li < wn { wd7[li] = L[li]; li = li + 1 }
205 var lj: i64 = 0
206 while lj < an { ar7[lj] = L[wn + lj]; lj = lj + 1 }
207 let ckpost: i64 = ac_ck(wd7, ar7)
208 if ckpost == ckpre { if en_count(ar7) > 2 { if churn_moves > 0 {
209 // resumed world must CONTINUE identically: same scripted step on both
210 ac_step(wd, ar, hp2, 0, 0-1, out)
211 let hp7: i64 = hp2 // same handle value is valid in the copy
212 ac_step(wd7, ar7, hp7, 0, 0-1, out)
213 if ac_ck(wd, ar) == ac_ck(wd7, ar7) { t7 = 1 }
214 } } }
215 } }
216 if t7 == 1 { pass = pass + 1; p("T7 GREEN save/load transparent: ck equal pre/post + resumed step identical (non-vacuous world)\n" as *u8) }
217 if t7 == 0 { p("T7 RED save/load rcs=" as *u8); pn(rcs); p(" rcl=" as *u8); pn(rcl); nl() }
218
219 p("nx_game_actor_gate: " as *u8); pn(pass); p("/" as *u8); pn(checks); nl()
220 if pass == checks { p("VERDICT GREEN\n" as *u8); return 0 }
221 p("VERDICT RED\n" as *u8)
222 return 1
223}