code wiki / (root) / nx_wow_moment_detector.nx

nx_wow_moment_detector.nx source

↩ module page · 404 lines · 14869 B

1// nx_wow_moment_detector.nx -- signature-feature awe-density grader. 2// 3// Per honest audit 2026-05-16: a world can be statistically diverse 4// but still bland if it has no MEMORABLE features. This grader 5// directly counts AWE MOMENTS -- the views that make a player stop 6// and gawk: monumental peaks, cliff edges over deep valleys, hidden 7// alcoves, dramatic vistas. A world with no awe moments is bland; 8// 3-8 per 10x10 km region is incredible. 9// 10// AXES (Q14 [0, Q]; higher = MORE wow): 11// 12// 0. SIGNATURE_PEAKS_PER_REGION: distinct local maxima above 13// 0.85 * max_relief, weighted by isolation (lonely peaks > clumps). 14// Target [3, 8] per region; saturates above. 15// 1. DRAMATIC_VALLEYS: cells below 0.10 * max_relief that have a 16// cell within 5m on the heightmap above 0.50 * max_relief 17// (canyon-edge proximity). 18// 2. ISOLATION_VARIANCE: stddev of nearest-neighbour distances among 19// signature features. Clumped features = boring; spread = wow. 20// 3. SCALE_DIVERSITY: ratio of largest to smallest signature feature 21// size. Worlds with only-huge or only-tiny features score low. 22// 4. RARITY: fraction of features with unique nearest-neighbour 23// bearing (no two adjacent features point the same way). 24// 25// EMITS LAYER_VERDICT (kind = NX_LAYER_KIND_READABILITY). 26// 27// genealogy_id: kaplan_1987_environmental_preference + 28// appleton_1996_landscape_aesthetics + awe_psych_canon 29// lineage_id: nx_wow_moment_detector_5axis_v1 30 31// nx_safety_envelope: 32// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 33// sil_target: SIL1 34// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 35// verdict: NOT_YET_EVALUATED 36 37import "nx_syscalls.nx" 38import "nx_tier.nx" 39import "nx_layer_verdict.nx" 40 41const NX_WM_Q: nx_int = 16384 42 43const NX_WM_AXIS_SIG_PEAKS: nx_int = 0 44const NX_WM_AXIS_DRAMATIC_VALLEYS: nx_int = 1 45const NX_WM_AXIS_ISOLATION_VAR: nx_int = 2 46const NX_WM_AXIS_SCALE_DIVERSITY: nx_int = 3 47const NX_WM_AXIS_RARITY: nx_int = 4 48const NX_WM_AXIS_COUNT: nx_int = 5 49 50func _wm_band_score(val: nx_int, lo_q: nx_int, hi_q: nx_int) -> nx_int { 51 let q: nx_int = NX_WM_Q 52 if val < 0 { return 0 } 53 if val < lo_q { 54 if lo_q > 0 { return (val * q) / lo_q } 55 return 0 56 } 57 if val <= hi_q { return q } 58 return q 59} 60 61// ===== Axis 0: signature peaks ===================================== 62// A signature peak is a cell whose value > 0.85 of (hmax) AND it's a 63// strict local maximum within a 3x3 neighborhood. Returns the count 64// scored against a target band [3, 12]. 65func _wm_signature_peaks_q14( 66 heightmap: *i64, w: nx_int, h: nx_int 67) -> nx_int { 68 let q: nx_int = NX_WM_Q 69 let n: nx_int = w * h 70 if n <= 0 { return 0 } 71 if w < 3 { return 0 } 72 if h < 3 { return 0 } 73 var hmax: nx_int = heightmap[0] 74 var hmin: nx_int = heightmap[0] 75 var i: nx_int = 0 76 while i < n { 77 let v: nx_int = heightmap[i] 78 if v > hmax { hmax = v } 79 if v < hmin { hmin = v } 80 i = i + 1 81 } 82 let range: nx_int = hmax - hmin 83 if range <= 0 { return 0 } 84 let threshold: nx_int = hmin + (range * 85) / 100 85 86 var n_peaks: nx_int = 0 87 var y: nx_int = 1 88 while y < h - 1 { 89 var x: nx_int = 1 90 while x < w - 1 { 91 let idx: nx_int = y * w + x 92 let v: nx_int = heightmap[idx] 93 if v >= threshold { 94 var is_peak: nx_int = 1 95 var dy: nx_int = 0 - 1 96 while dy <= 1 { 97 var dx: nx_int = 0 - 1 98 while dx <= 1 { 99 if dx != 0 { 100 if heightmap[(y + dy) * w + (x + dx)] > v { is_peak = 0 } 101 } 102 if dx == 0 { 103 if dy != 0 { 104 if heightmap[(y + dy) * w + (x + dx)] > v { is_peak = 0 } 105 } 106 } 107 dx = dx + 1 108 } 109 dy = dy + 1 110 } 111 if is_peak == 1 { n_peaks = n_peaks + 1 } 112 } 113 x = x + 1 114 } 115 y = y + 1 116 } 117 // Target band: 3-12 peaks. 118 var score: nx_int = 0 119 if n_peaks >= 3 { 120 if n_peaks <= 12 { score = q } 121 if n_peaks > 12 { score = q - (n_peaks - 12) * q / 12 } 122 } 123 if n_peaks < 3 { score = (n_peaks * q) / 3 } 124 if score < 0 { score = 0 } 125 if score > q { score = q } 126 return score 127} 128 129// ===== Axis 1: dramatic valleys ==================================== 130// Count cells whose value < 0.10 * range AND which have a neighbouring 131// cell within distance 5 (chebyshev) above 0.50 * range. 132func _wm_dramatic_valleys_q14( 133 heightmap: *i64, w: nx_int, h: nx_int 134) -> nx_int { 135 let q: nx_int = NX_WM_Q 136 let n: nx_int = w * h 137 if n <= 0 { return 0 } 138 var hmax: nx_int = heightmap[0] 139 var hmin: nx_int = heightmap[0] 140 var i: nx_int = 0 141 while i < n { 142 let v: nx_int = heightmap[i] 143 if v > hmax { hmax = v } 144 if v < hmin { hmin = v } 145 i = i + 1 146 } 147 let range: nx_int = hmax - hmin 148 if range <= 0 { return 0 } 149 let valley_t: nx_int = hmin + (range * 10) / 100 150 let high_t: nx_int = hmin + (range * 50) / 100 151 var n_dramatic: nx_int = 0 152 var y: nx_int = 0 153 while y < h { 154 var x: nx_int = 0 155 while x < w { 156 let v: nx_int = heightmap[y * w + x] 157 if v <= valley_t { 158 // Check 5x5 neighbourhood for a high cell. 159 var found_high: nx_int = 0 160 var dy: nx_int = 0 - 5 161 while dy <= 5 { 162 var dx: nx_int = 0 - 5 163 while dx <= 5 { 164 let nx: nx_int = x + dx 165 let ny: nx_int = y + dy 166 if nx >= 0 { if nx < w { 167 if ny >= 0 { if ny < h { 168 if heightmap[ny * w + nx] >= high_t { found_high = 1 } 169 } } 170 } } 171 dx = dx + 1 172 } 173 dy = dy + 1 174 } 175 if found_high == 1 { n_dramatic = n_dramatic + 1 } 176 } 177 x = x + 1 178 } 179 y = y + 1 180 } 181 // Target: 1-10% of cells. 182 let target_lo: nx_int = n / 100 183 let target_hi: nx_int = n / 10 184 var score: nx_int = 0 185 if n_dramatic >= target_lo { 186 if n_dramatic <= target_hi { score = q } 187 if n_dramatic > target_hi { 188 score = q - (n_dramatic - target_hi) * q / n 189 } 190 } 191 if n_dramatic < target_lo { 192 if target_lo > 0 { score = (n_dramatic * q) / target_lo } 193 } 194 if score < 0 { score = 0 } 195 if score > q { score = q } 196 return score 197} 198 199// ===== Axis 2: isolation variance ================================== 200// Caller passes a feature list (flat array of (x, y) pairs) for 201// signature features. Compute mean pairwise distance + stddev. 202// Higher stddev = more interesting distribution. Pass n=0 to skip. 203func _wm_isolation_var_q14( 204 features: *i64, n_features: nx_int 205) -> nx_int { 206 if (features as i64) == 0 { return NX_WM_Q / 2 } 207 if n_features < 3 { return 0 } 208 let q: nx_int = NX_WM_Q 209 var sum_d_sq: nx_int = 0 210 var min_d_sq: nx_int = 0 - 1 211 var max_d_sq: nx_int = 0 212 var count: nx_int = 0 213 var i: nx_int = 0 214 while i < n_features - 1 { 215 let dx: nx_int = features[(i + 1) * 2 ] - features[i * 2 ] 216 let dy: nx_int = features[(i + 1) * 2 + 1] - features[i * 2 + 1] 217 let d_sq: nx_int = dx * dx + dy * dy 218 sum_d_sq = sum_d_sq + d_sq 219 if d_sq > max_d_sq { max_d_sq = d_sq } 220 if min_d_sq < 0 { min_d_sq = d_sq } 221 if d_sq < min_d_sq { min_d_sq = d_sq } 222 count = count + 1 223 i = i + 1 224 } 225 if count == 0 { return 0 } 226 let mean_d_sq: nx_int = sum_d_sq / count 227 if mean_d_sq <= 0 { return 0 } 228 let range: nx_int = max_d_sq - min_d_sq 229 let cv_q: nx_int = (range * q) / mean_d_sq 230 // Target [0.5Q, 2Q] -- a healthy spread of distances. 231 if cv_q < q / 2 { return (cv_q * q * 2) / q } 232 if cv_q > q * 2 { return q - (cv_q - q * 2) / 2 } 233 return q 234} 235 236// ===== Axis 3: scale diversity ===================================== 237// Sizes here = caller-supplied feature radii. Returns Q14 of 238// max_size / min_size ratio (saturates at 8x). 239func _wm_scale_diversity_q14( 240 sizes: *i64, n_features: nx_int 241) -> nx_int { 242 if (sizes as i64) == 0 { return NX_WM_Q / 2 } 243 if n_features < 2 { return 0 } 244 let q: nx_int = NX_WM_Q 245 var smin: nx_int = sizes[0] 246 var smax: nx_int = sizes[0] 247 var i: nx_int = 0 248 while i < n_features { 249 let s: nx_int = sizes[i] 250 if s < smin { smin = s } 251 if s > smax { smax = s } 252 i = i + 1 253 } 254 if smin <= 0 { return 0 } 255 let ratio: nx_int = smax / smin 256 if ratio >= 8 { return q } 257 if ratio <= 1 { return 0 } 258 return ((ratio - 1) * q) / 7 259} 260 261// ===== Axis 4: rarity (bearing diversity) ========================== 262// Score = fraction of features whose nearest-neighbour bearing differs 263// from at least one other feature's nearest-neighbour bearing by > 30deg. 264// Simplified: compute (dy / dx) sign as a coarse bearing band; count 265// distinct signs. Skipped if no features supplied. 266func _wm_rarity_q14( 267 features: *i64, n_features: nx_int 268) -> nx_int { 269 if (features as i64) == 0 { return NX_WM_Q / 2 } 270 if n_features < 3 { return 0 } 271 let q: nx_int = NX_WM_Q 272 // 4 quadrant bins from each feature's bearing to next feature. 273 let bins: *i64 = (sys_mmap(4 * NX_SIZEOF_NX_INT)) as *i64 274 var b: nx_int = 0 275 while b < 4 { bins[b] = 0; b = b + 1 } 276 var i: nx_int = 0 277 while i < n_features - 1 { 278 let dx: nx_int = features[(i + 1) * 2 ] - features[i * 2 ] 279 let dy: nx_int = features[(i + 1) * 2 + 1] - features[i * 2 + 1] 280 var bin: nx_int = 0 281 if dx >= 0 { 282 if dy >= 0 { bin = 0 } else { bin = 1 } 283 } else { 284 if dy >= 0 { bin = 2 } else { bin = 3 } 285 } 286 bins[bin] = bins[bin] + 1 287 i = i + 1 288 } 289 var n_distinct: nx_int = 0 290 var j: nx_int = 0 291 while j < 4 { 292 if bins[j] > 0 { n_distinct = n_distinct + 1 } 293 j = j + 1 294 } 295 return (n_distinct * q) / 4 296} 297 298// ===== Public: wow-moment grader =================================== 299// Inputs: 300// heightmap, w, h required 301// features, n_features optional flat array of (x, y) pairs 302// sizes optional parallel array of feature radii 303// out_verdict 16-i64 LAYER_VERDICT 304func nx_wow_moment_detect( 305 heightmap: *i64, w: nx_int, h: nx_int, 306 features: *i64, n_features: nx_int, 307 sizes: *i64, 308 out_verdict: *i64 309) { 310 let sp: nx_int = _wm_signature_peaks_q14(heightmap, w, h) 311 let dv: nx_int = _wm_dramatic_valleys_q14(heightmap, w, h) 312 let iv: nx_int = _wm_isolation_var_q14(features, n_features) 313 let sd: nx_int = _wm_scale_diversity_q14(sizes, n_features) 314 let ra: nx_int = _wm_rarity_q14(features, n_features) 315 nx_layer_verdict_init(out_verdict, NX_LAYER_KIND_READABILITY, 316 NX_WM_AXIS_COUNT, NX_LAYER_REFINE_MORE_FEATURES) 317 out_verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_SIG_PEAKS] = sp 318 out_verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_DRAMATIC_VALLEYS] = dv 319 out_verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_ISOLATION_VAR] = iv 320 out_verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_SCALE_DIVERSITY] = sd 321 out_verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_RARITY] = ra 322 nx_layer_verdict_finalize(out_verdict) 323} 324 325// ===== Self-test ==================================================== 326func main() -> i64 { 327 let q: nx_int = NX_WM_Q 328 let verdict: *i64 = (sys_mmap(NX_LV_STRIDE * NX_SIZEOF_NX_INT)) as *i64 329 let null_ptr: *i64 = 0 as *i64 330 331 // T1: Build 16x16 map with 5 distinct peaks; expect signature 332 // peak count in band. 333 let w: nx_int = 16 334 let h: nx_int = 16 335 let n: nx_int = w * h 336 let map: *i64 = (sys_mmap(n * NX_SIZEOF_NX_INT)) as *i64 337 var i: nx_int = 0 338 while i < n { 339 let x: nx_int = i % w 340 let y: nx_int = i / w 341 // 5 peaks at (2,2), (5,10), (10,3), (12,12), (7,7). Quadratic 342 // falloff so each peak has a strict local maximum at its centre. 343 var v: nx_int = 0 344 let dx1: nx_int = x - 2; let dy1: nx_int = y - 2 345 let d1_sq: nx_int = dx1 * dx1 + dy1 * dy1 346 if d1_sq < 10 { v = v + (1000 - d1_sq * 100) } 347 let dx2: nx_int = x - 5; let dy2: nx_int = y - 10 348 let d2_sq: nx_int = dx2 * dx2 + dy2 * dy2 349 if d2_sq < 10 { v = v + (1000 - d2_sq * 100) } 350 let dx3: nx_int = x - 10; let dy3: nx_int = y - 3 351 let d3_sq: nx_int = dx3 * dx3 + dy3 * dy3 352 if d3_sq < 10 { v = v + (1000 - d3_sq * 100) } 353 let dx4: nx_int = x - 12; let dy4: nx_int = y - 12 354 let d4_sq: nx_int = dx4 * dx4 + dy4 * dy4 355 if d4_sq < 10 { v = v + (1000 - d4_sq * 100) } 356 let dx5: nx_int = x - 7; let dy5: nx_int = y - 7 357 let d5_sq: nx_int = dx5 * dx5 + dy5 * dy5 358 if d5_sq < 10 { v = v + (1000 - d5_sq * 100) } 359 map[i] = v 360 i = i + 1 361 } 362 nx_wow_moment_detect(map, w, h, null_ptr, 0, null_ptr, verdict) 363 // Signature peaks: should detect at least 3. 364 if verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_SIG_PEAKS] < q * 5 / 10 { 365 return __syscall(93, 1, 0, 0, 0, 0, 0) 366 } 367 368 // T2: Flat heightmap -> 0 peaks. 369 var f: nx_int = 0 370 while f < n { map[f] = 100; f = f + 1 } 371 nx_wow_moment_detect(map, w, h, null_ptr, 0, null_ptr, verdict) 372 if verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_SIG_PEAKS] != 0 { 373 return __syscall(93, 2, 0, 0, 0, 0, 0) 374 } 375 if verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_DRAMATIC_VALLEYS] != 0 { 376 return __syscall(93, 3, 0, 0, 0, 0, 0) 377 } 378 379 // T3: Feature list with diverse positions + sizes. 380 let feats: *i64 = (sys_mmap(8 * NX_SIZEOF_NX_INT)) as *i64 381 feats[0] = 0; feats[1] = 0 382 feats[2] = 50; feats[3] = 30 383 feats[4] = 30; feats[5] = 80 384 feats[6] = 90; feats[7] = 100 385 let sizes: *i64 = (sys_mmap(4 * NX_SIZEOF_NX_INT)) as *i64 386 sizes[0] = 5 387 sizes[1] = 15 388 sizes[2] = 25 389 sizes[3] = 50 390 nx_wow_moment_detect(map, w, h, feats, 4, sizes, verdict) 391 if verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_SCALE_DIVERSITY] < q * 5 / 10 { 392 return __syscall(93, 10, 0, 0, 0, 0, 0) 393 } 394 395 // T4: Verdict well-formed. 396 if verdict[NX_LV_OFF_KIND] != NX_LAYER_KIND_READABILITY { 397 return __syscall(93, 20, 0, 0, 0, 0, 0) 398 } 399 if nx_lv_grade_is_valid(verdict[NX_LV_OFF_GRADE]) != 1 { 400 return __syscall(93, 21, 0, 0, 0, 0, 0) 401 } 402 403 return 0 404}