code wiki / _hdl_build / nx_tactics_engine_gate.nx

nx_tactics_engine_gate.nx source

↩ module page · 196 lines · 7698 B

1// nx_tactics_engine_gate.nx -- gate for the data-driven TACTICS SIMULATION engine (G-ECO-005 rung 1). 2// Drives the REAL nx_tactics_engine_lib headlessly (no terminal) and asserts the engine is genuinely 3// CONFIG-DRIVEN + the core mechanics work, by RUNNING (not asserting): 4// (1) DATA-DRIVEN: two distinct configs yield distinct rosters (2v2 vs 2v3, 4 vs 5 units). 5// (2) WIN/LOSE both reachable: clearing team1 -> mode=win; clearing team0 -> mode=lose. 6// (3) COVER matters: hit-chance on open cell > hit-chance on a cover cell (same distance). 7// (4) BOUNDS: out-of-grid reads = wall; a move into a wall is rejected (no move, no move spent). 8// (5) EMERGENT PLAYTHROUGH: a scripted bot (advance-to-range + shoot) drives a full 2v2 battle to a 9// RESOLUTION (win or lose) within a bounded turn budget -- the whole turn loop + AI run end-to-end. 10// TACTICS-ENGINE-GATE verdict=GREEN iff all hold -> knowledge/status/tactics_engine.log. 11// license_tier: ORIGINAL 12import "nx_syscalls.nx" 13import "nx_tactics_engine_lib.nx" 14 15func tg_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 } 16func tg_n(fd: i64, v: i64) -> i64 { 17 var m: i64 = v 18 if m < 0 { sys_write(fd, "-" as *u8, 1); m = 0 - m } 19 let bb: *u8 = sys_mmap(28); let t: *u8 = sys_mmap(28); var k: i64 = 0 20 if m == 0 { t[0] = 48 as u8; k = 1 } 21 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 22 var i: i64 = 0 23 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 24 sys_write(fd, bb, k); return 0 25} 26 27func tg_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 28func tg_has(buf: *u8, len: i64, pat: *u8) -> i64 { 29 let pl: i64 = tg_len(pat) 30 var i: i64 = 0 31 while i + pl <= len { 32 var j: i64 = 0; var ok: i64 = 1 33 while j < pl { if buf[i + j] != pat[j] { ok = 0 } j = j + 1 } 34 if ok == 1 { return 1 } 35 i = i + 1 36 } 37 return 0 38} 39func tg_count_nl(buf: *u8, len: i64) -> i64 { 40 var n: i64 = 0; var i: i64 = 0 41 while i < len { if buf[i] == (10 as u8) { n = n + 1 } i = i + 1 } 42 return n 43} 44 45// scripted bot: advance the active player toward the nearest foe, shoot when in range; drive the 46// whole battle to a resolution. returns final mode (0 if it hit the cap = unresolved). itout[0]=iters. 47func tbot(st: *i64, cap: i64, itout: *i64) -> i64 { 48 var iter: i64 = 0 49 while iter < cap { 50 if st[2] != 0 { itout[0] = iter; return st[2] } 51 let ci: i64 = st[1] 52 if ci < 0 { itout[0] = iter; return st[2] } 53 let ei: i64 = teng_nearest_foe(st, st[16 + ci], st[22 + ci], st[34 + ci]) 54 if ei < 0 { teng_check_end(st); itout[0] = iter; return st[2] } 55 let d: i64 = teng_dist(st[16 + ci], st[22 + ci], st[16 + ei], st[22 + ei]) 56 if d <= st[71] { 57 teng_input(st, 4) 58 } else { 59 let ox: i64 = st[16 + ci]; let oy: i64 = st[22 + ci] 60 let tx: i64 = st[16 + ei]; let ty: i64 = st[22 + ei] 61 var key: i64 = 0 - 1 62 if teng_abs(tx - ox) >= teng_abs(ty - oy) { 63 if tx > ox { key = 3 } 64 if tx < ox { key = 2 } 65 } else { 66 if ty > oy { key = 1 } 67 if ty < oy { key = 0 } 68 } 69 if key < 0 { teng_input(st, 5) } else { 70 teng_input(st, key) 71 var moved: i64 = 1 72 if st[16 + ci] == ox { if st[22 + ci] == oy { moved = 0 } } 73 if moved == 0 { teng_input(st, 5) } else { if st[5] <= 0 { teng_input(st, 5) } } 74 } 75 } 76 iter = iter + 1 77 } 78 itout[0] = iter 79 return st[2] 80} 81 82func tg_report(fd: i64, r: *i64, ok: i64) -> i64 { 83 tg_w(fd, "TACTICS-ENGINE-GATE authored=organ datadriven[A_squad2->" as *u8); tg_n(fd, r[0]) 84 tg_w(fd, " A_enemy2->" as *u8); tg_n(fd, r[1]) 85 tg_w(fd, " B_enemy3->" as *u8); tg_n(fd, r[2]) 86 tg_w(fd, " B_units5->" as *u8); tg_n(fd, r[3]) 87 tg_w(fd, "] winlose[win->" as *u8); tg_n(fd, r[4]) 88 tg_w(fd, " lose->" as *u8); tg_n(fd, r[5]) 89 tg_w(fd, "] cover[open=" as *u8); tg_n(fd, r[6]) 90 tg_w(fd, ">covered=" as *u8); tg_n(fd, r[7]) 91 tg_w(fd, "] bounds[oobL=" as *u8); tg_n(fd, r[8]) 92 tg_w(fd, " oobR=" as *u8); tg_n(fd, r[9]) 93 tg_w(fd, " wallblock=" as *u8); tg_n(fd, r[10]) 94 tg_w(fd, "] play[resolved=" as *u8); tg_n(fd, r[13]) 95 tg_w(fd, " mode=" as *u8); tg_n(fd, r[11]) 96 tg_w(fd, " iters=" as *u8); tg_n(fd, r[12]) 97 tg_w(fd, "] render[len=" as *u8); tg_n(fd, r[14]) 98 tg_w(fd, " hud=" as *u8); tg_n(fd, r[15]) 99 tg_w(fd, " P1=" as *u8); tg_n(fd, r[16]) 100 tg_w(fd, " E1=" as *u8); tg_n(fd, r[17]) 101 tg_w(fd, " rows=" as *u8); tg_n(fd, r[18]) 102 if ok == 1 { tg_w(fd, "] verdict=GREEN\n" as *u8) } else { tg_w(fd, "] verdict=RED\n" as *u8) } 103 return 0 104} 105 106func main() -> i64 { 107 let st: *i64 = sys_mmap(8192) as *i64 108 let cfg: *i64 = sys_mmap(128) as *i64 109 let r: *i64 = sys_mmap(128) as *i64 110 let itp: *i64 = sys_mmap(16) as *i64 111 112 // config A = 2v2 113 cfg[0] = 16; cfg[1] = 12; cfg[2] = 2; cfg[3] = 2; cfg[4] = 10; cfg[5] = 5; cfg[6] = 5 114 cfg[7] = 9; cfg[8] = 10; cfg[9] = 8; cfg[10] = 8; cfg[11] = 3; cfg[12] = 3; cfg[13] = 12345 115 116 // (1) data-driven rosters 117 teng_init(st, cfg) 118 r[0] = teng_team_alive(st, 0) 119 r[1] = teng_team_alive(st, 1) 120 cfg[3] = 3; cfg[4] = 20 // config B = 2v3, tougher 121 teng_init(st, cfg) 122 r[2] = teng_team_alive(st, 1) 123 r[3] = teng_nunits(st) 124 cfg[3] = 2; cfg[4] = 10 // back to A 125 126 // (2) win/lose logic both reachable 127 teng_init(st, cfg) 128 let nu: i64 = teng_nunits(st) 129 var i: i64 = st[66] 130 while i < nu { st[40 + i] = 0; i = i + 1 } // clear team1 131 teng_check_end(st) 132 r[4] = st[2] 133 teng_init(st, cfg) 134 var j: i64 = 0 135 while j < st[66] { st[40 + j] = 0; j = j + 1 } // clear team0 136 teng_check_end(st) 137 r[5] = st[2] 138 139 // (3) cover reduces hit chance 140 teng_init(st, cfg) 141 r[6] = teng_chance(st, 2, 0) 142 r[7] = teng_chance(st, 2, 1) 143 144 // (4) bounds + wall-block 145 r[8] = 0 146 if teng_cell_get(st, 0 - 1, 0) == 1 { r[8] = 1 } 147 r[9] = 0 148 if teng_cell_get(st, st[64], 0) == 1 { r[9] = 1 } 149 let ci: i64 = st[1] 150 st[16 + ci] = 1; st[22 + ci] = 1; st[5] = 5 151 teng_move_unit(st, ci, 0, 0 - 1) 152 r[10] = 0 153 if st[22 + ci] == 1 { if st[5] == 5 { r[10] = 1 } } 154 155 // (5) emergent playthrough -> resolution 156 teng_init(st, cfg) 157 r[11] = tbot(st, 6000, itp) 158 r[12] = itp[0] 159 r[13] = 0 160 if r[11] != 0 { r[13] = 1 } 161 162 // (6) RENDER (rung 2): a fresh battle renders an ANSI frame with HUD + both teams' unit glyphs 163 teng_init(st, cfg) 164 let fb: *u8 = sys_mmap(16384) 165 let flen: i64 = teng_render(fb, st) 166 r[14] = flen 167 r[15] = tg_has(fb, flen, "TACTICS" as *u8) 168 r[16] = tg_has(fb, flen, "P1" as *u8) 169 r[17] = tg_has(fb, flen, "E1" as *u8) 170 r[18] = tg_count_nl(fb, flen) 171 172 var ok: i64 = 1 173 if r[0] != 2 { ok = 0 } 174 if r[1] != 2 { ok = 0 } 175 if r[2] != 3 { ok = 0 } 176 if r[3] != 5 { ok = 0 } 177 if r[4] != 1 { ok = 0 } 178 if r[5] != 2 { ok = 0 } 179 if r[6] <= r[7] { ok = 0 } 180 if r[8] != 1 { ok = 0 } 181 if r[9] != 1 { ok = 0 } 182 if r[10] != 1 { ok = 0 } 183 if r[13] != 1 { ok = 0 } 184 if r[14] <= 200 { ok = 0 } 185 if r[15] != 1 { ok = 0 } 186 if r[16] != 1 { ok = 0 } 187 if r[17] != 1 { ok = 0 } 188 if r[18] < 12 { ok = 0 } 189 190 tg_report(1, r, ok) 191 let lf: i64 = sys_openat_append("knowledge/status/tactics_engine.log" as *u8, 420) 192 if lf >= 0 { tg_report(lf, r, ok); sys_close(lf) } 193 if ok == 1 { sys_exit(0); return 0 } 194 sys_exit(1) 195 return 1 196}