code wiki / (root) / nx_worldgrade.nx

nx_worldgrade.nx source

↩ module page · 142 lines · 7896 B

1// nx_worldgrade.nx -- THE MISSING CONSUMER: grade a LIVE ENGINE WORLD with the 8-axis referee. 2// 3// nx_world_quality_grader.nx has existed since 2026-05-16 and had never graded anything, because 4// every one of its five declared consumers (nx_procgen_biome_test, nx_procgen_water_test, 5// nx_procgen_features_test, nx_procgen_signature_test, nx_layer_verdict) is SOURCE-ONLY and its own 6// main() is a SELF-TEST over synthetic fixtures. A grader whose only caller is its own unit test has 7// measured nothing about the product. This organ is the caller: it boots nx_wasm_craft's real world 8// generator at a recipe's (identity, seed), reads the terrain the engine ACTUALLY BUILT, and hands 9// that heightmap to the referee. 10// 11// THE SUBJECT IS THE REALISED VOXEL WORLD, NOT THE NOISE FUNCTION. wground(base,x,z) walks the column 12// down from WY-1 and returns the first solid block, so it sees erosion, the shore ramp, structures and 13// every gen-time row the engine applied -- whereas wheight() is the pre-build surface estimate. Those 14// are two different subjects and only one of them is what a player sees. 15// 16// SCOPE, STATED SO IT CANNOT BE OVER-READ: 17// * The FEATURE-VARIETY axis abstains (no feature histogram is supplied), so it scores 0 and can 18// only LOWER the grade. THE REPORTED GRADE IS THEREFORE A FLOOR, not a value -- it can rise when 19// a feature histogram is wired and can never fall for that reason. Announced in the output as 20// feature_hist=ABSENT so no reader can mistake the floor for the verdict. 21// * The BIOME map is the world's OWN surface block id at each column, read from the voxels. It is 22// not a labelling this organ invented, which is the whole point: a biome map derived here from 23// elevation would be graded against elevation and score well by construction -- a ruler measuring 24// its own reflection. 25// * gen-time recipe rows (world_recipes.conf column 7) are NOT applied. Every world whose row has 26// no spec column -- craft, beach, isle -- is therefore graded exactly as it ships. A world that 27// carries spec pairs (crags, ridge) would be graded as its BARE IDENTITY, so the output says 28// spec=NONE-APPLIED rather than letting the wrong subject pass as the right one. 29// license_tier: ORIGINAL No hw writes (Rule 26). 30// usage: nx_worldgrade <vnum> [seed] 31// exit: 0 graded | 2 usage 32import "nx_wasm_craft.nx" 33import "nx_world_quality_grader.nx" 34 35// The shipped recipes all carry this seed; it is a DEFAULT so the common call is one argument, and it 36// is echoed in the output so a run can never be read as being about a seed it was not given. 37const WG3_SEED_DEFAULT: i64 = 20260728 38// mmap rounds up to pages; the pad is the engine's own alignment slack, matching nx_world_snap's arena. 39const WG3_ARENA_PAD: i64 = 4096 40const WG3_ASCII_ZERO: i64 = 48 41const WG3_DEC: i64 = 10 42const WG3_ITOA_CAP: i64 = 32 43 44func wg3_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 45func wg3_puts(s: *u8) -> i64 { sys_write(1, s, wg3_slen(s)); return 0 } 46func wg3_pn(v: i64) -> i64 { 47 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 } 48 var m: i64 = v 49 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 50 let t: *u8 = sys_mmap(WG3_ITOA_CAP) 51 var k: i64 = 0 52 while m > 0 { t[k] = (WG3_ASCII_ZERO + (m % WG3_DEC)) as u8; m = m / WG3_DEC; k = k + 1 } 53 let o: *u8 = sys_mmap(WG3_ITOA_CAP) 54 var i: i64 = 0 55 while i < k { o[i] = t[k - 1 - i]; i = i + 1 } 56 sys_write(1, o, k) 57 return 0 58} 59func wg3_int(s: *u8) -> i64 { 60 var n: i64 = 0 61 var i: i64 = 0 62 while s[i] != (0 as u8) { 63 let c: i64 = s[i] as i64 64 if c >= WG3_ASCII_ZERO { if c < WG3_ASCII_ZERO + WG3_DEC { n = n*WG3_DEC + (c - WG3_ASCII_ZERO) } } 65 i = i + 1 66 } 67 return n 68} 69// THE LETTER COMES FROM THE GRADER'S OWN ENUM, never from a second table: a duplicate rubric drifts. 70func wg3_letter(g: i64) -> i64 { 71 if g == NX_GRADE_S { wg3_puts("S" as *u8); return 0 } 72 if g == NX_GRADE_A { wg3_puts("A" as *u8); return 0 } 73 if g == NX_GRADE_B { wg3_puts("B" as *u8); return 0 } 74 if g == NX_GRADE_C { wg3_puts("C" as *u8); return 0 } 75 if g == NX_GRADE_D { wg3_puts("D" as *u8); return 0 } 76 if g == NX_GRADE_F { wg3_puts("F" as *u8); return 0 } 77 wg3_puts("UNKNOWN" as *u8) 78 return 0 79} 80 81func main(argc: i64, argv: *i64) -> i64 { 82 if argc < 2 { 83 wg3_puts("usage: nx_worldgrade <vnum> [seed] -- grades the REALISED voxel terrain of that world\n" as *u8) 84 return 2 85 } 86 let v: i64 = wg3_int(argv[1] as *u8) 87 var seed: i64 = WG3_SEED_DEFAULT 88 if argc > 2 { seed = wg3_int(argv[2] as *u8) } 89 let base: i64 = sys_mmap(CRAFT_TOTAL + WG3_ARENA_PAD) as i64 90 init_impl_v(base, v, seed) 91 let n: i64 = WX*WZ 92 let hm: *i64 = sys_mmap(n*NX_SIZEOF_NX_INT) as *i64 93 let bm: *i64 = sys_mmap(n*NX_SIZEOF_NX_INT) as *i64 94 // A VOID COLUMN IS NOT A ZERO-HEIGHT COLUMN. wground returns -1 where nothing solid exists at all; 95 // folding that silently to 0 would invent a flat plain the world does not have and would drag the 96 // flatness axis toward the flattering answer. They are clamped so the grader can run, and COUNTED 97 // and ANNOUNCED so the reader knows how much of the grade rests on invented ground. 98 var voids: i64 = 0 99 var z: i64 = 0 100 while z < WZ { 101 var x: i64 = 0 102 while x < WX { 103 var g: i64 = wground(base, x, z) 104 if g < 0 { g = 0; voids = voids + 1 } 105 hm[z*WX + x] = g 106 bm[z*WX + x] = vget(base, x, g, z) 107 x = x + 1 108 } 109 z = z + 1 110 } 111 let out: *i64 = sys_mmap(NX_WQG_OUT_STRIDE*NX_SIZEOF_NX_INT) as *i64 112 let nullp: *i64 = 0 as *i64 113 // max_expected_relief = WY, the engine's OWN vertical extent. A world cannot have more relief than 114 // it has blocks, so the normaliser is a property of the engine rather than a number chosen here. 115 nx_world_quality_grade(hm, WX, WZ, WY, bm, nullp, 0, out) 116 wg3_puts("{\x22organ\x22:\x22nx_worldgrade\x22,\x22vnum\x22:" as *u8); wg3_pn(v) 117 wg3_puts(",\x22seed\x22:" as *u8); wg3_pn(seed) 118 wg3_puts(",\x22grid_w\x22:" as *u8); wg3_pn(WX) 119 wg3_puts(",\x22grid_h\x22:" as *u8); wg3_pn(WZ) 120 wg3_puts(",\x22max_expected_relief\x22:" as *u8); wg3_pn(WY) 121 wg3_puts(",\x22void_columns\x22:" as *u8); wg3_pn(voids) 122 wg3_puts(",\x22subject\x22:\x22realised-voxel-terrain-wground\x22" as *u8) 123 wg3_puts(",\x22spec\x22:\x22NONE-APPLIED\x22,\x22feature_hist\x22:\x22ABSENT\x22" as *u8) 124 wg3_puts(",\x22grade\x22:\x22" as *u8); wg3_letter(out[NX_WQG_OFF_GRADE]); wg3_puts("\x22" as *u8) 125 wg3_puts(",\x22grade_enum\x22:" as *u8); wg3_pn(out[NX_WQG_OFF_GRADE]) 126 wg3_puts(",\x22q\x22:" as *u8); wg3_pn(NX_WQG_Q) 127 wg3_puts(",\x22axis_win_floor\x22:" as *u8); wg3_pn(NX_WQG_AXIS_WIN_FLOOR) 128 wg3_puts(",\x22axis_marginal_floor\x22:" as *u8); wg3_pn(NX_WQG_AXIS_MARGINAL_FLOOR) 129 wg3_puts(",\x22diversity\x22:" as *u8); wg3_pn(out[NX_WQG_OFF_DIVERSITY]) 130 wg3_puts(",\x22local_variation\x22:" as *u8); wg3_pn(out[NX_WQG_OFF_LOCAL_VAR]) 131 wg3_puts(",\x22extremes\x22:" as *u8); wg3_pn(out[NX_WQG_OFF_EXTREMES]) 132 wg3_puts(",\x22flatness_penalty\x22:" as *u8); wg3_pn(out[NX_WQG_OFF_FLATNESS_PENALTY]) 133 wg3_puts(",\x22fractal_dim\x22:" as *u8); wg3_pn(out[NX_WQG_OFF_FRACTAL_DIM]) 134 wg3_puts(",\x22biome_coherence\x22:" as *u8); wg3_pn(out[NX_WQG_OFF_BIOME_COHERENCE]) 135 wg3_puts(",\x22feature_variety\x22:" as *u8); wg3_pn(out[NX_WQG_OFF_FEATURE_VARIETY]) 136 wg3_puts(",\x22readability\x22:" as *u8); wg3_pn(out[NX_WQG_OFF_READABILITY]) 137 wg3_puts(",\x22refine_axis\x22:" as *u8); wg3_pn(out[NX_WQG_OFF_REFINE_AXIS]) 138 wg3_puts(",\x22min_height\x22:" as *u8); wg3_pn(out[NX_WQG_OFF_MIN_HEIGHT]) 139 wg3_puts(",\x22max_height\x22:" as *u8); wg3_pn(out[NX_WQG_OFF_MAX_HEIGHT]) 140 wg3_puts("}\n" as *u8) 141 return 0 142}