Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .claude/status.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
task: PR #434 (W-9 final-surface talus_step_final)
phase: CI pass 2 in flight (dim=128→256 fixture, non-vacuity control removed)
blocked_on: CI completion (run #29284354893 in_progress)
next: CI completes → extract v2-golden-arm64 left:/right: → re-pin golden → green CI
updated: 2026-07-13 23:04
task: #438 W-10 material diversity (presentation-only soil split + slope outcrops)
phase: CI
blocked_on: CI run #29288184040 in progress; code-critic review in progress
next: (1) CI completes → verify all 4 jobs green; (2) critic completes → resolve verdict; (3) create PR with --base render-r12-terragen-preview; (4) append verdict comment; (5) mark ready-for-review
updated: 2026-07-13 23:59
12 changes: 8 additions & 4 deletions v2/crates/world/src/bin/map_dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use world::gen::material::MaterialId;
const HMAX: i64 = 200;

/// Primary-material → RGB palette (top-down surface colour).
/// Includes W-10 presentation-only discriminants: SoilDry (9), SoilWet (10).
fn colour(m: u8) -> [u8; 3] {
match m {
x if x == MaterialId::Air as u8 => [180, 180, 190], // air (above-surface empty) — pale grey
Expand All @@ -31,6 +32,8 @@ fn colour(m: u8) -> [u8; 3] {
x if x == MaterialId::Tuff as u8 => [172, 150, 138], // volcanic tuff — light brown
x if x == MaterialId::Till as u8 => [184, 194, 206], // glacial till — grey-blue
x if x == MaterialId::Water as u8 => [40, 70, 130], // coastal water — blue (W-SIM-7, #423)
9 => [64, 96, 42], // W-10: SoilDry (discriminant 9) — darker/drier soil green
10 => [128, 164, 90], // W-10: SoilWet (discriminant 10) — lighter/wetter soil green
_ => [255, 0, 255], // unknown — magenta
}
}
Expand Down Expand Up @@ -64,14 +67,15 @@ fn main() {
std::fs::File::create(&out).and_then(|mut f| f.write_all(&buf)).expect("write ppm");

// Material histogram to stderr — a quick sanity read without opening the image.
let mut hist = [0u32; 8];
// Covers all discriminants: 0-8 (MaterialId), 9-10 (W-10 presentation-only).
let mut hist = [0u32; 11];
for &m in &fields.surface_material {
if (m as usize) < 8 {
if (m as usize) < 11 {
hist[m as usize] += 1;
}
}
let names = ["Air", "Sand", "Permafrost", "Soil", "Bedrock", "Basalt", "Tuff", "Till"];
eprintln!("wrote {out} ({dim}x{dim}, seed={seed:#x}, all landforms ON)");
let names = ["Air", "Sand", "Permafrost", "Soil", "Bedrock", "Basalt", "Tuff", "Till", "Water", "SoilDry", "SoilWet"];
eprintln!("wrote {out} ({dim}x{dim}, seed={seed:#x}, all landforms ON, W-10 enabled)");
for (i, n) in names.iter().enumerate() {
if hist[i] > 0 {
eprintln!(" {n:<10} {:>8} ({:.1}%)", hist[i], 100.0 * hist[i] as f64 / (dim * dim) as f64);
Expand Down
112 changes: 112 additions & 0 deletions v2/crates/world/src/bin/w10_phase0.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//! W-10 Phase-0 measurement: moisture and slope histograms for SoilDry/Soil/SoilWet split.
//! Usage: w10_phase0 [dim]
//! Outputs: moisture histogram (deciles), slope histogram (deciles), class share estimates.

use world::gen::caps::classify_and_caps_staged;
use world::gen::material::MaterialId;
use world::gen::moisture::moisture_at;

const HMAX: i64 = 200;

fn compute_deciles(values: &[i64]) -> Vec<i64> {
if values.is_empty() {
return vec![0; 11];
}
let mut sorted = values.to_vec();
sorted.sort_unstable();
let n = sorted.len();
(0..=10)
.map(|i| {
let idx = (i * n) / 10;
sorted[idx.min(n - 1)]
})
.collect()
}

fn main() {
let dim: usize = std::env::args()
.nth(1)
.and_then(|s| s.parse().ok())
.unwrap_or(512);

println!("\n=== W-10 PHASE-0 MEASUREMENT (moisture/slope histograms @dim={}, seeds 1..2) ===", dim);

for seed in [1u64, 2] {
println!("\n--- Seed {} ---", seed);

// Run the post-W-9 classification (all landforms enabled, talus disabled to match Phase-0 intent).
// Actually, we want the POST-talus field since that's what classify uses.
let (_, staged, _) = classify_and_caps_staged(
seed, HMAX, dim, false, true, true, true, true, true, false, true // enable_w10=true
);

let _n = dim * dim;
let post_deneedle_height = &staged.post_deneedle;
let erosion = world::gen::erosion::erode(seed, HMAX, dim, true, true);

// Collect moisture and slope for Soil cells only
let mut soil_moistures = Vec::new();
let mut soil_slopes = Vec::new();

for z in 0..dim {
for x in 0..dim {
let idx = z * dim + x;

// Check if substrate is Soil (MaterialId::Soil = 3)
let material_byte = erosion.surface_material[idx] as u8;
if material_byte != MaterialId::Soil as u8 {
continue; // Skip non-Soil cells
}

// Compute moisture
let area = erosion.drainage.area[idx];
let moisture = moisture_at(area);
soil_moistures.push(moisture);

// Compute slope
let slope = match erosion.drainage.downstream[idx] {
Some(d) => (post_deneedle_height[idx] - post_deneedle_height[d]).max(0),
None => 0,
};
soil_slopes.push(slope);
}
}

// Compute deciles
let moisture_deciles = compute_deciles(&soil_moistures);
let slope_deciles = compute_deciles(&soil_slopes);

println!(" Soil cells: {}", soil_moistures.len());
println!(" Moisture (0=dry, 1000=wet): deciles = {:?}", moisture_deciles);
println!(" Slope: deciles = {:?}", slope_deciles);

// Test threshold candidates from deciles (target: 40–60% / 25–35% / 15–25%)
// Deciles show steep distribution: p50≈10–11, p90≈80–170
let candidates: &[(i64, i64, &str)] = &[
(15, 80, "CANDIDATE-A"),
(20, 100, "CANDIDATE-B"),
(25, 120, "CANDIDATE-C"),
];

for (dry_thresh, wet_thresh, label) in candidates {
let dry_count = soil_moistures.iter().filter(|&&m| m < *dry_thresh).count();
let wet_count = soil_moistures.iter().filter(|&&m| m >= *wet_thresh).count();
let normal_count = soil_moistures.len() - dry_count - wet_count;
let outcrop_count = soil_slopes.iter().filter(|&&s| s >= 5).count();

println!(" {} (dry<{}, wet>={}): SoilDry {:.1}% | Soil {:.1}% | SoilWet {:.1}% | Outcrop {:.1}%",
label, dry_thresh, wet_thresh,
100.0 * dry_count as f64 / soil_moistures.len() as f64,
100.0 * normal_count as f64 / soil_moistures.len() as f64,
100.0 * wet_count as f64 / soil_moistures.len() as f64,
100.0 * outcrop_count as f64 / soil_moistures.len() as f64);
}
}

println!("\n=== CHOOSE CANDIDATE ABOVE (target: 40–60% / 25–35% / 15–25%) ===");
println!("Pick the candidate closest to those shares, then pin:");
println!("// Example: if CANDIDATE-B (20/100) gives best distribution:");
println!("const SOILDRY_THRESHOLD: i64 = 20; // Below this -> SoilDry");
println!("const SOILWET_THRESHOLD: i64 = 100; // At/above this -> SoilWet");
println!("const OUTCROP_SLOPE_THRESHOLD: i64 = 5; // Soil* with slope >= this -> Bedrock");
}
6 changes: 3 additions & 3 deletions v2/crates/world/src/bin/w9_sweep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ fn phase0_measurement(dim: usize) {

for seed in [1u64, 42] {
let (_, staged, masks) = classify_and_caps_staged(
seed, HMAX, dim, false, true, true, true, true, true, false // All landforms ON, talus OFF
seed, HMAX, dim, false, true, true, true, true, true, false, true // All landforms ON, talus OFF, enable_w10=true
);

println!("\nSeed {} (all landforms ON, dim={})", seed, dim);
Expand Down Expand Up @@ -66,7 +66,7 @@ fn sweep_measurement(dim: usize) {

// Generate base map once (with all landforms ON, talus OFF to get post-coastal)
let (_, staged, masks) = classify_and_caps_staged(
seed, HMAX, dim, false, true, true, true, true, true, false
seed, HMAX, dim, false, true, true, true, true, true, false, true // enable_w10=true
);

// BASELINE: Measure counts for talus-OFF (post-coastal only)
Expand Down Expand Up @@ -116,7 +116,7 @@ fn export_candidates(dim: usize) {

// Generate base map once for staged heights
let (_, staged, _) = classify_and_caps_staged(
seed, HMAX, dim, false, true, true, true, true, true, false
seed, HMAX, dim, false, true, true, true, true, true, false, true // enable_w10=true
);

// Get production materials from baseline (talus OFF) — materials don't change with talus smoothing
Expand Down
Loading
Loading