This commit is contained in:
Rainer Leit
2026-09-25 17:02:24 +03:00
parent cc43ed8dc8
commit 9597629951
2149 changed files with 460234 additions and 1770 deletions
@@ -0,0 +1,91 @@
package field
import (
"math"
"math/rand/v2"
"testing"
)
// The deque has to give the same answer as the loop it replaces, on every cell, including the edges and the
// seam. It is O(1) a cell against O(radius squared), which is the difference between a diagnostic and a hang
// at planet scale - and an optimisation that is only nearly right is worse than the version that was slow.
func TestSlidingWindowsMatchTheNaiveLoop(t *testing.T) {
r := rand.New(rand.NewPCG(7, 9))
const w, h = 61, 37
f := New(w, h, 8)
for i := range f.Data {
f.Data[i] = float32(r.NormFloat64() * 50)
}
naive := func(cx, cy, radius int, wrapX, wantMax bool) float32 {
best := float32(math.Inf(1))
if wantMax {
best = float32(math.Inf(-1))
}
for y := cy - radius; y <= cy+radius; y++ {
sy := y
if sy < 0 {
sy = 0
} else if sy >= h {
sy = h - 1
}
for x := cx - radius; x <= cx+radius; x++ {
sx := x
if wrapX {
sx = ((sx % w) + w) % w
} else if sx < 0 {
sx = 0
} else if sx >= w {
sx = w - 1
}
v := f.Data[sy*w+sx]
if (wantMax && v > best) || (!wantMax && v < best) {
best = v
}
}
}
return best
}
for _, radius := range []int{1, 3, 8, 20} {
for _, wrapX := range []bool{false, true} {
hi := SlidingMax(f, radius, wrapX)
lo := SlidingMin(f, radius, wrapX)
rel := LocalRelief(f, radius, wrapX)
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
i := y*w + x
if got, want := hi.Data[i], naive(x, y, radius, wrapX, true); got != want {
t.Fatalf("max r=%d wrap=%v at (%d,%d): %v want %v", radius, wrapX, x, y, got, want)
}
if got, want := lo.Data[i], naive(x, y, radius, wrapX, false); got != want {
t.Fatalf("min r=%d wrap=%v at (%d,%d): %v want %v", radius, wrapX, x, y, got, want)
}
if got := rel.Data[i]; got != hi.Data[i]-lo.Data[i] {
t.Fatalf("relief r=%d at (%d,%d): %v against %v", radius, x, y, got,
hi.Data[i]-lo.Data[i])
}
}
}
}
}
}
// A radius of zero is a no-op rather than an error, which is what a caller with a window smaller than one
// cell should get.
func TestASlidingWindowOfNothingIsTheFieldItself(t *testing.T) {
f := New(4, 3, 8)
for i := range f.Data {
f.Data[i] = float32(i)
}
for _, got := range []*Field{SlidingMax(f, 0, true), SlidingMin(f, 0, false)} {
for i := range f.Data {
if got.Data[i] != f.Data[i] {
t.Fatalf("radius 0 changed cell %d", i)
}
}
}
if rel := LocalRelief(f, 0, true); rel.Data[5] != 0 {
t.Errorf("relief over a single cell is zero, got %v", rel.Data[5])
}
}