code wiki / _hdl_build / nx_charjudge_gate.nx
nx_charjudge_gate.nx source
↩ module page · 277 lines · 10048 B
1// nx_charjudge_gate.nx -- the LIAR-KILLER battery for the v2 character judge, all fixtures SYNTHETIC +
2// deterministic (no file deps): a composed "character" (smooth bg + textured figure + border contours +
3// face patch with an eye pair), its eyeless twin, a flat blob, an aligned-16px patch-scramble of the
4// composed image, and the smooth+noise+palette COLLAGE that games v1. Teeth assert the HUMAN ordering,
5// per-axis kills, determinism, and the conf override path. Designing this battery already killed two
6// contour-axis designs before they shipped (plain run-length: dense noise is fully connected; scramble
7// seams are long lines) -- that is the gate doing its job at design time. license_tier: ORIGINAL expect_exit: 0
8import "nx_syscalls.nx"
9import "nx_charjudge_lib.nx"
10const CHG_W: i64 = 256
11const CHG_H: i64 = 256
12const CHG_LCG_A: i64 = 1103515245
13const CHG_LCG_C: i64 = 12345
14const CHG_LCG_M: i64 = 2147483647
15
16func gw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
17func gn(v: i64) -> i64 {
18 let b: *u8 = sys_mmap(32)
19 var x: i64 = v; var ng: i64 = 0
20 if x < 0 { ng = 1; x = 0-x }
21 var i: i64 = 31
22 if x == 0 { b[i]=48 as u8; i=i-1 }
23 while x > 0 { b[i]=(48+x%10) as u8; x=x/10; i=i-1 }
24 if ng == 1 { b[i]=45 as u8; i=i-1 }
25 sys_write(1,(b as i64+i+1) as *u8,31-i)
26 return 0
27}
28func chg_px(r: i64, g: i64, b: i64) -> i64 {
29 var r2: i64 = r
30 var g2: i64 = g
31 var b2: i64 = b
32 if r2 < 0 { r2 = 0 }
33 if r2 > 255 { r2 = 255 }
34 if g2 < 0 { g2 = 0 }
35 if g2 > 255 { g2 = 255 }
36 if b2 < 0 { b2 = 0 }
37 if b2 > 255 { b2 = 255 }
38 return r2 + g2*256 + b2*CHJ_MAGIC_65536
39}
40// composed character fixture. eyes=1 draws the eye pair.
41func chg_composed(fb: *i64, eyes: i64) -> i64 {
42 var s: i64 = 777
43 var y: i64 = 0
44 while y < CHG_H {
45 var x: i64 = 0
46 while x < CHG_W {
47 fb[y*CHG_W+x] = chg_px(40 + y, 80 + y/2, 250 - y/2)
48 x = x + 1
49 }
50 y = y + 1
51 }
52 y = 48
53 while y < 224 {
54 var x: i64 = 64
55 while x < 192 {
56 s = (s*CHG_LCG_A + CHG_LCG_C) & CHG_LCG_M
57 let nz: i64 = (s>>15) % 51 - 25
58 fb[y*CHG_W+x] = chg_px(60 + y%128 + nz, 50 + (x+y)%150 + nz, 90 + x%120 + nz)
59 x = x + 1
60 }
61 y = y + 1
62 }
63 // face patch (flat skin) so the eyes are the only compact dark blobs there
64 y = 64
65 while y < 120 {
66 var x: i64 = 96
67 while x < 176 {
68 fb[y*CHG_W+x] = chg_px(230, 200, 180)
69 x = x + 1
70 }
71 y = y + 1
72 }
73 if eyes == 1 {
74 var ey: i64 = 0-3
75 while ey <= 3 {
76 var ex: i64 = 0-3
77 while ex <= 3 {
78 if ex*ex + ey*ey <= 9 {
79 fb[(89+ey)*CHG_W + 113+ex] = chg_px(25, 20, 20)
80 fb[(89+ey)*CHG_W + 145+ex] = chg_px(25, 20, 20)
81 }
82 ex = ex + 1
83 }
84 ey = ey + 1
85 }
86 }
87 // 2px dark border = the long contours
88 y = 48
89 while y < 224 {
90 fb[y*CHG_W+64] = chg_px(30,30,40)
91 fb[y*CHG_W+65] = chg_px(30,30,40)
92 fb[y*CHG_W+190] = chg_px(30,30,40)
93 fb[y*CHG_W+191] = chg_px(30,30,40)
94 y = y + 1
95 }
96 var x5: i64 = 64
97 while x5 < 192 {
98 fb[48*CHG_W+x5] = chg_px(30,30,40)
99 fb[49*CHG_W+x5] = chg_px(30,30,40)
100 fb[222*CHG_W+x5] = chg_px(30,30,40)
101 fb[223*CHG_W+x5] = chg_px(30,30,40)
102 x5 = x5 + 1
103 }
104 return 0
105}
106func chg_blob(fb: *i64) -> i64 {
107 var y: i64 = 0
108 while y < CHG_H {
109 var x: i64 = 0
110 while x < CHG_W {
111 fb[y*CHG_W+x] = chg_px(40 + y, 80 + y/2, 250 - y/2)
112 x = x + 1
113 }
114 y = y + 1
115 }
116 y = 48
117 while y < 224 {
118 var x: i64 = 64
119 while x < 192 {
120 fb[y*CHG_W+x] = chg_px(200, 170, 150)
121 x = x + 1
122 }
123 y = y + 1
124 }
125 y = 48
126 while y < 224 {
127 fb[y*CHG_W+64] = chg_px(30,30,40)
128 fb[y*CHG_W+191] = chg_px(30,30,40)
129 y = y + 1
130 }
131 var x6: i64 = 64
132 while x6 < 192 {
133 fb[48*CHG_W+x6] = chg_px(30,30,40)
134 fb[223*CHG_W+x6] = chg_px(30,30,40)
135 x6 = x6 + 1
136 }
137 return 0
138}
139func chg_scramble(src: *i64, dst: *i64) -> i64 {
140 let P: i64 = 16
141 let nx: i64 = CHG_W/P
142 let ny: i64 = CHG_H/P
143 let n: i64 = nx*ny
144 let perm: *i64 = sys_mmap(n*8) as *i64
145 var i: i64 = 0
146 while i < n { perm[i] = i; i = i + 1 }
147 var s: i64 = 80404
148 i = n - 1
149 while i > 0 {
150 s = (s*CHG_LCG_A + CHG_LCG_C) & CHG_LCG_M
151 let j: i64 = s % (i+1)
152 let t: i64 = perm[i]; perm[i] = perm[j]; perm[j] = t
153 i = i - 1
154 }
155 i = 0
156 while i < n {
157 let src2: i64 = perm[i]
158 let dx: i64 = (i%nx)*P
159 let dy: i64 = (i/nx)*P
160 let sx: i64 = (src2%nx)*P
161 let sy: i64 = (src2/nx)*P
162 var yy: i64 = 0
163 while yy < P {
164 var xx: i64 = 0
165 while xx < P { dst[(dy+yy)*CHG_W + dx+xx] = src[(sy+yy)*CHG_W + sx+xx]; xx = xx + 1 }
166 yy = yy + 1
167 }
168 i = i + 1
169 }
170 return 0
171}
172func chg_collage(fb: *i64) -> i64 {
173 var s: i64 = 4242
174 var y: i64 = 0
175 while y < CHG_H {
176 var x: i64 = 0
177 while x < CHG_W {
178 if x < CHG_W/2 { fb[y*CHG_W+x] = chg_px(120, 140, 160) }
179 if x >= CHG_W/2 {
180 // high bits: an LCG's LOW bits have period 2^k -- s%256 gave PERIODIC stripes, i.e.
181 // real coherent contours, and the "noise" collage wasn't noise (gate T4 caught it)
182 s = (s*CHG_LCG_A + CHG_LCG_C) & CHG_LCG_M
183 let r: i64 = (s>>15) % 256
184 s = (s*CHG_LCG_A + CHG_LCG_C) & CHG_LCG_M
185 let g: i64 = (s>>15) % 256
186 s = (s*CHG_LCG_A + CHG_LCG_C) & CHG_LCG_M
187 let b: i64 = (s>>15) % 256
188 fb[y*CHG_W+x] = chg_px(r, g, b)
189 }
190 x = x + 1
191 }
192 y = y + 1
193 }
194 return 0
195}
196func tooth(name: *u8, ok: i64, fails: *i64) -> i64 {
197 if ok == 1 { gw("PASS " as *u8) }
198 if ok != 1 { gw("FAIL " as *u8); fails[0] = fails[0] + 1 }
199 gw(name)
200 gw("\n" as *u8)
201 return 0
202}
203
204func main() -> i64 {
205 gw("=== nx_charjudge_gate -- liar-killer battery for the v2 character judge ===\n" as *u8)
206 let fails: *i64 = sys_mmap(16) as *i64
207 fails[0] = 0
208 let npx: i64 = CHG_W*CHG_H
209 let fA: *i64 = sys_mmap(npx*8) as *i64
210 let fB: *i64 = sys_mmap(npx*8) as *i64
211 let fS: *i64 = sys_mmap(npx*8) as *i64
212 let fC: *i64 = sys_mmap(npx*8) as *i64
213 let fE: *i64 = sys_mmap(npx*8) as *i64
214 chg_composed(fA, 1)
215 chg_blob(fB)
216 chg_scramble(fA, fS)
217 chg_collage(fC)
218 chg_composed(fE, 0)
219 let oA: *i64 = sys_mmap(96) as *i64
220 let oA2: *i64 = sys_mmap(96) as *i64
221 let oB: *i64 = sys_mmap(96) as *i64
222 let oS: *i64 = sys_mmap(96) as *i64
223 let oC: *i64 = sys_mmap(96) as *i64
224 let oE: *i64 = sys_mmap(96) as *i64
225 let cp: *u8 = "knowledge/charjudge.conf" as *u8
226 chj_judge(fA, CHG_W, CHG_H, cp, oA)
227 chj_judge(fA, CHG_W, CHG_H, cp, oA2)
228 chj_judge(fB, CHG_W, CHG_H, cp, oB)
229 chj_judge(fS, CHG_W, CHG_H, cp, oS)
230 chj_judge(fC, CHG_W, CHG_H, cp, oC)
231 chj_judge(fE, CHG_W, CHG_H, cp, oE)
232 gw("composed: head=" as *u8); gn(oA[4]); gw(" comp=" as *u8); gn(oA[0]); gw(" pal=" as *u8); gn(oA[1]); gw(" con=" as *u8); gn(oA[2]); gw(" face=" as *u8); gn(oA[3]); gw("\n" as *u8)
233 gw("blob: head=" as *u8); gn(oB[4]); gw(" comp=" as *u8); gn(oB[0]); gw(" face=" as *u8); gn(oB[3]); gw("\n" as *u8)
234 gw("scramble: head=" as *u8); gn(oS[4]); gw(" comp=" as *u8); gn(oS[0]); gw(" con=" as *u8); gn(oS[2]); gw("\n" as *u8)
235 gw("collage: head=" as *u8); gn(oC[4]); gw(" comp=" as *u8); gn(oC[0]); gw(" con=" as *u8); gn(oC[2]); gw("\n" as *u8)
236 gw("eyeless: head=" as *u8); gn(oE[4]); gw(" face=" as *u8); gn(oE[3]); gw("\n" as *u8)
237 var t: i64 = 0
238 if oA[4] >= 600 { t = 1 }
239 tooth("T1 composed character scores >= 600" as *u8, t, fails)
240 t = 0
241 if oB[3] == 0 { if oB[4] == 0 { t = 1 } }
242 tooth("T2 faceless flat blob floors to 0 (face axis)" as *u8, t, fails)
243 // a 16px-grid scramble GENUINELY contains long straight seam lines, so contour cannot floor it to
244 // zero -- the honest claim is a deep drop below the composed original (real-content scrambles
245 // measured 20/1000 on the kk portrait; this synthetic bg has gentler seams)
246 t = 0
247 if oS[4] < 300 { if oS[4]*3 < oA[4] { t = 1 } }
248 tooth("T3 16px scramble drops below 300 and below composed/3" as *u8, t, fails)
249 t = 0
250 if oC[2] < 100 { if oC[4] < 100 { t = 1 } }
251 tooth("T4 smooth+noise+palette collage floors (contour kills the v1 gameable vector)" as *u8, t, fails)
252 t = 0
253 if oE[3] == 0 { if oE[4] == 0 { if oA[3] == 1000 { t = 1 } } }
254 tooth("T5 face axis isolated: eyeless twin 0, eyed twin 1000" as *u8, t, fails)
255 t = 0
256 if oA[4] == oA2[4] { t = 1 }
257 tooth("T6 deterministic (same fixture twice, same headline)" as *u8, t, fails)
258 // T7: conf override path -- face_required=0 lifts the eyeless twin off the floor
259 let cfd: i64 = sys_openat_wr("/tmp/chj_face_off.conf" as *u8, 0x1a4)
260 let cstr: *u8 = "face_required=0\n" as *u8
261 var cn: i64 = 0
262 while cstr[cn] != (0 as u8) { cn = cn + 1 }
263 sys_write(cfd, cstr, cn)
264 sys_close(cfd)
265 let oE2: *i64 = sys_mmap(96) as *i64
266 chj_judge(fE, CHG_W, CHG_H, "/tmp/chj_face_off.conf" as *u8, oE2)
267 t = 0
268 if oE2[4] > 0 { t = 1 }
269 tooth("T7 conf override proven live (face_required=0 lifts the eyeless twin)" as *u8, t, fails)
270 t = 0
271 if oA[4] > oB[4] { if oA[4] > oS[4] { if oA[4] > oC[4] { t = 1 } } }
272 tooth("T8 strict ordering: composed above blob, scramble, collage" as *u8, t, fails)
273 if fails[0] == 0 { gw("CHARJUDGE-GATE GREEN 8/8\n" as *u8); sys_exit(0); return 0 }
274 gw("CHARJUDGE-GATE RED fails=" as *u8); gn(fails[0]); gw("\n" as *u8)
275 sys_exit(1)
276 return 1
277}