code wiki / _hdl_build / nx_procgen_terrain_gate.nx

nx_procgen_terrain_gate.nx source

↩ module page · 221 lines · 10138 B

1// nx_procgen_terrain_gate.nx -- Gx/PROCGEN: rule-grounded, seed-diverse procedural terrain (the Infinigen 2// direction: procedural, asset-free, parametric-for-diversity, NOT random noise). FBM value-noise heightfield -> 3// D8 flow-direction -> flow-accumulation (descending-elevation pass = a real WATERSHED) -> rivers that PROVABLY 4// flow downhill (the clay-audit named "rivers that don't flow downhill" as the failure) -> shaded-relief render 5// (hillshade x altitude colormap, rivers blue). Three SEEDS side-by-side = parametric diversity (don't overfit to 6// one environment). All integer, deterministic, sovereign. Honest: this is coherence rung 1, not photoreal yet. 7// D001 MIGRATION 2026-09-02 (procgen PG19): the verdict was hand-rolled (PASS/FAIL prints, a fails counter, sys_exit(1)), so 8// /api/promote refused it and nothing outside could read its outcome. Every tooth is now a gv_check and the exit code IS the 9// verdict (nx_gate_verdict). The measurements, thresholds and the PNG are unchanged. 10// license_tier: ORIGINAL expect_exit: 0 11import "nx_syscalls.nx" 12import "nx_gate_verdict.nx" 13import "nx_png_write.nx" 14 15func pt_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 16func pt_pn(v: i64) -> i64 { let b: *u8=sys_mmap(32) as *u8; var x: i64=v; var ng: i64=0; if x<0{ng=1;x=0-x} var i: i64=31; if x==0{b[i]=48 as u8;i=i-1} while x>0{b[i]=(48+x%10) as u8;x=x/10;i=i-1} if ng==1{b[i]=45 as u8;i=i-1} sys_write(1,(b as i64+i+1) as *u8,31-i); return 0 } 17 18// integer hash -> [0,4095] 19func pt_hash2(x: i64, y: i64, seed: i64) -> i64 { 20 var a: i64=(x+1)*73856093 + (y+1)*19349663 + (seed+1)*83492791 21 a = a % 16777216 22 if a<0 { a = a + 16777216 } 23 a = (a*1103515245 + 12345) % 16777216 24 if a<0 { a = a + 16777216 } 25 return a % 4096 26} 27// smoothstep on Q12 t in [0,4096] 28func pt_smooth(t: i64) -> i64 { let t2: i64=(t*t)/4096; return (t2*(3*4096 - 2*t))/4096 } 29// value noise at (px,py) with `lat` lattice cells across dim `sz`, seed -> [0,4095] 30func pt_vnoise(px: i64, py: i64, lat: i64, sz: i64, seed: i64) -> i64 { 31 let fx: i64=(px*lat*4096)/sz 32 let fy: i64=(py*lat*4096)/sz 33 let gx: i64=fx/4096; let tx: i64=fx-gx*4096 34 let gy: i64=fy/4096; let ty: i64=fy-gy*4096 35 let c00: i64=pt_hash2(gx,gy,seed) 36 let c10: i64=pt_hash2(gx+1,gy,seed) 37 let c01: i64=pt_hash2(gx,gy+1,seed) 38 let c11: i64=pt_hash2(gx+1,gy+1,seed) 39 let sx: i64=pt_smooth(tx); let sy: i64=pt_smooth(ty) 40 let top: i64=c00 + ((c10-c00)*sx)/4096 41 let bot: i64=c01 + ((c11-c01)*sx)/4096 42 return top + ((bot-top)*sy)/4096 43} 44// FBM 5 octaves -> [0,HMAX] 45func pt_fbm(px: i64, py: i64, sz: i64, seed: i64) -> i64 { 46 var h: i64=0; var amp: i64=2048; var lat: i64=5; var norm: i64=0; var o: i64=0 47 while o<5 { 48 let v: i64=pt_vnoise(px,py,lat,sz,seed+o*131) 49 h = h + (v*amp)/4096 50 norm = norm + amp 51 amp = amp/2 52 lat = lat*2 53 o = o+1 54 } 55 if norm<1 { norm=1 } 56 return (h*4000)/norm 57} 58 59func main() -> i64 { 60 pt_puts("=== nx_procgen_terrain_gate -- rule-grounded seed-diverse procedural terrain (Infinigen direction) ===\n" as *u8) 61 let ctr: *i64=gv_ctr() 62 let TW: i64=280; let TH: i64=280; let GAP: i64=20 63 let W: i64=TW*3+GAP*2; let H: i64=TH 64 let N: i64=TW*TH 65 let rgb: *u8=sys_mmap(W*H*3+16) 66 var i: i64=0 67 while i<W*H { let o: i64=i*3; rgb[o]=10 as u8; rgb[o+1]=12 as u8; rgb[o+2]=18 as u8; i=i+1 } 68 let hf: *i64=sys_mmap(N*8) as *i64 69 let dn: *i64=sys_mmap(N*8) as *i64 70 let ac: *i64=sys_mmap(N*8) as *i64 71 let order: *i64=sys_mmap(N*8) as *i64 72 let NB: i64=260 73 let cnt: *i64=sys_mmap(NB*8) as *i64 74 let pos: *i64=sys_mmap(NB*8) as *i64 75 // dx/dy for 8 neighbors 76 let ndx: *i64=sys_mmap(8*8) as *i64 77 let ndy: *i64=sys_mmap(8*8) as *i64 78 ndx[0]=0-1; ndx[1]=0; ndx[2]=1; ndx[3]=0-1; ndx[4]=1; ndx[5]=0-1; ndx[6]=0; ndx[7]=1 79 ndy[0]=0-1; ndy[1]=0-1; ndy[2]=0-1; ndy[3]=0; ndy[4]=0; ndy[5]=1; ndy[6]=1; ndy[7]=1 80 var globaldownhill: i64=0; var globalriver: i64=0; var hrange0: i64=0 81 var s: i64=0 82 while s<3 { 83 let seed: i64=1000 + s*777 84 // 1) heightfield 85 var hmin: i64=999999; var hmax: i64=0 86 var py: i64=0 87 while py<TH { 88 var px: i64=0 89 while px<TW { 90 let hv: i64=pt_fbm(px,py,TW,seed) 91 hf[py*TW+px]=hv 92 if hv<hmin { hmin=hv } 93 if hv>hmax { hmax=hv } 94 px=px+1 95 } 96 py=py+1 97 } 98 if s==0 { hrange0=hmax-hmin } 99 // 2) D8 flow direction (interior; border -> self) 100 var c: i64=0 101 while c<N { 102 dn[c]=c; ac[c]=1 103 c=c+1 104 } 105 py=1 106 while py<TH-1 { 107 var px: i64=1 108 while px<TW-1 { 109 let ci: i64=py*TW+px 110 let hc: i64=hf[ci] 111 var best: i64=hc; var bidx: i64=ci 112 var k: i64=0 113 while k<8 { 114 let ni: i64=(py+ndy[k])*TW + (px+ndx[k]) 115 if hf[ni]<best { best=hf[ni]; bidx=ni } 116 k=k+1 117 } 118 dn[ci]=bidx 119 px=px+1 120 } 121 py=py+1 122 } 123 // 3) counting sort by height/16 ascending 124 var b: i64=0 125 while b<NB { cnt[b]=0; b=b+1 } 126 c=0 127 while c<N { var bb: i64=hf[c]/16; if bb<0 {bb=0} if bb>=NB {bb=NB-1} cnt[bb]=cnt[bb]+1; c=c+1 } 128 pos[0]=0; b=1 129 while b<NB { pos[b]=pos[b-1]+cnt[b-1]; b=b+1 } 130 c=0 131 while c<N { var bb: i64=hf[c]/16; if bb<0 {bb=0} if bb>=NB {bb=NB-1} order[pos[bb]]=c; pos[bb]=pos[bb]+1; c=c+1 } 132 // 4) flow accumulation: process descending height 133 var oi: i64=N-1 134 while oi>=0 { 135 let cell: i64=order[oi] 136 let d: i64=dn[cell] 137 if d!=cell { ac[d]=ac[d]+ac[cell] } 138 oi=oi-1 139 } 140 // 5) render into canvas at x-offset 141 let xoff: i64=s*(TW+GAP) 142 var rdownhill: i64=0; var rriver: i64=0 143 py=1 144 while py<TH-1 { 145 var px: i64=1 146 while px<TW-1 { 147 let ci: i64=py*TW+px 148 let hc: i64=hf[ci] 149 // hillshade from gradient 150 let dzdx: i64=hf[ci+1]-hf[ci-1] 151 let dzdy: i64=hf[ci+TW]-hf[ci-TW] 152 var shade: i64=150 + (0-dzdx-dzdy)/6 153 if shade<40 { shade=40 } 154 if shade>255 { shade=255 } 155 // altitude colormap 156 var br: i64=0; var bg: i64=0; var bb2: i64=0 157 if hc<700 { br=40; bg=90; bb2=140 } 158 else { if hc<1600 { br=70; bg=120; bb2=60 } 159 else { if hc<2600 { br=110; bg=95; bb2=60 } 160 else { if hc<3300 { br=140; bg=132; bb2=122 } 161 else { br=222; bg=222; bb2=228 } } } } 162 let isriver: i64=ac[ci] 163 if isriver>90 { br=50; bg=110; bb2=205 } 164 var rr: i64=(br*shade)/255; var gg: i64=(bg*shade)/255; var bl: i64=(bb2*shade)/255 165 if rr>255 {rr=255} if gg>255 {gg=255} if bl>255 {bl=255} 166 let ox: i64=xoff+px 167 if ox<W { let o: i64=(py*W+ox)*3 168 rgb[o]=rr as u8; rgb[o+1]=gg as u8; rgb[o+2]=bl as u8 } 169 // downhill proof: river cells whose downstream is strictly lower 170 if isriver>90 { let d: i64=dn[ci] 171 if d!=ci { rriver=rriver+1; if hf[d]<hc { rdownhill=rdownhill+1 } } } 172 px=px+1 173 } 174 py=py+1 175 } 176 globaldownhill=globaldownhill+rdownhill; globalriver=globalriver+rriver 177 pt_puts(" seed "); pt_pn(seed); pt_puts(": hrange="); pt_pn(hmax-hmin); pt_puts(" rivercells="); pt_pn(rriver); pt_puts(" downhill="); pt_pn(rdownhill); pt_puts("\n" as *u8) 178 s=s+1 179 } 180 nx_png_write_rgb("knowledge/nx_procgen_terrain.png\x00" as *u8, rgb, W, H) 181 pt_puts(" wrote knowledge/nx_procgen_terrain.png\n" as *u8) 182 // T1 varied heightfield 183 var t1: i64=0 184 if hrange0>1500 { t1=1 } 185 pt_puts(" hrange(seed0)="); pt_pn(hrange0); pt_puts("\n" as *u8) 186 gv_check("T1 heightfield is varied, not flat (seed0 height range over 1500)" as *u8, t1, ctr) 187 // T2 water flows downhill (watershed coherence) 188 var pct: i64=0 189 if globalriver>0 { pct=(globaldownhill*100)/globalriver } 190 pt_puts(" river cells="); pt_pn(globalriver); pt_puts(" flowing-downhill="); pt_pn(pct); pt_puts("%\n" as *u8) 191 var t2: i64=0 192 if globalriver>200 { if pct>=95 { t2=1 } } 193 gv_check("T2 rivers provably flow downhill: over 200 river cells and at least 95 percent with a strictly lower downstream cell (a real watershed, not noise)" as *u8, t2, ctr) 194 // T3 seed diversity (parametric = don't overfit) 195 var dsum: i64=0; var samp: i64=0; var sy2: i64=10 196 while sy2<TH-10 { 197 var sx2: i64=10 198 while sx2<TW-10 { 199 let a: i64=pt_fbm(sx2,sy2,TW,1000) 200 let c2: i64=pt_fbm(sx2,sy2,TW,1000+2*777) 201 var dd: i64=a-c2; if dd<0 {dd=0-dd} 202 dsum=dsum+dd; samp=samp+1 203 sx2=sx2+23 204 } 205 sy2=sy2+23 206 } 207 var davg: i64=0 208 if samp>0 { davg=dsum/samp } 209 pt_puts(" seed diversity avg|dh|="); pt_pn(davg); pt_puts("\n" as *u8) 210 var t3: i64=0 211 if davg>200 { t3=1 } 212 gv_check("T3 seeds produce diverse terrain: mean absolute height difference between two seeds over 200 (parametric, no overfit)" as *u8, t3, ctr) 213 // T4 png 214 let szp: *i64=sys_mmap(16) as *i64 215 let rb: *u8=sys_read_file("knowledge/nx_procgen_terrain.png\x00" as *u8, szp) 216 var t4: i64=0 217 if (rb as i64)!=0 { if szp[0]>1000 { t4=1 } } 218 if (rb as i64)!=0 { pt_puts(" png bytes="); pt_pn(szp[0]); pt_puts("\n" as *u8) } 219 gv_check("T4 the shaded-relief PNG was written and reads back over 1000 bytes" as *u8, t4, ctr) 220 return gv_verdict("nx_procgen_terrain_gate" as *u8, ctr, "rule-grounded, seed-diverse, watershed-coherent procedural terrain (Infinigen direction, sovereign integer); coherence rung, not photoreal" as *u8) 221}