package check import ( "testing" "salty/terrain/internal/manifest" "salty/terrain/internal/uplift" ) // TestBorderIsAlwaysOcean is the boundary condition the whole solve rests on, asserted rather than assumed. // // A cell on the map border is an outlet: `fluvial.isOutlet` returns true for it whatever else is true, so it // takes no uplift and is never eroded, and the repose clamp will not lower it either. Land that reaches the // border therefore freezes at whatever the initial relief gave it while the interior erodes away beneath it, // and what that looks like is a rim of untouched terrain standing a hundred metres over its neighbour — it is // what once reported a 66 degree slope on a map whose angle of repose was 22. `continentMask` imposes a // margin to prevent it, and this test is what says the margin is still doing its job. // // It is worth a test rather than a comment because the margin is easy to break from a distance. The uplift // rate used to be multiplied by the continent mask, so the margin's taper was suppressing uplift at the border // as a side effect; decoupling the two (D-52) removed that, and nothing in the change was anywhere near this // file. The invariant is the border cells themselves, so that is what is asserted; the distances and rates are // reported alongside because they are what a person would want to see when it does fail. func TestBorderIsAlwaysOcean(t *testing.T) { const size = 1400 const sideM = 14280.0 cell := sideM / (size - 1) for _, seed := range []int64{7, 9342, 67914} { m := manifest.Defaults() m.Source.Seed = seed up := uplift.Build(size, cell, m) for x := 0; x < size; x++ { for _, i := range [2]int{x, (size-1)*size + x} { if !up.Base[i] { t.Errorf("seed %d: cell (%d,%d) on the top or bottom border is land", seed, i%size, i/size) } } } for y := 0; y < size; y++ { for _, i := range [2]int{y * size, y*size + size - 1} { if !up.Base[i] { t.Errorf("seed %d: cell (%d,%d) on the left or right border is land", seed, i%size, i/size) } } } // How hard the margin is pressing. The margin does not only keep land off the border; where the // continent would have run past the edge it *cuts* it, and it cuts along a contour of distance-to-edge, // which is a straight line parallel to that edge. So a coastline inside the margin band is a coastline // the margin drew rather than one the noise did, and the count is the measure of how much of one there // is. It is logged, not asserted: some is unavoidable and the right threshold is a judgement. band := int(0.04 * size) nearest := size var peakRate, peakHeight float64 landInBand, shoreInBand, shore := 0, 0, 0 for i := range up.Base { x, y := i%size, i/size d := min(min(x, size-1-x), min(y, size-1-y)) if up.Base[i] { // A waterline cell: ocean with land in the four-neighbourhood. for _, n := range [4]int{i - 1, i + 1, i - size, i + size} { if n >= 0 && n < len(up.Base) && !up.Base[n] { shore++ if d < band { shoreInBand++ } break } } continue } if d < nearest { nearest = d } if d < band { landInBand++ if r := float64(up.Rate.Data[i]) * 1000; r > peakRate { peakRate = r } if h := float64(up.Height.Data[i]); h > peakHeight { peakHeight = h } } } pct := 0.0 if shore > 0 { pct = float64(shoreInBand) / float64(shore) * 100 } t.Logf("seed %6d: nearest land %d cells (%.0f m) from the border; inside the %d-cell margin, "+ "%d land cells, peak uplift %.2f mm/yr, peak initial relief %.0f m; %.1f%% of the shoreline is "+ "inside the margin band (a coast the margin drew, not the noise)", seed, nearest, float64(nearest)*cell, band, landInBand, peakRate, peakHeight, pct) } }