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}