code wiki / _hdl_build / nx_tactics_emit.nx
nx_tactics_emit.nx source
↩ module page · 250 lines · 11126 B
1// nx_tactics_emit.nx -- the TACTICS GAME EMITTER (G-ECO-005 rung 3): a data tactics game-spec in,
2// a complete playable tactics game module out, hands-off -- the SECOND engine's autonomy lever,
3// mirroring nx_game_emit for dungeons. It reads a tactics spec (grid/squad/enemy/hp/dmg/moves/
4// range/walls/cover/hit-curve/seed) and WRITES a per-game .nx module that fills the engine cfg and
5// calls teng_run (nx_tactics_engine_lib). The generated game is then built native by Nishi's own
6// toolchain and is playable in a terminal (and headless-provable via a scripted bot).
7//
8// Spec grammar (one key per line): name <module> title <hud> grid_w/grid_h n_player/n_enemy
9// hp dmg moves range n_walls n_cover hit_base hit_distdiv cover_penalty seed
10//
11// CLI: nx_tactics_emit <specpath> -> writes runtime/_hdl_build/<name>.nx
12// SELF-GATE (no args): parse knowledge/specs/game_tactics.spec, emit the module, and PROVE it:
13// cfg parsed right + module written + module calls teng_run + a scripted bot drives the parsed
14// cfg to a battle RESOLUTION. TACTICS-EMIT-GATE verdict=GREEN -> knowledge/status/tactics_emit.log.
15//
16// HONEST AUTHORSHIP: this emitter + the engine lib are TUTOR-authored tooling; the GAMES it writes
17// from specs are emitter output (the autonomy lever). license_tier: ORIGINAL
18import "nx_syscalls.nx"
19import "nx_tactics_engine_lib.nx"
20const K_MAGIC_12345: i64 = 12345
21const K_MAGIC_65536: i64 = 65536
22const K_MAGIC_8192: i64 = 8192
23const K_MAGIC_6000: i64 = 6000
24
25func te_w(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 }
26func te_c(fd: i64, c: i64) -> i64 { let b: *u8 = sys_mmap(8); b[0] = c as u8; sys_write(fd, b, 1); return 0 }
27func te_wn(fd: i64, v: i64) -> i64 {
28 var m: i64 = v
29 if m < 0 { te_c(fd, 45); m = 0 - m }
30 let bb: *u8 = sys_mmap(28); let t: *u8 = sys_mmap(28); var k: i64 = 0
31 if m == 0 { t[0] = 48 as u8; k = 1 }
32 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
33 var i: i64 = 0
34 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
35 sys_write(fd, bb, k); return 0
36}
37func te_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
38func te_read(path: *u8, buf: *u8, cap: i64) -> i64 {
39 let fd: i64 = sys_openat_rd(path)
40 if fd < 0 { return 0 - 1 }
41 var n: i64 = 0
42 var r: i64 = sys_read(fd, buf, cap - 1)
43 while r > 0 { n = n + r; r = sys_read(fd, buf + n, cap - 1 - n) }
44 sys_close(fd)
45 return n
46}
47func te_match(buf: *u8, pos: i64, key: *u8) -> i64 {
48 var i: i64 = 0
49 while key[i] != (0 as u8) { if buf[pos + i] != key[i] { return 0 } i = i + 1 }
50 return 1
51}
52func te_linestart(buf: *u8, pos: i64) -> i64 {
53 if pos == 0 { return 1 }
54 if buf[pos - 1] == (10 as u8) { return 1 }
55 return 0
56}
57func te_find(buf: *u8, len: i64, key: *u8) -> i64 {
58 let kl: i64 = te_strlen(key)
59 var i: i64 = 0
60 while i < len {
61 if te_linestart(buf, i) == 1 { if te_match(buf, i, key) == 1 { if buf[i + kl] == (32 as u8) { return i + kl + 1 } } }
62 i = i + 1
63 }
64 return 0 - 1
65}
66func te_pint(buf: *u8, pos: i64) -> i64 {
67 var p: i64 = pos
68 while buf[p] == (32 as u8) { p = p + 1 }
69 var neg: i64 = 0
70 if buf[p] == (45 as u8) { neg = 1; p = p + 1 }
71 var v: i64 = 0; var go: i64 = 1
72 while go == 1 { let c: i64 = buf[p] as i64; if c < 48 { go = 0 } if c > 57 { go = 0 } if go == 1 { v = v * 10 + (c - 48); p = p + 1 } }
73 if neg == 1 { return 0 - v }
74 return v
75}
76func te_int(buf: *u8, len: i64, key: *u8, dflt: i64) -> i64 {
77 let p: i64 = te_find(buf, len, key)
78 if p < 0 { return dflt }
79 return te_pint(buf, p)
80}
81func te_str(buf: *u8, len: i64, key: *u8, out: *u8) -> i64 {
82 let p: i64 = te_find(buf, len, key)
83 if p < 0 { out[0] = 0 as u8; return 0 }
84 var r: i64 = 0; var w: i64 = 0; var go: i64 = 1
85 while go == 1 {
86 let c: i64 = buf[p + r] as i64
87 if c == 10 { go = 0 }
88 if c == 0 { go = 0 }
89 if go == 1 { if c != 13 { out[w] = c as u8; w = w + 1 } r = r + 1 }
90 }
91 out[w] = 0 as u8
92 return w
93}
94func te_has(buf: *u8, len: i64, pat: *u8) -> i64 {
95 let pl: i64 = te_strlen(pat)
96 var i: i64 = 0
97 while i + pl <= len {
98 var j: i64 = 0; var ok: i64 = 1
99 while j < pl { if buf[i + j] != pat[j] { ok = 0 } j = j + 1 }
100 if ok == 1 { return 1 }
101 i = i + 1
102 }
103 return 0
104}
105func te_modpath(name: *u8, out: *u8) -> i64 {
106 var w: i64 = 0; var i: i64 = 0
107 let pre: *u8 = "runtime/_hdl_build/" as *u8
108 while pre[i] != (0 as u8) { out[w] = pre[i]; w = w + 1; i = i + 1 }
109 i = 0
110 while name[i] != (0 as u8) { out[w] = name[i]; w = w + 1; i = i + 1 }
111 let suf: *u8 = ".nx" as *u8
112 i = 0
113 while suf[i] != (0 as u8) { out[w] = suf[i]; w = w + 1; i = i + 1 }
114 out[w] = 0 as u8
115 return w
116}
117func te_parse_cfg(buf: *u8, len: i64, cfg: *i64) -> i64 {
118 cfg[0] = te_int(buf, len, "grid_w" as *u8, 16)
119 cfg[1] = te_int(buf, len, "grid_h" as *u8, 12)
120 cfg[2] = te_int(buf, len, "n_player" as *u8, 2)
121 cfg[3] = te_int(buf, len, "n_enemy" as *u8, 2)
122 cfg[4] = te_int(buf, len, "hp" as *u8, 10)
123 cfg[5] = te_int(buf, len, "dmg" as *u8, 5)
124 cfg[6] = te_int(buf, len, "moves" as *u8, 5)
125 cfg[7] = te_int(buf, len, "range" as *u8, 9)
126 cfg[8] = te_int(buf, len, "n_walls" as *u8, 10)
127 cfg[9] = te_int(buf, len, "n_cover" as *u8, 8)
128 cfg[10] = te_int(buf, len, "hit_base" as *u8, 8)
129 cfg[11] = te_int(buf, len, "hit_distdiv" as *u8, 3)
130 cfg[12] = te_int(buf, len, "cover_penalty" as *u8, 3)
131 cfg[13] = te_int(buf, len, "seed" as *u8, K_MAGIC_12345)
132 return 0
133}
134func te_emit(name: *u8, cfg: *i64) -> i64 {
135 let mp: *u8 = sys_mmap(256)
136 te_modpath(name, mp)
137 let fd: i64 = sys_openat_wr(mp, 0x1a4)
138 if fd < 0 { return 0 }
139 te_w(fd, "// AUTHORED BY nx_tactics_emit from a data tactics game-spec -- per-game module over nx_tactics_engine_lib\n" as *u8)
140 te_w(fd, "import " as *u8); te_c(fd, 34); te_w(fd, "nx_syscalls.nx" as *u8); te_c(fd, 34); te_c(fd, 10)
141 te_w(fd, "import " as *u8); te_c(fd, 34); te_w(fd, "nx_tactics_engine_lib.nx" as *u8); te_c(fd, 34); te_c(fd, 10)
142 te_w(fd, "func main() -> i64 {\n" as *u8)
143 te_w(fd, " let cfg: *i64 = sys_mmap(128) as *i64\n" as *u8)
144 var k: i64 = 0
145 while k < 14 {
146 te_w(fd, " cfg[" as *u8); te_wn(fd, k); te_w(fd, "] = " as *u8); te_wn(fd, cfg[k]); te_c(fd, 10)
147 k = k + 1
148 }
149 te_w(fd, " return teng_run(cfg)\n" as *u8)
150 te_w(fd, "}\n" as *u8)
151 sys_close(fd)
152 return 1
153}
154// scripted bot: advance active player to range + shoot; drive the battle to a resolution.
155func te_bot(st: *i64, cap: i64) -> i64 {
156 var iter: i64 = 0
157 while iter < cap {
158 if st[2] != 0 { return st[2] }
159 let ci: i64 = st[1]
160 if ci < 0 { return st[2] }
161 let ei: i64 = teng_nearest_foe(st, st[16 + ci], st[22 + ci], st[34 + ci])
162 if ei < 0 { teng_check_end(st); return st[2] }
163 let d: i64 = teng_dist(st[16 + ci], st[22 + ci], st[16 + ei], st[22 + ei])
164 if d <= st[71] {
165 teng_input(st, 4)
166 } else {
167 let ox: i64 = st[16 + ci]; let oy: i64 = st[22 + ci]
168 let tx: i64 = st[16 + ei]; let ty: i64 = st[22 + ei]
169 var key: i64 = 0 - 1
170 if teng_abs(tx - ox) >= teng_abs(ty - oy) {
171 if tx > ox { key = 3 }
172 if tx < ox { key = 2 }
173 } else {
174 if ty > oy { key = 1 }
175 if ty < oy { key = 0 }
176 }
177 if key < 0 { teng_input(st, 5) } else {
178 teng_input(st, key)
179 var moved: i64 = 1
180 if st[16 + ci] == ox { if st[22 + ci] == oy { moved = 0 } }
181 if moved == 0 { teng_input(st, 5) } else { if st[5] <= 0 { teng_input(st, 5) } }
182 }
183 }
184 iter = iter + 1
185 }
186 return st[2]
187}
188
189func main(argc: i64, argv: *i64) -> i64 {
190 if argc >= 2 {
191 let sp: *u8 = argv[1] as *u8
192 let buf: *u8 = sys_mmap(K_MAGIC_65536)
193 let n: i64 = te_read(sp, buf, K_MAGIC_65536)
194 if n <= 0 { te_w(1, "TACTICS-EMIT REFUSED: cannot read spec\n" as *u8); sys_exit(1); return 1 }
195 let name: *u8 = sys_mmap(128)
196 te_str(buf, n, "name" as *u8, name)
197 if name[0] == (0 as u8) { te_w(1, "TACTICS-EMIT REFUSED: no name\n" as *u8); sys_exit(1); return 1 }
198 let cfg: *i64 = sys_mmap(128) as *i64
199 te_parse_cfg(buf, n, cfg)
200 if te_emit(name, cfg) == 0 { te_w(1, "TACTICS-EMIT REFUSED: cannot open module path\n" as *u8); sys_exit(1); return 1 }
201 let mp: *u8 = sys_mmap(256); te_modpath(name, mp)
202 te_w(1, "TACTICS-EMIT GREEN name=" as *u8); te_w(1, name); te_w(1, " -> " as *u8); te_w(1, mp); te_c(1, 10)
203 sys_exit(0); return 0
204 }
205
206 // SELF-GATE
207 let buf: *u8 = sys_mmap(K_MAGIC_65536)
208 let n: i64 = te_read("knowledge/specs/game_tactics.spec" as *u8, buf, K_MAGIC_65536)
209 if n <= 0 { te_w(1, "TACTICS-EMIT-GATE verdict=RED (cannot read game_tactics.spec)\n" as *u8); sys_exit(1); return 1 }
210 let name: *u8 = sys_mmap(128)
211 te_str(buf, n, "name" as *u8, name)
212 let cfg: *i64 = sys_mmap(128) as *i64
213 te_parse_cfg(buf, n, cfg)
214 let emitted: i64 = te_emit(name, cfg)
215 let mp: *u8 = sys_mmap(256); te_modpath(name, mp)
216 let mbuf: *u8 = sys_mmap(K_MAGIC_65536)
217 let mn: i64 = te_read(mp, mbuf, K_MAGIC_65536)
218 var has_run: i64 = 0
219 if mn > 0 { has_run = te_has(mbuf, mn, "teng_run" as *u8) }
220 // play proof: the parsed cfg drives a real battle to resolution
221 let st: *i64 = sys_mmap(K_MAGIC_8192) as *i64
222 teng_init(st, cfg)
223 let mode: i64 = te_bot(st, K_MAGIC_6000)
224
225 var ok: i64 = 1
226 if cfg[0] != 16 { ok = 0 }
227 if cfg[2] != 2 { ok = 0 }
228 if cfg[3] != 2 { ok = 0 }
229 if emitted != 1 { ok = 0 }
230 if has_run != 1 { ok = 0 }
231 if mode == 0 { ok = 0 }
232
233 let fd: i64 = sys_openat_append("knowledge/status/tactics_emit.log" as *u8, 420)
234 te_w(1, "TACTICS-EMIT-GATE authored=organ spec=game_tactics parsed[grid_w16->" as *u8); te_wn(1, cfg[0])
235 te_w(1, " nplayer2->" as *u8); te_wn(1, cfg[2]); te_w(1, " nenemy2->" as *u8); te_wn(1, cfg[3])
236 te_w(1, "] emitted_module=" as *u8); te_wn(1, emitted); te_w(1, " has_teng_run=" as *u8); te_wn(1, has_run)
237 te_w(1, " playthrough_mode=" as *u8); te_wn(1, mode)
238 if ok == 1 { te_w(1, " verdict=GREEN\n" as *u8) } else { te_w(1, " verdict=RED\n" as *u8) }
239 if fd >= 0 {
240 te_w(fd, "TACTICS-EMIT-GATE authored=organ spec=game_tactics parsed[grid_w16->" as *u8); te_wn(fd, cfg[0])
241 te_w(fd, " nplayer2->" as *u8); te_wn(fd, cfg[2]); te_w(fd, " nenemy2->" as *u8); te_wn(fd, cfg[3])
242 te_w(fd, "] emitted_module=" as *u8); te_wn(fd, emitted); te_w(fd, " has_teng_run=" as *u8); te_wn(fd, has_run)
243 te_w(fd, " playthrough_mode=" as *u8); te_wn(fd, mode)
244 if ok == 1 { te_w(fd, " verdict=GREEN\n" as *u8) } else { te_w(fd, " verdict=RED\n" as *u8) }
245 sys_close(fd)
246 }
247 if ok == 1 { sys_exit(0); return 0 }
248 sys_exit(1)
249 return 1
250}