nx_world_quality_grader.nx source
↩ module page · 905 lines · 36490 B
1// nx_world_quality_grader.nx -- mathematical verdict for procgen worlds.
2//
3// Per user 2026-05-16: "build an iterative loop like we got going on
4// elder ai i dont want to have to manually check if you generate good
5// maps. does minecraft or these other prc gens have something that
6// actually mathematically measures if the world is good like how god
7// says and i saw it was good as a confirmation check its not trash"
8//
9// Genesis 1:31 -- "And God saw every thing that he had made, and,
10// behold, it was very good." This primitive ships the substrate's
11// SABBATH GRADER for generated worlds: a per-tick verdict over a
12// heightmap that returns sealed-enum grade + per-axis Q14 scores +
13// refine-axis directive so the caller can iterate.
14//
15// Most procgens (Minecraft, Houdini, No Man's Sky, Spelunky) have
16// NO mathematical world-quality measurement -- generation is one-shot
17// noise with hand-tuned constants. The substrate's posture is
18// honest-perf-verdict: every output has a measurable verdict, and
19// every LOSE carries a named_improvement. This primitive surfaces
20// that posture at the WORLD level.
21//
22// FULL CAPABILITY (per feedback-maximum-capability-no-simplification
23// cardinal, 2026-05-16):
24//
25// 8 axes:
26// DIVERSITY -- (max-min) / max_possible_relief. Range-based.
27// LOCAL_VARIATION -- mean |neighbour-difference| / max_relief.
28// Banded (too jagged is also bad).
29// EXTREMES -- ratio of cells in top-10% + bottom-10%.
30// Signature features push this up.
31// FLATNESS_PENALTY -- ratio of cells at modal-bucket height.
32// HIGHER = MORE FLAT = WORSE; verdict inverts.
33// FRACTAL_DIM -- Hurst-exponent estimator via multi-scale
34// mean-abs-diff slope. Spehar 2003: most
35// aesthetically pleasing fractal dimension band
36// maps to H in [0.3, 0.7]. Peak band 0.4-0.6.
37// BIOME_COHERENCE -- fraction of cells where biome ID matches
38// expected elevation band (DESERT at low,
39// FOREST at mid, SNOW at high). Caller-supplied
40// biome_map. Skipped (verdict=MARGINAL) if NULL.
41// FEATURE_VARIETY -- normalised Shannon entropy of the feature-kind
42// histogram. An all-forest world scores low;
43// multi-kind worlds score high. Caller-supplied
44// feature_hist. Skipped (=MARGINAL) if NULL.
45// READABILITY -- fraction of cells where the 3x3 local stddev
46// sits in the "legible" band [0.05Q, 0.25Q]
47// relative to local mean. Too noisy -> illegible;
48// too smooth -> boring.
49//
50// Output buffer layout (12 i64):
51// out[0] = overall_grade (NX_GRADE_F .. NX_GRADE_S)
52// out[1] = diversity_q14
53// out[2] = local_variation_q14
54// out[3] = extremes_q14
55// out[4] = flatness_penalty_q14 (HIGHER = MORE FLAT = WORSE)
56// out[5] = fractal_dim_q14
57// out[6] = biome_coherence_q14
58// out[7] = feature_variety_q14
59// out[8] = readability_q14
60// out[9] = refine_axis (NX_WQG_REFINE_*)
61// out[10] = min_height_observed
62// out[11] = max_height_observed
63//
64// Loss audit: all ratios in Q14 fixed-point; no FP. Statistics
65// computed in two passes (min/max/sum + histogram + neighbour-diff)
66// over the heightmap. No squaring/variance to avoid i64 overflow
67// for large heightmaps.
68//
69// genealogy_id: spehar_2003_universal_aesthetic_fractals +
70// berlyne_1974_aesthetic_complexity +
71// kaplan_1987_environmental_preference +
72// shannon_1948_information_entropy +
73// nx_quality_grade_sclass_canon (substrate convention)
74// lineage_id: nx_world_quality_grader_8axis_q14_v2
75
76// nx_safety_envelope:
77// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
78// sil_target: SIL1
79// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
80// verdict: NOT_YET_EVALUATED
81
82import "nx_syscalls.nx"
83import "nx_tier.nx"
84const NX_MAGIC_23170: i64 = 23170
85const NX_MAGIC_4096: i64 = 4096
86const NX_MAGIC_8192: i64 = 8192
87const NX_MAGIC_46341: i64 = 46341
88const NX_MAGIC_12288: i64 = 12288
89const NX_MAGIC_16384: i64 = 16384
90const NX_MAGIC_25976: i64 = 25976
91const NX_MAGIC_32768: i64 = 32768
92const NX_MAGIC_38048: i64 = 38048
93const NX_MAGIC_42361: i64 = 42361
94const NX_MAGIC_46006: i64 = 46006
95const NX_MAGIC_49152: i64 = 49152
96const NX_MAGIC_51916: i64 = 51916
97const NX_MAGIC_54432: i64 = 54432
98const NX_MAGIC_56619: i64 = 56619
99const NX_MAGIC_58744: i64 = 58744
100const NX_MAGIC_60686: i64 = 60686
101const NX_MAGIC_62390: i64 = 62390
102const NX_MAGIC_63984: i64 = 63984
103const NX_MAGIC_65536: i64 = 65536
104const NX_MAGIC_9000: i64 = 9000
105const NX_MAGIC_12000: i64 = 12000
106const NX_MAGIC_8000: i64 = 8000
107const NX_MAGIC_14000: i64 = 14000
108const NX_MAGIC_6553: i64 = 6553
109
110// ===== Q14 ==========================================================
111const NX_WQG_Q: nx_int = 16384
112
113// ===== Output-buffer offsets =======================================
114const NX_WQG_OUT_STRIDE: nx_int = 12
115const NX_WQG_OFF_GRADE: nx_int = 0
116const NX_WQG_OFF_DIVERSITY: nx_int = 1
117const NX_WQG_OFF_LOCAL_VAR: nx_int = 2
118const NX_WQG_OFF_EXTREMES: nx_int = 3
119const NX_WQG_OFF_FLATNESS_PENALTY: nx_int = 4
120const NX_WQG_OFF_FRACTAL_DIM: nx_int = 5
121const NX_WQG_OFF_BIOME_COHERENCE: nx_int = 6
122const NX_WQG_OFF_FEATURE_VARIETY: nx_int = 7
123const NX_WQG_OFF_READABILITY: nx_int = 8
124const NX_WQG_OFF_REFINE_AXIS: nx_int = 9
125const NX_WQG_OFF_MIN_HEIGHT: nx_int = 10
126const NX_WQG_OFF_MAX_HEIGHT: nx_int = 11
127
128// ===== Grade sealed enum ===========================================
129const NX_GRADE_F: nx_int = 0
130const NX_GRADE_D: nx_int = 1
131const NX_GRADE_C: nx_int = 2
132const NX_GRADE_B: nx_int = 3
133const NX_GRADE_A: nx_int = 4
134const NX_GRADE_S: nx_int = 5
135const NX_GRADE_COUNT: nx_int = 6
136
137// ===== Refine-axis sealed enum =====================================
138const NX_WQG_REFINE_NONE: nx_int = 0
139const NX_WQG_REFINE_MORE_RELIEF: nx_int = 1
140const NX_WQG_REFINE_MORE_FEATURES: nx_int = 2
141const NX_WQG_REFINE_LESS_FLATNESS: nx_int = 3
142const NX_WQG_REFINE_ADD_DETAIL: nx_int = 4
143const NX_WQG_REFINE_SMOOTH_NOISE: nx_int = 5
144const NX_WQG_REFINE_FIX_FRACTAL: nx_int = 6 // fractal dim outside aesthetic band
145const NX_WQG_REFINE_FIX_BIOMES: nx_int = 7 // biome map doesn't match elevation
146const NX_WQG_REFINE_MORE_VARIETY: nx_int = 8 // feature kind histogram too narrow
147const NX_WQG_REFINE_IMPROVE_READ: nx_int = 9 // readability low
148const NX_WQG_REFINE_COUNT: nx_int = 10
149
150// ===== Histogram resolution ========================================
151const NX_WQG_HIST_BUCKETS: nx_int = 16
152
153// ===== Score thresholds ============================================
154const NX_WQG_AXIS_WIN_FLOOR: nx_int = 9830 // 0.6Q
155const NX_WQG_AXIS_MARGINAL_FLOOR: nx_int = 6553 // 0.4Q
156const NX_WQG_LOCAL_VAR_UPPER: nx_int = 13107 // 0.8Q
157const NX_WQG_FLATNESS_OK_CEIL: nx_int = 6553 // 0.4Q
158const NX_WQG_FLATNESS_BAD_CEIL: nx_int = 9830 // 0.6Q
159// Fractal-dim aesthetic band (Spehar 2003): peak score at H ~ 0.5,
160// MARGINAL outside [0.3, 0.7]. Scores are normalised so 0.5
161// -> Q (peak), and decay parabolically. WIN threshold same 0.6Q.
162
163// ===== Validity predicates ==========================================
164func nx_grade_is_valid(g: nx_int) -> nx_int {
165 if g >= NX_GRADE_F { if g <= NX_GRADE_S { return 1 } }
166 return 0
167}
168
169func nx_wqg_refine_is_valid(r: nx_int) -> nx_int {
170 if r >= NX_WQG_REFINE_NONE { if r < NX_WQG_REFINE_COUNT { return 1 } }
171 return 0
172}
173
174// ===== Verdict primitives ==========================================
175func _wqg_axis_verdict(score: nx_int, floor_win: nx_int, floor_marg: nx_int) -> nx_int {
176 if score >= floor_win { return 1 }
177 if score >= floor_marg { return 0 }
178 return 0 - 1
179}
180
181func _wqg_axis_verdict_banded(
182 score: nx_int,
183 floor_win: nx_int,
184 floor_marg: nx_int,
185 upper_marg: nx_int
186) -> nx_int {
187 if score >= floor_win {
188 if score <= upper_marg { return 1 }
189 return 0
190 }
191 if score >= floor_marg { return 0 }
192 return 0 - 1
193}
194
195// ===== Grade-letter helper (8 axes) ================================
196// Mirrors nx_quality_grade.nx S-class rubric. Symmetric voting:
197// 8 WIN -> S
198// 7 WIN -> A (regardless of losses among the 1 non-WIN; loss caps at A)
199// 6 WIN -> B if losses <= 1, else C
200// 5 WIN -> B if losses == 0, else C
201// 4 WIN -> C if losses <= 1, else D
202// 3 WIN -> D
203// losses >= 4 -> F
204// else -> C
205func _wqg_grade_from_8(
206 v0: nx_int, v1: nx_int, v2: nx_int, v3: nx_int,
207 v4: nx_int, v5: nx_int, v6: nx_int, v7: nx_int
208) -> nx_int {
209 var wins: nx_int = 0
210 var losses: nx_int = 0
211
212 if v0 == 1 { wins = wins + 1 }
213 if v0 == 0 - 1 { losses = losses + 1 }
214 if v1 == 1 { wins = wins + 1 }
215 if v1 == 0 - 1 { losses = losses + 1 }
216 if v2 == 1 { wins = wins + 1 }
217 if v2 == 0 - 1 { losses = losses + 1 }
218 if v3 == 1 { wins = wins + 1 }
219 if v3 == 0 - 1 { losses = losses + 1 }
220 if v4 == 1 { wins = wins + 1 }
221 if v4 == 0 - 1 { losses = losses + 1 }
222 if v5 == 1 { wins = wins + 1 }
223 if v5 == 0 - 1 { losses = losses + 1 }
224 if v6 == 1 { wins = wins + 1 }
225 if v6 == 0 - 1 { losses = losses + 1 }
226 if v7 == 1 { wins = wins + 1 }
227 if v7 == 0 - 1 { losses = losses + 1 }
228
229 if losses >= 4 { return NX_GRADE_F }
230 if wins == 8 { return NX_GRADE_S }
231 if wins == 7 { return NX_GRADE_A }
232 if wins == 6 {
233 if losses <= 1 { return NX_GRADE_B }
234 return NX_GRADE_C
235 }
236 if wins == 5 {
237 if losses == 0 { return NX_GRADE_B }
238 return NX_GRADE_C
239 }
240 if wins == 4 {
241 if losses <= 1 { return NX_GRADE_C }
242 return NX_GRADE_D
243 }
244 if wins == 3 { return NX_GRADE_D }
245 return NX_GRADE_C
246}
247
248// ===== Refine-axis picker ==========================================
249// Picks the weakest axis as a refine directive. Priority: missing-
250// relief > extremes > local-var > flatness > fractal > biome > variety > readability.
251func _wqg_pick_refine_axis(
252 grade: nx_int,
253 diversity: nx_int,
254 local_var: nx_int,
255 extremes: nx_int,
256 flatness: nx_int,
257 fractal: nx_int,
258 biome: nx_int,
259 variety: nx_int,
260 readability: nx_int,
261 biome_provided: nx_int,
262 variety_provided: nx_int
263) -> nx_int {
264 if grade == NX_GRADE_S { return NX_WQG_REFINE_NONE }
265
266 if diversity < NX_WQG_AXIS_MARGINAL_FLOOR { return NX_WQG_REFINE_MORE_RELIEF }
267 if extremes < NX_WQG_AXIS_MARGINAL_FLOOR { return NX_WQG_REFINE_MORE_FEATURES }
268 if local_var < NX_WQG_AXIS_MARGINAL_FLOOR { return NX_WQG_REFINE_ADD_DETAIL }
269 if local_var > NX_WQG_LOCAL_VAR_UPPER { return NX_WQG_REFINE_SMOOTH_NOISE }
270 if flatness > NX_WQG_FLATNESS_BAD_CEIL { return NX_WQG_REFINE_LESS_FLATNESS }
271 if fractal < NX_WQG_AXIS_MARGINAL_FLOOR { return NX_WQG_REFINE_FIX_FRACTAL }
272 if biome_provided == 1 {
273 if biome < NX_WQG_AXIS_MARGINAL_FLOOR { return NX_WQG_REFINE_FIX_BIOMES }
274 }
275 if variety_provided == 1 {
276 if variety < NX_WQG_AXIS_MARGINAL_FLOOR { return NX_WQG_REFINE_MORE_VARIETY }
277 }
278 if readability < NX_WQG_AXIS_MARGINAL_FLOOR { return NX_WQG_REFINE_IMPROVE_READ }
279
280 // Marginal-but-not-failing -- weakest axis.
281 if diversity < NX_WQG_AXIS_WIN_FLOOR { return NX_WQG_REFINE_MORE_RELIEF }
282 if extremes < NX_WQG_AXIS_WIN_FLOOR { return NX_WQG_REFINE_MORE_FEATURES }
283 if fractal < NX_WQG_AXIS_WIN_FLOOR { return NX_WQG_REFINE_FIX_FRACTAL }
284 return NX_WQG_REFINE_NONE
285}
286
287// ===== Fractal-dim Hurst-exponent estimator =========================
288// Multi-scale mean-abs-diff slope. At scale s in [1, 2, 4]:
289// D(s) = mean |h(x+s,y) - h(x,y)|
290// For fractional Brownian surface, D(s) ~ s^H where H is the Hurst
291// exponent. We estimate H = log(D(4)/D(1)) / log(4). No log table:
292// using integer ratio with explicit comparison bands.
293//
294// Spehar 2003 aesthetic peak: H ~ 0.5 (most pleasing).
295// Returns a score in [0, Q] that peaks at H = 0.5 and decays
296// parabolically on either side. H outside [0.0, 1.0] -> 0.
297//
298// Formula: score = Q * (1 - 4 * (H - 0.5)^2) clamped to [0, Q].
299// So H = 0.5 -> Q; H = 0.25 -> Q * (1 - 0.25) = 0.75Q;
300// H = 0.0 -> 0; H = 1.0 -> 0.
301func _wqg_fractal_dim_score(
302 heightmap: *i64, width: nx_int, height: nx_int
303) -> nx_int {
304 // Need at least 5x5 to sample scale=4.
305 if width < 5 { return 0 }
306 if height < 5 { return 0 }
307 let q: nx_int = NX_WQG_Q
308
309 var sum1: nx_int = 0
310 var n1: nx_int = 0
311 var sum4: nx_int = 0
312 var n4: nx_int = 0
313
314 var y: nx_int = 0
315 while y < height {
316 var x: nx_int = 0
317 while x < width {
318 let idx: nx_int = y * width + x
319 if x + 1 < width {
320 let d1: nx_int = heightmap[idx + 1] - heightmap[idx]
321 var a1: nx_int = d1
322 if a1 < 0 { a1 = 0 - a1 }
323 sum1 = sum1 + a1
324 n1 = n1 + 1
325 }
326 if x + 4 < width {
327 let d4: nx_int = heightmap[idx + 4] - heightmap[idx]
328 var a4: nx_int = d4
329 if a4 < 0 { a4 = 0 - a4 }
330 sum4 = sum4 + a4
331 n4 = n4 + 1
332 }
333 x = x + 1
334 }
335 y = y + 1
336 }
337 if n1 == 0 { return 0 }
338 if n4 == 0 { return 0 }
339 let mean1: nx_int = sum1 / n1
340 let mean4: nx_int = sum4 / n4
341 if mean1 == 0 { return 0 }
342 // ratio = mean4 / mean1 in Q14.
343 let ratio_q14: nx_int = (mean4 * q) / mean1
344 // H = log4(ratio). Approximate via piecewise bands:
345 // ratio == 1 (Q) -> H = 0 (very rough surface)
346 // ratio == 2 (2Q) -> H = 0.5 (peak)
347 // ratio == 4 (4Q) -> H = 1.0 (smooth)
348 // ratio == sqrt(2) (1.41Q ~ 23170) -> H = 0.25
349 // ratio == sqrt(8) (2.83Q ~ 46341) -> H = 0.75
350 //
351 // Linear interp in log space via these anchor points; clamp.
352 var h_q14: nx_int = 0
353 if ratio_q14 <= q { h_q14 = 0 }
354 if ratio_q14 > q {
355 if ratio_q14 <= NX_MAGIC_23170 {
356 // H in [0, 0.25] = [0, 4096 Q14]; linear in this band.
357 h_q14 = ((ratio_q14 - q) * NX_MAGIC_4096) / (NX_MAGIC_23170 - q)
358 }
359 }
360 if ratio_q14 > NX_MAGIC_23170 {
361 if ratio_q14 <= q * 2 {
362 // H in [0.25, 0.5] = [4096, 8192]
363 h_q14 = NX_MAGIC_4096 + ((ratio_q14 - NX_MAGIC_23170) * (NX_MAGIC_8192 - NX_MAGIC_4096)) / (q * 2 - NX_MAGIC_23170)
364 }
365 }
366 if ratio_q14 > q * 2 {
367 if ratio_q14 <= NX_MAGIC_46341 {
368 // H in [0.5, 0.75] = [8192, 12288]
369 h_q14 = NX_MAGIC_8192 + ((ratio_q14 - q * 2) * (NX_MAGIC_12288 - NX_MAGIC_8192)) / (NX_MAGIC_46341 - q * 2)
370 }
371 }
372 if ratio_q14 > NX_MAGIC_46341 {
373 if ratio_q14 <= q * 4 {
374 // H in [0.75, 1.0] = [12288, 16384]
375 h_q14 = NX_MAGIC_12288 + ((ratio_q14 - NX_MAGIC_46341) * (NX_MAGIC_16384 - NX_MAGIC_12288)) / (q * 4 - NX_MAGIC_46341)
376 }
377 }
378 if ratio_q14 > q * 4 { h_q14 = q }
379 if h_q14 < 0 { h_q14 = 0 }
380 if h_q14 > q { h_q14 = q }
381
382 // score = q * (1 - 4 * (H - 0.5)^2)
383 let dh: nx_int = h_q14 - (q / 2)
384 let dh_sq: nx_int = (dh * dh) / q
385 var penalty: nx_int = 4 * dh_sq
386 if penalty > q { penalty = q }
387 return q - penalty
388}
389
390// ===== Biome-coherence score ========================================
391// biome_map: parallel to heightmap, same dimensions. Each cell holds a
392// biome ID (0..n_biome_kinds-1). We classify each cell's elevation
393// into one of 4 bands (low/mid/hi/peak) and check the biome ID's
394// "expected band" matches. Expected bands are encoded in a lookup:
395// biome 8 (DESERT) -> LOW
396// biome 0 (TUNDRA) -> LOW
397// biome 1 (BOREAL_FOREST) -> MID
398// biome 5 (TEMPERATE_FOREST) -> MID
399// biome 11 (TROPICAL_RAINFOREST) -> MID
400// biome 4 (GRASSLAND) -> MID
401// biome 12 (SNOW) -> HIGH
402// biome 13 (ICE) -> PEAK
403// Any unknown biome -> any-band-counts-as-match.
404//
405// Score = fraction of cells whose biome's expected band matches the
406// elevation band they're in.
407func _wqg_biome_expected_band(biome: nx_int) -> nx_int {
408 // 0 = LOW, 1 = MID, 2 = HIGH, 3 = PEAK, -1 = ANY
409 if biome == 8 { return 0 }
410 if biome == 0 { return 0 }
411 if biome == 1 { return 1 }
412 if biome == 5 { return 1 }
413 if biome == 11 { return 1 }
414 if biome == 4 { return 1 }
415 if biome == 12 { return 2 }
416 if biome == 13 { return 3 }
417 return 0 - 1
418}
419
420func _wqg_biome_coherence_score(
421 heightmap: *i64, biome_map: *i64,
422 width: nx_int, height: nx_int,
423 hmin: nx_int, hmax: nx_int
424) -> nx_int {
425 let q: nx_int = NX_WQG_Q
426 let range: nx_int = hmax - hmin
427 if range <= 0 { return 0 }
428 let n: nx_int = width * height
429 let low_max: nx_int = hmin + range / 4
430 let mid_max: nx_int = hmin + (range * 2) / 4
431 let hi_max: nx_int = hmin + (range * 3) / 4
432
433 var n_match: nx_int = 0
434 var i: nx_int = 0
435 while i < n {
436 let v: nx_int = heightmap[i]
437 let b: nx_int = biome_map[i]
438 var band: nx_int = 0
439 if v > low_max { band = 1 }
440 if v > mid_max { band = 2 }
441 if v > hi_max { band = 3 }
442 let exp: nx_int = _wqg_biome_expected_band(b)
443 if exp == 0 - 1 { n_match = n_match + 1 }
444 if exp == band { n_match = n_match + 1 }
445 i = i + 1
446 }
447 // Each cell that matches contributes once; cap at q.
448 return (n_match * q) / n
449}
450
451// ===== Feature-variety (Shannon entropy of kind histogram) =========
452// feature_hist[k] = count of features of kind k. n_kinds = histogram
453// length. We compute normalised entropy:
454// H = -sum( p_k * log2(p_k) ) where p_k = count_k / total
455// normalised = H / log2(n_kinds) in [0, 1]
456// All-one-kind -> H = 0; uniform distribution -> H = log2(n_kinds).
457//
458// Approximation in Q14: use 16-bin log2 lookup. Skip kinds with 0
459// count. Returns score in [0, Q].
460func _wqg_log2_q14_table(p_bin: nx_int) -> nx_int {
461 // p_bin in [1, 16], returns log2(p_bin) in Q14.
462 if p_bin <= 1 { return 0 }
463 if p_bin == 2 { return NX_MAGIC_16384 } // 1.0
464 if p_bin == 3 { return NX_MAGIC_25976 } // 1.585
465 if p_bin == 4 { return NX_MAGIC_32768 } // 2.0
466 if p_bin == 5 { return NX_MAGIC_38048 } // 2.322
467 if p_bin == 6 { return NX_MAGIC_42361 } // 2.585
468 if p_bin == 7 { return NX_MAGIC_46006 } // 2.807
469 if p_bin == 8 { return NX_MAGIC_49152 } // 3.0
470 if p_bin == 9 { return NX_MAGIC_51916 } // 3.170
471 if p_bin == 10 { return NX_MAGIC_54432 } // 3.322
472 if p_bin == 11 { return NX_MAGIC_56619 } // 3.456
473 if p_bin == 12 { return NX_MAGIC_58744 } // 3.585
474 if p_bin == 13 { return NX_MAGIC_60686 } // 3.700
475 if p_bin == 14 { return NX_MAGIC_62390 } // 3.807
476 if p_bin == 15 { return NX_MAGIC_63984 } // 3.907
477 return NX_MAGIC_65536 // log2(16) = 4.0
478}
479
480func _wqg_feature_variety_score(
481 feature_hist: *i64, n_kinds: nx_int
482) -> nx_int {
483 let q: nx_int = NX_WQG_Q
484 if n_kinds <= 1 { return 0 }
485 var total: nx_int = 0
486 var i: nx_int = 0
487 while i < n_kinds {
488 total = total + feature_hist[i]
489 i = i + 1
490 }
491 if total == 0 { return 0 }
492 // Entropy in Q14: H = sum( p_k_q14 * log2(1/p_k) ).
493 // Quantise p_k to 1..16 bins for table lookup.
494 var ent_q14: nx_int = 0
495 var k: nx_int = 0
496 while k < n_kinds {
497 let c: nx_int = feature_hist[k]
498 if c > 0 {
499 // p_k = c / total. bin = round(total / c) clamped [1, 16].
500 var bin: nx_int = total / c
501 if bin < 1 { bin = 1 }
502 if bin > 16 { bin = 16 }
503 let log_bin_q14: nx_int = _wqg_log2_q14_table(bin)
504 // contrib_q14 = p_k_q14 * log2(1/p_k) = (c/total) * log_bin
505 let contrib: nx_int = (c * log_bin_q14) / total
506 ent_q14 = ent_q14 + contrib
507 }
508 k = k + 1
509 }
510 // Normalise by log2(n_kinds). Clamp n_kinds bin lookup to 16.
511 var nb: nx_int = n_kinds
512 if nb > 16 { nb = 16 }
513 let max_ent: nx_int = _wqg_log2_q14_table(nb)
514 if max_ent <= 0 { return 0 }
515 let norm: nx_int = (ent_q14 * q) / max_ent
516 if norm > q { return q }
517 if norm < 0 { return 0 }
518 return norm
519}
520
521// ===== Readability ==================================================
522// Fraction of cells whose 3x3 local stddev (approximated as max-min
523// in the 3x3 neighborhood) is in the legible band [0.05, 0.25] of
524// max_relief. Too smooth -> boring. Too noisy -> illegible.
525//
526// We use range (max-min) over the 3x3 neighborhood as a stddev
527// proxy (avoids squaring + sqrt for Q14 budget). Stddev ~ range / 4
528// is a well-known approximation for moderate sample sizes.
529func _wqg_readability_score(
530 heightmap: *i64, width: nx_int, height: nx_int,
531 max_relief: nx_int
532) -> nx_int {
533 let q: nx_int = NX_WQG_Q
534 if width < 3 { return 0 }
535 if height < 3 { return 0 }
536 if max_relief <= 0 { return 0 }
537 let lo: nx_int = (max_relief * 819) / q // 0.05
538 let hi: nx_int = (max_relief * NX_MAGIC_4096) / q // 0.25
539
540 var n_legible: nx_int = 0
541 var n_inner: nx_int = 0
542 var y: nx_int = 1
543 while y < height - 1 {
544 var x: nx_int = 1
545 while x < width - 1 {
546 let c: nx_int = y * width + x
547 var lmin: nx_int = heightmap[c]
548 var lmax: nx_int = heightmap[c]
549 var dy: nx_int = 0 - 1
550 while dy <= 1 {
551 var dx: nx_int = 0 - 1
552 while dx <= 1 {
553 let v: nx_int = heightmap[(y + dy) * width + (x + dx)]
554 if v < lmin { lmin = v }
555 if v > lmax { lmax = v }
556 dx = dx + 1
557 }
558 dy = dy + 1
559 }
560 let rng: nx_int = lmax - lmin
561 if rng >= lo {
562 if rng <= hi {
563 n_legible = n_legible + 1
564 }
565 }
566 n_inner = n_inner + 1
567 x = x + 1
568 }
569 y = y + 1
570 }
571 if n_inner == 0 { return 0 }
572 return (n_legible * q) / n_inner
573}
574
575// ===== Main grader (8 axes) =========================================
576// heightmap: w*h flat i64 array, row-major.
577// width, height: grid dimensions.
578// max_expected_relief: caller's expected maximum relief.
579// biome_map: parallel i64 array of biome IDs (0 = skip).
580// feature_hist: i64 array of per-kind counts (0 = skip).
581// n_feature_kinds: length of feature_hist.
582// out_verdict: 12 i64s receiving the verdict.
583func nx_world_quality_grade(
584 heightmap: *i64,
585 width: nx_int,
586 height: nx_int,
587 max_expected_relief: nx_int,
588 biome_map: *i64,
589 feature_hist: *i64,
590 n_feature_kinds: nx_int,
591 out_verdict: *i64
592) {
593 let q: nx_int = NX_WQG_Q
594 let n: nx_int = width * height
595
596 // Init output.
597 var k: nx_int = 0
598 while k < NX_WQG_OUT_STRIDE { out_verdict[k] = 0; k = k + 1 }
599 out_verdict[NX_WQG_OFF_GRADE] = NX_GRADE_F
600 out_verdict[NX_WQG_OFF_REFINE_AXIS] = NX_WQG_REFINE_MORE_RELIEF
601
602 if n <= 0 { return }
603 if max_expected_relief <= 0 { return }
604
605 // Pass 1: min / max.
606 var hmin: nx_int = heightmap[0]
607 var hmax: nx_int = heightmap[0]
608 var i: nx_int = 0
609 while i < n {
610 let v: nx_int = heightmap[i]
611 if v < hmin { hmin = v }
612 if v > hmax { hmax = v }
613 i = i + 1
614 }
615 let range: nx_int = hmax - hmin
616 out_verdict[NX_WQG_OFF_MIN_HEIGHT] = hmin
617 out_verdict[NX_WQG_OFF_MAX_HEIGHT] = hmax
618
619 // DIVERSITY.
620 var diversity: nx_int = (range * q) / max_expected_relief
621 if diversity > q { diversity = q }
622 if diversity < 0 { diversity = 0 }
623 out_verdict[NX_WQG_OFF_DIVERSITY] = diversity
624
625 // Pass 2: neighbour-diff + histogram.
626 let hist: *i64 = (sys_mmap(NX_WQG_HIST_BUCKETS * NX_SIZEOF_NX_INT)) as *i64
627 var b: nx_int = 0
628 while b < NX_WQG_HIST_BUCKETS { hist[b] = 0; b = b + 1 }
629
630 var sum_abs_diff: nx_int = 0
631 var n_diff: nx_int = 0
632 var hi: nx_int = 0
633 while hi < n {
634 if range > 0 {
635 var bb: nx_int = ((heightmap[hi] - hmin) * NX_WQG_HIST_BUCKETS) / (range + 1)
636 if bb < 0 { bb = 0 }
637 if bb >= NX_WQG_HIST_BUCKETS { bb = NX_WQG_HIST_BUCKETS - 1 }
638 hist[bb] = hist[bb] + 1
639 }
640 let xi: nx_int = hi % width
641 let yi: nx_int = hi / width
642 if xi + 1 < width {
643 let dr: nx_int = heightmap[hi + 1] - heightmap[hi]
644 var adr: nx_int = dr
645 if adr < 0 { adr = 0 - adr }
646 sum_abs_diff = sum_abs_diff + adr
647 n_diff = n_diff + 1
648 }
649 if yi + 1 < height {
650 let dd: nx_int = heightmap[hi + width] - heightmap[hi]
651 var add_: nx_int = dd
652 if add_ < 0 { add_ = 0 - add_ }
653 sum_abs_diff = sum_abs_diff + add_
654 n_diff = n_diff + 1
655 }
656 hi = hi + 1
657 }
658
659 // LOCAL_VARIATION.
660 var local_var: nx_int = 0
661 if n_diff > 0 {
662 let mean_abs_diff: nx_int = sum_abs_diff / n_diff
663 local_var = (mean_abs_diff * 4 * q) / max_expected_relief
664 if local_var > q { local_var = q }
665 if local_var < 0 { local_var = 0 }
666 }
667 out_verdict[NX_WQG_OFF_LOCAL_VAR] = local_var
668
669 // FLATNESS.
670 var max_bucket: nx_int = 0
671 var bi: nx_int = 0
672 while bi < NX_WQG_HIST_BUCKETS {
673 if hist[bi] > max_bucket { max_bucket = hist[bi] }
674 bi = bi + 1
675 }
676 let flatness: nx_int = (max_bucket * q) / n
677 out_verdict[NX_WQG_OFF_FLATNESS_PENALTY] = flatness
678
679 // EXTREMES.
680 let top_t: nx_int = hmin + (range * 9) / 10
681 let bot_t: nx_int = hmin + range / 10
682 var n_extreme: nx_int = 0
683 var ei: nx_int = 0
684 while ei < n {
685 let v: nx_int = heightmap[ei]
686 if v >= top_t { n_extreme = n_extreme + 1 }
687 if v <= bot_t { n_extreme = n_extreme + 1 }
688 ei = ei + 1
689 }
690 var extremes: nx_int = (n_extreme * 5 * q) / n
691 if extremes > q { extremes = q }
692 out_verdict[NX_WQG_OFF_EXTREMES] = extremes
693
694 // FRACTAL_DIM.
695 let fractal: nx_int = _wqg_fractal_dim_score(heightmap, width, height)
696 out_verdict[NX_WQG_OFF_FRACTAL_DIM] = fractal
697
698 // BIOME_COHERENCE.
699 var biome_score: nx_int = 0
700 var biome_provided: nx_int = 0
701 if (biome_map as i64) != 0 {
702 biome_provided = 1
703 biome_score = _wqg_biome_coherence_score(heightmap, biome_map, width, height, hmin, hmax)
704 }
705 out_verdict[NX_WQG_OFF_BIOME_COHERENCE] = biome_score
706
707 // FEATURE_VARIETY.
708 var variety_score: nx_int = 0
709 var variety_provided: nx_int = 0
710 if (feature_hist as i64) != 0 {
711 if n_feature_kinds > 0 {
712 variety_provided = 1
713 variety_score = _wqg_feature_variety_score(feature_hist, n_feature_kinds)
714 }
715 }
716 out_verdict[NX_WQG_OFF_FEATURE_VARIETY] = variety_score
717
718 // READABILITY.
719 let readability: nx_int = _wqg_readability_score(heightmap, width, height, max_expected_relief)
720 out_verdict[NX_WQG_OFF_READABILITY] = readability
721
722 // Per-axis verdicts.
723 let v_div: nx_int = _wqg_axis_verdict(diversity, NX_WQG_AXIS_WIN_FLOOR, NX_WQG_AXIS_MARGINAL_FLOOR)
724 let v_loc: nx_int = _wqg_axis_verdict_banded(local_var, NX_WQG_AXIS_WIN_FLOOR, NX_WQG_AXIS_MARGINAL_FLOOR, NX_WQG_LOCAL_VAR_UPPER)
725 let v_ext: nx_int = _wqg_axis_verdict(extremes, NX_WQG_AXIS_WIN_FLOOR, NX_WQG_AXIS_MARGINAL_FLOOR)
726 var v_flat: nx_int = 0 - 1
727 if flatness <= NX_WQG_FLATNESS_OK_CEIL { v_flat = 1 }
728 if flatness > NX_WQG_FLATNESS_OK_CEIL {
729 if flatness <= NX_WQG_FLATNESS_BAD_CEIL { v_flat = 0 }
730 }
731 let v_frac: nx_int = _wqg_axis_verdict(fractal, NX_WQG_AXIS_WIN_FLOOR, NX_WQG_AXIS_MARGINAL_FLOOR)
732
733 // Optional axes -- MARGINAL when not provided.
734 var v_bio: nx_int = 0
735 if biome_provided == 1 {
736 v_bio = _wqg_axis_verdict(biome_score, NX_WQG_AXIS_WIN_FLOOR, NX_WQG_AXIS_MARGINAL_FLOOR)
737 }
738 var v_var: nx_int = 0
739 if variety_provided == 1 {
740 v_var = _wqg_axis_verdict(variety_score, NX_WQG_AXIS_WIN_FLOOR, NX_WQG_AXIS_MARGINAL_FLOOR)
741 }
742 let v_read: nx_int = _wqg_axis_verdict(readability, NX_WQG_AXIS_WIN_FLOOR, NX_WQG_AXIS_MARGINAL_FLOOR)
743
744 let grade: nx_int = _wqg_grade_from_8(v_div, v_loc, v_ext, v_flat, v_frac, v_bio, v_var, v_read)
745 out_verdict[NX_WQG_OFF_GRADE] = grade
746 out_verdict[NX_WQG_OFF_REFINE_AXIS] = _wqg_pick_refine_axis(
747 grade, diversity, local_var, extremes, flatness,
748 fractal, biome_score, variety_score, readability,
749 biome_provided, variety_provided
750 )
751}
752
753// ===== Self-test ====================================================
754func main() -> i64 {
755 let q: nx_int = NX_WQG_Q
756 let v: *i64 = (sys_mmap(NX_WQG_OUT_STRIDE * NX_SIZEOF_NX_INT)) as *i64
757 let null_ptr: *i64 = 0 as *i64
758
759 // T1: Validity predicates.
760 if nx_grade_is_valid(NX_GRADE_F) != 1 { return __syscall(93, 1, 0, 0, 0, 0, 0) }
761 if nx_grade_is_valid(NX_GRADE_S) != 1 { return __syscall(93, 2, 0, 0, 0, 0, 0) }
762 if nx_grade_is_valid(99) != 0 { return __syscall(93, 3, 0, 0, 0, 0, 0) }
763 if nx_wqg_refine_is_valid(NX_WQG_REFINE_NONE) != 1 { return __syscall(93, 4, 0, 0, 0, 0, 0) }
764 if nx_wqg_refine_is_valid(NX_WQG_REFINE_IMPROVE_READ) != 1 { return __syscall(93, 5, 0, 0, 0, 0, 0) }
765 if nx_wqg_refine_is_valid(99) != 0 { return __syscall(93, 6, 0, 0, 0, 0, 0) }
766
767 // T2: Constant heightmap -> F (no diversity).
768 let w: nx_int = 8
769 let h: nx_int = 8
770 let n: nx_int = w * h
771 let map_flat: *i64 = (sys_mmap(n * NX_SIZEOF_NX_INT)) as *i64
772 var i: nx_int = 0
773 while i < n { map_flat[i] = 100; i = i + 1 }
774 nx_world_quality_grade(map_flat, w, h, 1000, null_ptr, null_ptr, 0, v)
775 if v[NX_WQG_OFF_GRADE] != NX_GRADE_F { return __syscall(93, 10, 0, 0, 0, 0, 0) }
776 if v[NX_WQG_OFF_DIVERSITY] != 0 { return __syscall(93, 11, 0, 0, 0, 0, 0) }
777 if v[NX_WQG_OFF_REFINE_AXIS] != NX_WQG_REFINE_MORE_RELIEF { return __syscall(93, 12, 0, 0, 0, 0, 0) }
778
779 // T3: Linear ramp -- good diversity.
780 let map_ramp: *i64 = (sys_mmap(n * NX_SIZEOF_NX_INT)) as *i64
781 var j: nx_int = 0
782 while j < n {
783 map_ramp[j] = j * 1000 / n
784 j = j + 1
785 }
786 nx_world_quality_grade(map_ramp, w, h, 1000, null_ptr, null_ptr, 0, v)
787 if v[NX_WQG_OFF_DIVERSITY] < NX_MAGIC_9000 { return __syscall(93, 20, 0, 0, 0, 0, 0) }
788 if v[NX_WQG_OFF_MIN_HEIGHT] != 0 { return __syscall(93, 21, 0, 0, 0, 0, 0) }
789 if v[NX_WQG_OFF_MAX_HEIGHT] < 900 { return __syscall(93, 22, 0, 0, 0, 0, 0) }
790 if v[NX_WQG_OFF_GRADE] < NX_GRADE_D { return __syscall(93, 23, 0, 0, 0, 0, 0) }
791
792 // T4: 8x8 "mountain" map -- has extremes, varied.
793 let map_real: *i64 = (sys_mmap(n * NX_SIZEOF_NX_INT)) as *i64
794 var ry: nx_int = 0
795 while ry < h {
796 var rx: nx_int = 0
797 while rx < w {
798 let dx: nx_int = rx - 4
799 let dy: nx_int = ry - 4
800 let d2: nx_int = dx * dx + dy * dy
801 var h_val: nx_int = 1000 - d2 * 50
802 if h_val < 0 { h_val = 0 }
803 if (rx + ry) % 2 == 0 { h_val = h_val + 50 }
804 map_real[ry * w + rx] = h_val
805 rx = rx + 1
806 }
807 ry = ry + 1
808 }
809 nx_world_quality_grade(map_real, w, h, 1000, null_ptr, null_ptr, 0, v)
810 if v[NX_WQG_OFF_DIVERSITY] < NX_MAGIC_9000 { return __syscall(93, 30, 0, 0, 0, 0, 0) }
811 if v[NX_WQG_OFF_EXTREMES] == 0 { return __syscall(93, 31, 0, 0, 0, 0, 0) }
812 if v[NX_WQG_OFF_GRADE] < NX_GRADE_C { return __syscall(93, 32, 0, 0, 0, 0, 0) }
813
814 // T5: Refusal paths.
815 nx_world_quality_grade(map_flat, 0, h, 1000, null_ptr, null_ptr, 0, v)
816 if v[NX_WQG_OFF_GRADE] != NX_GRADE_F { return __syscall(93, 40, 0, 0, 0, 0, 0) }
817 nx_world_quality_grade(map_flat, w, h, 0, null_ptr, null_ptr, 0, v)
818 if v[NX_WQG_OFF_GRADE] != NX_GRADE_F { return __syscall(93, 41, 0, 0, 0, 0, 0) }
819
820 // T6: Grade-letter helper -- 8 wins -> S.
821 if _wqg_grade_from_8(1, 1, 1, 1, 1, 1, 1, 1) != NX_GRADE_S { return __syscall(93, 50, 0, 0, 0, 0, 0) }
822 // 7 wins -> A.
823 if _wqg_grade_from_8(1, 1, 1, 1, 1, 1, 1, 0) != NX_GRADE_A { return __syscall(93, 51, 0, 0, 0, 0, 0) }
824 // 6 wins, 0 losses -> B.
825 if _wqg_grade_from_8(1, 1, 1, 1, 1, 1, 0, 0) != NX_GRADE_B { return __syscall(93, 52, 0, 0, 0, 0, 0) }
826 // 4 losses -> F.
827 if _wqg_grade_from_8(0 - 1, 0 - 1, 0 - 1, 0 - 1, 1, 1, 1, 1) != NX_GRADE_F { return __syscall(93, 53, 0, 0, 0, 0, 0) }
828 // 3 wins, 2 losses, 3 marginal -> D.
829 if _wqg_grade_from_8(1, 1, 1, 0, 0, 0, 0 - 1, 0 - 1) != NX_GRADE_D { return __syscall(93, 54, 0, 0, 0, 0, 0) }
830
831 // T7: BIOME_COHERENCE -- map_real has hi peak at centre, low corners.
832 // Compute the band cutoffs the grader will use (quartiles of the
833 // observed range), then assign biomes that match those bands so
834 // BIOME_COHERENCE -> ~Q. Grader bands:
835 // v <= hmin + range/4 -> LOW
836 // v <= hmin + range*2/4 -> MID
837 // v <= hmin + range*3/4 -> HIGH
838 // else -> PEAK
839 let biome_map: *i64 = (sys_mmap(n * NX_SIZEOF_NX_INT)) as *i64
840 // map_real has hmin ~ 0 (some cells = 0), hmax ~ 1050 (centre + jitter).
841 // Re-scan to compute actual hmin/hmax for the test:
842 var th_min: nx_int = map_real[0]
843 var th_max: nx_int = map_real[0]
844 var th_i: nx_int = 0
845 while th_i < n {
846 let vv: nx_int = map_real[th_i]
847 if vv < th_min { th_min = vv }
848 if vv > th_max { th_max = vv }
849 th_i = th_i + 1
850 }
851 let th_range: nx_int = th_max - th_min
852 let band1_top: nx_int = th_min + th_range / 4
853 let band2_top: nx_int = th_min + (th_range * 2) / 4
854 let band3_top: nx_int = th_min + (th_range * 3) / 4
855 var bi2: nx_int = 0
856 while bi2 < n {
857 let hv: nx_int = map_real[bi2]
858 if hv <= band1_top { biome_map[bi2] = 8 } // DESERT (LOW)
859 if hv > band1_top {
860 if hv <= band2_top { biome_map[bi2] = 5 } // TEMPERATE_FOREST (MID)
861 }
862 if hv > band2_top {
863 if hv <= band3_top { biome_map[bi2] = 12 } // SNOW (HIGH)
864 }
865 if hv > band3_top { biome_map[bi2] = 13 } // ICE (PEAK)
866 bi2 = bi2 + 1
867 }
868 nx_world_quality_grade(map_real, w, h, 1000, biome_map, null_ptr, 0, v)
869 if v[NX_WQG_OFF_BIOME_COHERENCE] < NX_MAGIC_12000 { return __syscall(93, 60, 0, 0, 0, 0, 0) } // >= 0.73Q
870
871 // T8: BIOME_COHERENCE with WRONG biomes -> low score.
872 var bi3: nx_int = 0
873 while bi3 < n { biome_map[bi3] = 13; bi3 = bi3 + 1 } // all ICE everywhere
874 nx_world_quality_grade(map_real, w, h, 1000, biome_map, null_ptr, 0, v)
875 // ICE expects PEAK band only; most cells aren't there -> low score.
876 if v[NX_WQG_OFF_BIOME_COHERENCE] > NX_MAGIC_8000 { return __syscall(93, 70, 0, 0, 0, 0, 0) }
877
878 // T9: FEATURE_VARIETY -- uniform 4-kind distribution = max.
879 let hist4: *i64 = (sys_mmap(4 * NX_SIZEOF_NX_INT)) as *i64
880 hist4[0] = 10
881 hist4[1] = 10
882 hist4[2] = 10
883 hist4[3] = 10
884 nx_world_quality_grade(map_real, w, h, 1000, null_ptr, hist4, 4, v)
885 if v[NX_WQG_OFF_FEATURE_VARIETY] < NX_MAGIC_14000 { return __syscall(93, 80, 0, 0, 0, 0, 0) } // ~Q
886 // All-one-kind -> 0.
887 hist4[0] = 40
888 hist4[1] = 0
889 hist4[2] = 0
890 hist4[3] = 0
891 nx_world_quality_grade(map_real, w, h, 1000, null_ptr, hist4, 4, v)
892 if v[NX_WQG_OFF_FEATURE_VARIETY] != 0 { return __syscall(93, 81, 0, 0, 0, 0, 0) }
893
894 // T10: READABILITY non-zero on the mountain map (has structured
895 // local variation, not pure noise).
896 nx_world_quality_grade(map_real, w, h, 1000, null_ptr, null_ptr, 0, v)
897 if v[NX_WQG_OFF_READABILITY] <= 0 { return __syscall(93, 90, 0, 0, 0, 0, 0) }
898
899 // T11: FRACTAL_DIM ramp test -- pure ramp scales linearly, so
900 // mean4/mean1 ~ 4 -> H ~ 1.0 -> fractal score near 0 (too smooth).
901 nx_world_quality_grade(map_ramp, w, h, 1000, null_ptr, null_ptr, 0, v)
902 if v[NX_WQG_OFF_FRACTAL_DIM] > NX_MAGIC_6553 { return __syscall(93, 100, 0, 0, 0, 0, 0) } // < 0.4Q
903
904 return 0
905}