refactor: plotter, generator

This commit is contained in:
Ilia Denisov
2025-09-12 21:32:50 +03:00
parent d3b00b5c8d
commit 05999687aa
11 changed files with 262 additions and 140 deletions
+75
View File
@@ -0,0 +1,75 @@
package plotter
import (
"errors"
"fmt"
"math"
"math/rand"
"github.com/iliadenisov/galaxy/pkg/bitmap"
)
type Plotter struct {
factor float32
clearFn func()
circleFn func(x, y int, r float32)
freeCountFn func() int
freeNumberToCoordFn func(int) (int, int, error)
}
func NewPlotter(width, height uint32, factor float32) (Plotter, error) {
return NewBitmapPlotter(NewBitmap(width, height, factor), factor)
}
func NewBitmap(width, height uint32, factor float32) bitmap.Bitmap {
return bitmap.NewBitmap(AsPlotterSize(width, height, factor))
}
func NewBitmapPlotter(bm bitmap.Bitmap, factor float32) (Plotter, error) {
if factor > 1 || factor <= 0 {
return Plotter{}, fmt.Errorf("factor should be: 0 > F <= 1")
}
return Plotter{
factor: factor,
clearFn: bm.Clear,
circleFn: func(x, y int, r float32) { bm.Circle(x, y, r, true) },
freeCountFn: bm.FreeCount,
freeNumberToCoordFn: bm.GetFreeN,
}, nil
}
func (p Plotter) RandomFreePoint(deadZoneRaduis float32) (float32, float32, error) {
if deadZoneRaduis <= 0. {
return 0, 0, fmt.Errorf("radius must be positive value: %f", deadZoneRaduis)
}
fsCount := p.freeCountFn()
if fsCount == 0 {
return 0, 0, errors.New("RandomFreePoint: no free space left")
}
next := rand.Intn(fsCount)
x, y, err := p.freeNumberToCoordFn(next)
if err != nil {
return 0, 0, fmt.Errorf("RandomFreePoint: freeNumberToCoordFn: %s", err)
}
p.plotDeadZone(x, y, deadZoneRaduis)
planetX := float32(x)*p.factor + rand.Float32()*p.factor
planetY := float32(y)*p.factor + rand.Float32()*p.factor
return planetX, planetY, nil
}
func (p Plotter) MarkDeadZone(x, y float32, radius float32) {
p.plotDeadZone(int(x/p.factor), int(y/p.factor), radius)
}
func (p Plotter) plotDeadZone(x, y int, radius float32) {
p.circleFn(x, y, radius/p.factor)
}
func (p Plotter) Clear() { p.clearFn() }
func AsPlotterSize(width, height uint32, factor float32) (uint32, uint32) {
if factor > 1 || factor <= 0 {
return width, height
}
return uint32(math.Ceil(float64(width) / float64(factor))), uint32(math.Ceil(float64(height) / float64(factor)))
}
+86
View File
@@ -0,0 +1,86 @@
package plotter_test
import (
"testing"
"github.com/iliadenisov/galaxy/pkg/generator/plotter"
)
func TestNewPlotter(t *testing.T) {
_, err := plotter.NewPlotter(10, 10, 0)
if err == nil {
t.Error("expect: error when factor=0")
}
_, err = plotter.NewPlotter(10, 10, -0.01)
if err == nil {
t.Error("expect: error when factor<0")
}
_, err = plotter.NewPlotter(10, 10, 1.001)
if err == nil {
t.Error("expect: error when factor>1")
}
_, err = plotter.NewPlotter(10, 10, 1)
if err != nil {
t.Error("expect: no error when factor=1")
}
}
func TestAsPlotterSize(t *testing.T) {
for _, tc := range []struct {
w, h uint32
f float32
ew, eh uint32
}{
{10, 10, 0, 10, 10},
{10, 10, -1, 10, 10},
{10, 10, 1.1, 10, 10},
{10, 20, 0.5, 20, 40},
{30, 60, 0.3, 100, 200},
{10, 20, 0.25, 40, 80},
} {
w, h := plotter.AsPlotterSize(tc.w, tc.h, tc.f)
if tc.ew != w || tc.eh != h {
t.Errorf("expect: w=%d h=%d, got: w=%d h=%d", tc.ew, tc.eh, w, h)
}
}
}
func TestRandomFreePoint(t *testing.T) {
var factor float32 = 0.25
var w, h uint32 = 20, 20
bm := plotter.NewBitmap(w, h, factor)
p, err := plotter.NewBitmapPlotter(bm, factor) // 80x80
if err != nil {
t.Fatal(err)
}
x, y, err := p.RandomFreePoint(3)
if err != nil {
t.Errorf("expect: no error getting random point, got: %s", err)
}
if x > float32(w) || y > float32(w) {
t.Errorf("expect: point coordinates within map size %dx%d, got: x=%f y=%f", w, h, x, y)
}
_, _, err = p.RandomFreePoint(0)
if err == nil {
t.Error("expect: error when radius not positive, got: none")
}
_, _, err = p.RandomFreePoint(float32(w + h)) // guaranteed to mark whole area dead zone
if err != nil {
t.Errorf("expect: no error getting random point, got: %s", err)
}
_, _, err = p.RandomFreePoint(1)
if err == nil {
t.Error("expect: error when no free space left, got: none")
}
p.Clear()
_, _, err = p.RandomFreePoint(10)
if err != nil {
t.Errorf("expect: no error getting random point after clearing, got: %s", err)
}
}