code wiki / (root) / nx_procgen_preset_test.nx

nx_procgen_preset_test.nx source

↩ module page · 165 lines · 9414 B

1// nx_procgen_preset_test.nx -- smoke for bidirectional progressive disclosure. 2// 3// What this validates -- the STRUCTURAL invariants of the cardinal: 4// 1. Tier 0 just-works (single call, no knobs, returns useful struct) 5// 2. Tier 0 == Tier 1 with defaults (no hidden code path under Tier 0) 6// 3. Determinism: same (seed, preset, dims) -> bit-identical heightmap 7// 4. Presets actually affect output (different preset -> different heightmap) 8// 5. Tier-2 raw composition reproduces Tier-1 result (visible recipe) 9// 6. Defensive at boundaries: invalid preset / zero dims fall back cleanly 10// 7. Sealed-enum preset validity gate 11// 8. Height-band classifier composes with Perlin sealed-enum 12// 9. Poisson density honors preset radius differences (after the 13// r>=10 saturation fix landed -- previously this assertion blocked 14// on a substrate compiler-bug masquerading as algorithm bug; see 15// project-poisson-disk-bug-large-r-2026-05-15.md). 16 17import "nx_syscalls.nx" 18import "nx_tier.nx" 19import "nx_perlin.nx" 20import "nx_procgen_preset.nx" 21 22func main() -> nx_int { 23 // === Test 1: Tier-0 just-works produces valid Landscape ========== 24 let l0: *Landscape = nx_procgen_landscape_default(42) 25 if l0.width != NX_PROCGEN_DEFAULT_WIDTH { return 1 } 26 if l0.height != NX_PROCGEN_DEFAULT_HEIGHT { return 2 } 27 if l0.preset != NX_PROCGEN_PRESET_FOREST { return 3 } 28 if l0.seed != 42 { return 4 } 29 // Heightmap pointer must be non-null. 30 if (l0.heightmap as i64) == 0 { return 5 } 31 32 // === Test 2: heightmap is filled (not all zero) ================== 33 var nonzero: nx_int = 0 34 var iy: nx_int = 0 35 while iy < l0.height { 36 var ix: nx_int = 0 37 while ix < l0.width { 38 if nx_landscape_height_at(l0, ix, iy) != 0 { 39 nonzero = nonzero + 1 40 } 41 ix = ix + 1 42 } 43 iy = iy + 1 44 } 45 if nonzero < 100 { return 10 } 46 47 // === Test 3: BIDIRECTIONAL INVARIANT -- Tier 0 == Tier 1(defaults) ==== 48 // 49 // Calling Tier-1 with the SAME defaults as Tier-0 yields identical 50 // shape AND identical heightmap. This is the load-bearing assertion 51 // for the cardinal: Tier-0 is literally a one-line Tier-1 call, no 52 // hidden code path, no opaque defaults outside the named consts. 53 let l1: *Landscape = nx_procgen_landscape(42, 54 NX_PROCGEN_PRESET_FOREST, 55 NX_PROCGEN_DEFAULT_WIDTH, 56 NX_PROCGEN_DEFAULT_HEIGHT, 57 NX_PROCGEN_DEFAULT_DENSITY_Q10) 58 if l1.width != l0.width { return 20 } 59 if l1.height != l0.height { return 21 } 60 if l1.preset != l0.preset { return 22 } 61 if l1.seed != l0.seed { return 23 } 62 // Heightmap content must match -- determinism + same recipe. 63 if nx_landscape_height_at(l1, 0, 0) != nx_landscape_height_at(l0, 0, 0) { return 24 } 64 if nx_landscape_height_at(l1, 17, 23) != nx_landscape_height_at(l0, 17, 23) { return 25 } 65 if nx_landscape_height_at(l1, 31, 31) != nx_landscape_height_at(l0, 31, 31) { return 26 } 66 if nx_landscape_height_at(l1, 63, 63) != nx_landscape_height_at(l0, 63, 63) { return 27 } 67 if nx_landscape_height_at(l1, 40, 7) != nx_landscape_height_at(l0, 40, 7) { return 28 } 68 69 // === Test 4: determinism -- same seed/preset/dims produce same heightmap ==== 70 let l_same: *Landscape = nx_procgen_landscape(42, 71 NX_PROCGEN_PRESET_FOREST, 72 NX_PROCGEN_DEFAULT_WIDTH, 73 NX_PROCGEN_DEFAULT_HEIGHT, 74 NX_PROCGEN_DEFAULT_DENSITY_Q10) 75 // Sample five cells -- determinism must hold pixel-perfect. 76 if nx_landscape_height_at(l_same, 5, 5) != nx_landscape_height_at(l0, 5, 5) { return 30 } 77 if nx_landscape_height_at(l_same, 32, 0) != nx_landscape_height_at(l0, 32, 0) { return 31 } 78 if nx_landscape_height_at(l_same, 0, 32) != nx_landscape_height_at(l0, 0, 32) { return 32 } 79 80 // === Test 5: different seed -> different heightmap =============== 81 // 82 // The Perlin gradient table is seed-permuted; different seeds yield 83 // different output. At least one of three sampled cells must differ. 84 let l_seed: *Landscape = nx_procgen_landscape(99, 85 NX_PROCGEN_PRESET_FOREST, 86 NX_PROCGEN_DEFAULT_WIDTH, 87 NX_PROCGEN_DEFAULT_HEIGHT, 88 NX_PROCGEN_DEFAULT_DENSITY_Q10) 89 var seed_diff: nx_int = 0 90 if nx_landscape_height_at(l_seed, 10, 10) != nx_landscape_height_at(l0, 10, 10) { seed_diff = 1 } 91 if nx_landscape_height_at(l_seed, 20, 30) != nx_landscape_height_at(l0, 20, 30) { seed_diff = 1 } 92 if nx_landscape_height_at(l_seed, 50, 50) != nx_landscape_height_at(l0, 50, 50) { seed_diff = 1 } 93 if seed_diff != 1 { return 40 } 94 95 // === Test 6: different preset -> different heightmap ============= 96 // 97 // FOREST and MOUNTAIN use different octaves+persistence, so the 98 // fbm output at the same (seed, x, y) must differ for some cell. 99 let l_mtn: *Landscape = nx_procgen_landscape(42, 100 NX_PROCGEN_PRESET_MOUNTAIN, 101 NX_PROCGEN_DEFAULT_WIDTH, 102 NX_PROCGEN_DEFAULT_HEIGHT, 103 NX_PROCGEN_DEFAULT_DENSITY_Q10) 104 var preset_diff: nx_int = 0 105 if nx_landscape_height_at(l_mtn, 10, 10) != nx_landscape_height_at(l0, 10, 10) { preset_diff = 1 } 106 if nx_landscape_height_at(l_mtn, 20, 30) != nx_landscape_height_at(l0, 20, 30) { preset_diff = 1 } 107 if nx_landscape_height_at(l_mtn, 50, 50) != nx_landscape_height_at(l0, 50, 50) { preset_diff = 1 } 108 if preset_diff != 1 { return 50 } 109 110 // === Test 6b: presets produce DIFFERENT poisson density ========== 111 // 112 // FOREST has base_radius=4, DESERT has base_radius=10, MOUNTAIN has 113 // base_radius=12. On same canvas + same seed, density-ordering 114 // must be FOREST > DESERT > MOUNTAIN (more features at smaller r). 115 // This assertion would have failed before the Poisson stack-arg 116 // codegen fix landed (xs/ys read garbage, all candidates accepted). 117 let lf: *Landscape = nx_procgen_landscape(7, 118 NX_PROCGEN_PRESET_FOREST, 119 64, 64, 1024) 120 let ld: *Landscape = nx_procgen_landscape(7, 121 NX_PROCGEN_PRESET_DESERT, 122 64, 64, 1024) 123 let lm: *Landscape = nx_procgen_landscape(7, 124 NX_PROCGEN_PRESET_MOUNTAIN, 125 64, 64, 1024) 126 if lf.n_features <= ld.n_features { return 55 } 127 if ld.n_features < lm.n_features { return 56 } 128 129 // === Test 7: invalid preset falls back to FOREST ================= 130 let l_fallback: *Landscape = nx_procgen_landscape(7, 99, 131 64, 64, 1024) 132 if l_fallback.preset != NX_PROCGEN_PRESET_FOREST { return 60 } 133 134 // === Test 8: zero/negative dims fall back to defaults ============ 135 let l_zero: *Landscape = nx_procgen_landscape(7, 136 NX_PROCGEN_PRESET_FOREST, 137 0, 0, 0) 138 if l_zero.width != NX_PROCGEN_DEFAULT_WIDTH { return 70 } 139 if l_zero.height != NX_PROCGEN_DEFAULT_HEIGHT { return 71 } 140 141 // === Test 9: sealed-enum validity ================================ 142 if nx_procgen_preset_is_valid(NX_PROCGEN_PRESET_FOREST) != 1 { return 80 } 143 if nx_procgen_preset_is_valid(NX_PROCGEN_PRESET_DESERT) != 1 { return 81 } 144 if nx_procgen_preset_is_valid(NX_PROCGEN_PRESET_MEADOW) != 1 { return 82 } 145 if nx_procgen_preset_is_valid(NX_PROCGEN_PRESET_COAST) != 1 { return 83 } 146 if nx_procgen_preset_is_valid(NX_PROCGEN_PRESET_MOUNTAIN) != 1 { return 84 } 147 if nx_procgen_preset_is_valid(NX_PROCGEN_N_PRESETS) != 0 { return 85 } 148 if nx_procgen_preset_is_valid(99) != 0 { return 86 } 149 if nx_procgen_preset_is_valid(0 - 1) != 0 { return 87 } 150 151 // === Test 10: height-band classifier composes with Perlin sealed-enum === 152 // 153 // The accessor returns a band value that must be valid per Perlin's 154 // own sealed-enum gate. Composition across modules. 155 let band: nx_int = nx_landscape_height_band_at(l0, 32, 32) 156 if nx_perlin_band_is_valid(band) != 1 { return 90 } 157 158 // === Test 11: out-of-bounds height read returns 0 (no SEGV) ====== 159 if nx_landscape_height_at(l0, 0 - 1, 0) != 0 { return 100 } 160 if nx_landscape_height_at(l0, l0.width, 0) != 0 { return 101 } 161 if nx_landscape_height_at(l0, 0, 0 - 1) != 0 { return 102 } 162 if nx_landscape_height_at(l0, 0, l0.height) != 0 { return 103 } 163 164 return 0 165}