From 371453fac5d7a8e8bded18f0b3ecb4cb6fef6495 Mon Sep 17 00:00:00 2001 From: Ilia Denisov Date: Thu, 11 Sep 2025 01:34:55 +0300 Subject: [PATCH] refactor: plotter bitmap --- go.mod | 2 +- pkg/bitmap/assets_test/circle_case_00.txt | 6 + pkg/bitmap/assets_test/circle_case_01.txt | 6 + pkg/bitmap/assets_test/circle_case_02.txt | 12 ++ pkg/bitmap/assets_test/circle_case_03.txt | 12 ++ pkg/bitmap/assets_test/circle_case_04.txt | 15 +++ pkg/bitmap/bitmap.go | 60 ++++++++- pkg/bitmap/bitmap_test.go | 105 ++++++++++++--- pkg/bitmap/go.mod | 3 - pkg/generator/draw/draw.go | 148 ---------------------- pkg/generator/draw/draw_test.go | 82 ------------ pkg/generator/draw/export_test.go | 3 - pkg/generator/generator.go | 69 +++++----- 13 files changed, 222 insertions(+), 301 deletions(-) create mode 100644 pkg/bitmap/assets_test/circle_case_01.txt create mode 100644 pkg/bitmap/assets_test/circle_case_02.txt create mode 100644 pkg/bitmap/assets_test/circle_case_03.txt create mode 100644 pkg/bitmap/assets_test/circle_case_04.txt delete mode 100644 pkg/bitmap/go.mod delete mode 100644 pkg/generator/draw/draw.go delete mode 100644 pkg/generator/draw/draw_test.go delete mode 100644 pkg/generator/draw/export_test.go diff --git a/go.mod b/go.mod index 42f3349..87557e4 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/iliadenisov/galaxy -go 1.20 +go 1.25.0 diff --git a/pkg/bitmap/assets_test/circle_case_00.txt b/pkg/bitmap/assets_test/circle_case_00.txt index e69de29..f743b85 100644 --- a/pkg/bitmap/assets_test/circle_case_00.txt +++ b/pkg/bitmap/assets_test/circle_case_00.txt @@ -0,0 +1,6 @@ +░░██████░░░░ +██░░░░░░██░░ +██░░░░░░██░░ +██░░░░░░██░░ +░░██████░░░░ +░░░░░░░░░░░░ \ No newline at end of file diff --git a/pkg/bitmap/assets_test/circle_case_01.txt b/pkg/bitmap/assets_test/circle_case_01.txt new file mode 100644 index 0000000..340ef5f --- /dev/null +++ b/pkg/bitmap/assets_test/circle_case_01.txt @@ -0,0 +1,6 @@ +████░░░░░░██ +██████░░████ +██████░░████ +██████░░████ +████░░░░░░██ +░░░░░░░░░░░░ \ No newline at end of file diff --git a/pkg/bitmap/assets_test/circle_case_02.txt b/pkg/bitmap/assets_test/circle_case_02.txt new file mode 100644 index 0000000..520a0d1 --- /dev/null +++ b/pkg/bitmap/assets_test/circle_case_02.txt @@ -0,0 +1,12 @@ +░░░░░░██████████░░░░░░░░ +░░░░██████████████░░░░░░ +░░██████████████████░░░░ +██████████████████████░░ +██████████████████████░░ +██████████████████████░░ +██████████████████████░░ +██████████████████████░░ +░░██████████████████░░░░ +░░░░██████████████░░░░░░ +░░░░░░██████████░░░░░░░░ +░░░░░░░░░░░░░░░░░░░░░░░░ \ No newline at end of file diff --git a/pkg/bitmap/assets_test/circle_case_03.txt b/pkg/bitmap/assets_test/circle_case_03.txt new file mode 100644 index 0000000..b1da9f2 --- /dev/null +++ b/pkg/bitmap/assets_test/circle_case_03.txt @@ -0,0 +1,12 @@ +██░░░░░░░░░░░░░░░░░░██░░ +██░░░░░░░░░░░░░░░░░░██░░ +██░░░░░░░░░░░░░░░░░░██░░ +░░██░░░░░░░░░░░░░░██░░░░ +░░░░██░░░░░░░░░░██░░░░░░ +░░░░░░██████████░░░░░░░░ +░░░░░░░░░░░░░░░░░░░░░░░░ +░░░░░░██████████░░░░░░░░ +░░░░██░░░░░░░░░░██░░░░░░ +░░██░░░░░░░░░░░░░░██░░░░ +██░░░░░░░░░░░░░░░░░░██░░ +██░░░░░░░░░░░░░░░░░░██░░ \ No newline at end of file diff --git a/pkg/bitmap/assets_test/circle_case_04.txt b/pkg/bitmap/assets_test/circle_case_04.txt new file mode 100644 index 0000000..c1a61ac --- /dev/null +++ b/pkg/bitmap/assets_test/circle_case_04.txt @@ -0,0 +1,15 @@ +░░░░░░░░░░██████████░░░░░░░░░░ +░░░░░░████░░░░░░░░░░████░░░░░░ +░░░░██░░░░░░░░░░░░░░░░░░██░░░░ +░░██░░░░░░░░░░░░░░░░░░░░░░██░░ +░░██░░░░░░░░░░░░░░░░░░░░░░██░░ +██░░░░░░░░░░░░░░░░░░░░░░░░░░██ +██░░░░░░░░░░░░░░░░░░░░░░░░░░██ +██░░░░░░░░░░░░░░░░░░░░░░░░░░██ +██░░░░░░░░░░░░░░░░░░░░░░░░░░██ +██░░░░░░░░░░░░░░░░░░░░░░░░░░██ +░░██░░░░░░░░░░░░░░░░░░░░░░██░░ +░░██░░░░░░░░░░░░░░░░░░░░░░██░░ +░░░░██░░░░░░░░░░░░░░░░░░██░░░░ +░░░░░░████░░░░░░░░░░████░░░░░░ +░░░░░░░░░░██████████░░░░░░░░░░ \ No newline at end of file diff --git a/pkg/bitmap/bitmap.go b/pkg/bitmap/bitmap.go index 16913a8..4569e02 100644 --- a/pkg/bitmap/bitmap.go +++ b/pkg/bitmap/bitmap.go @@ -1,8 +1,10 @@ package bitmap import ( + "errors" "fmt" "math" + "math/bits" ) const intSize = 32 @@ -35,14 +37,61 @@ func (p bitmap) isSet(number uint32) bool { return p.bitVector[number/intSize]&(0b1<<(number%intSize)) > 0 } -func (p bitmap) Circle(x, y int, r float64) { +func (p bitmap) FreeCount() (result int) { + result = int(p.width) * int(p.height) + for i := range p.bitVector { + result -= bits.OnesCount32(p.bitVector[i]) + } + return +} + +func (p bitmap) GetFreeN(number int) (int, int, error) { + if p.FreeCount() == 0 { + return 0, 0, errors.New("no free pixels left") + } + fc := 0 + n := 0 + for ; n < int(p.width)*int(p.height); n++ { + if p.isSet(uint32(n)) { + continue + } + if fc == number { + y := n / int(p.height) + x := n - int(p.height)*y + return x, y, nil + } + fc++ + } + return 0, 0, fmt.Errorf("get free pixel: no such number=%d, max=%d", number, n) +} + +func (p bitmap) SetFreeN(number int) error { + if p.FreeCount() == 0 { + return errors.New("no free pixels left") + } + fc := 0 + n := 0 + for ; n < int(p.width)*int(p.height); n++ { + if p.isSet(uint32(n)) { + continue + } + if fc == number { + p.set(uint32(n)) + return nil + } + fc++ + } + return fmt.Errorf("set free pixel: no such number=%d, max=%d", number, n) +} + +func (p bitmap) Circle(x, y int, r float64, fill bool) { plotX := 0 plotY := int(math.Ceil(r)) delta := 3 - 2*plotY lastY := plotY for plotX <= plotY { p.octant(x, y, plotX, plotY) - if plotY < lastY { + if fill && plotY < lastY { for lineX := 0; lineX < plotX; lineX++ { p.octant(x, y, lineX, plotY) } @@ -56,6 +105,9 @@ func (p bitmap) Circle(x, y int, r float64) { } plotX += 1 } + if !fill { + return + } for fillX := 0; fillX < plotX; fillX++ { for fillY := 0; fillY <= fillX; fillY++ { p.octant(x, y, fillX, fillY) @@ -63,7 +115,7 @@ func (p bitmap) Circle(x, y int, r float64) { } } -func (p bitmap) CircleAdjacent(x, y int, r float64) { +func (p bitmap) circleAdjacent(x, y int, r float64) { plotX := 0 plotY := int(math.Ceil(r)) delta := 1 - 2*plotY @@ -110,7 +162,7 @@ func (p bitmap) String() string { cnt := 0 for i := 0; i < len(p.bitVector); i++ { for bit := 0; bit < intSize && cnt < int(p.width*p.height); bit++ { - result += fmt.Sprintf("%s", px[p.bitVector[i]&(0b1< 0]) + result += px[p.bitVector[i]&(0b1< 0] cnt++ if cnt%int(p.width) == 0 { result += "\n" diff --git a/pkg/bitmap/bitmap_test.go b/pkg/bitmap/bitmap_test.go index 5ea2dbd..d294ddc 100644 --- a/pkg/bitmap/bitmap_test.go +++ b/pkg/bitmap/bitmap_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "bitmap" + "github.com/iliadenisov/galaxy/pkg/bitmap" ) func TestBitVectorSize(t *testing.T) { @@ -126,6 +126,76 @@ func TestSetPixel(t *testing.T) { } } +func TestFreeCount(t *testing.T) { + bm := bitmap.NewBitmap(10, 10) + type testCase struct { + x, y, expect int + } + for _, tc := range []testCase{ + {0, 0, 99}, + {5, 5, 98}, + {9, 9, 97}, + {10, 10, 97}, + {15, 6, 96}, + {9, 9, 96}, + {3, 8, 95}, + } { + t.Run(fmt.Sprintf("x=%d,y=%d", tc.x, tc.y), func(t *testing.T) { + bm.Set(tc.x, tc.y) + count := bm.FreeCount() + if tc.expect != count { + t.Errorf("expected: %d, actual %d", tc.expect, count) + } + }) + } +} + +func TestSetFreeN(t *testing.T) { + bm := bitmap.NewBitmap(5, 5) + type testCase struct { + x, y, number int + } + for i, tc := range []testCase{ + {0, 0, 0}, + {1, 0, 0}, + {4, 0, 2}, + {2, 2, 9}, + {1, 1, 3}, + {3, 1, 4}, + {3, 2, 7}, + {4, 4, 17}, + {3, 0, 1}, + } { + t.Run(fmt.Sprintf("tc#%d", i), func(t *testing.T) { + if x, y, err := bm.GetFreeN(tc.number); err != nil { + t.Errorf("get free by number=%d: %s", tc.number, err) + } else if tc.x != x || tc.y != y { + t.Fatalf("expected: x=%d, y=%d by number=%d, got: x=%d, y=%d", tc.x, tc.y, tc.number, x, y) + } + if err := bm.SetFreeN(tc.number); err != nil { + t.Errorf("set free by number=%d: %s", tc.number, err) + } else if !bm.IsSet(tc.x, tc.y) { + t.Errorf("expected to be set: free_number=%d @ x=%d,y=%d bitmap:\n%s", tc.number, tc.x, tc.y, bm) + } + }) + } + + bm = bitmap.NewBitmap(2, 2) + bm.Set(0, 0) + bm.Set(1, 0) + bm.Set(0, 1) + if err := bm.SetFreeN(1); err == nil { + t.Errorf("expected: error when free pixel number greater than free pixels count") + } + if _, _, err := bm.GetFreeN(1); err == nil { + t.Errorf("expected: error when free pixel number greater than free pixels count") + } + bm.Set(1, 1) + if err := bm.SetFreeN(0); err == nil { + t.Errorf("expected: error when no free pixels left") + } +} + func TestClear(t *testing.T) { var bm = bitmap.NewBitmap(10, 10) for range 50 { @@ -148,37 +218,32 @@ func TestClear(t *testing.T) { } } -func TestCircle5x5(t *testing.T) { +func TestCircle(t *testing.T) { type testCase struct { x, y int r float64 filled bool } - bm := bitmap.NewBitmap(80, 80) for i, tc := range []testCase{ - {3, 3, 0.9, false}, + {2, 2, 2, false}, + {0, 2, 2, true}, + {5, 5, 5, true}, + {5, 0, 5, false}, + {7, 7, 6.6, false}, } { - file := fmt.Sprintf("assets_test/circle_case_%02d.txt", i) - _ = file - t.Run(file, func(t *testing.T) { - bm.CircleAdjacent(tc.x, tc.y, tc.r) - b, err := os.ReadFile(file) + exampleFile := fmt.Sprintf("assets_test/circle_case_%02d.txt", i) + t.Run(exampleFile, func(t *testing.T) { + size := uint32(tc.r*2) + 2 + bm := bitmap.NewBitmap(size, size) + bm.Circle(tc.x, tc.y, tc.r, tc.filled) + b, err := os.ReadFile(exampleFile) if err != nil { t.Fatal(err) } expect := strings.TrimSpace(string(b)) - if expect != bm.String() { - t.Errorf("expect:\n%s\ngot:\n%s\n", expect, bm.String()) + if expect != strings.TrimSpace(bm.String()) { + t.Errorf("expect:\n%s\ngot:\n%s\n", expect, bm) } }) } } - -func TestCircle(t *testing.T) { - var size int = 40 - var bm1 = bitmap.NewBitmap(uint32(size), uint32(size)) - bm1.Circle(size/2+5, size/2-5, float64(size/2)-3) - fmt.Println(bm1) - var bm2 = bitmap.NewBitmap(uint32(size), uint32(size)) - bm2.CircleAdjacent(size/2+20, size/2, float64(size/2)-5) -} diff --git a/pkg/bitmap/go.mod b/pkg/bitmap/go.mod deleted file mode 100644 index 2ea27db..0000000 --- a/pkg/bitmap/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module bitmap - -go 1.24.5 diff --git a/pkg/generator/draw/draw.go b/pkg/generator/draw/draw.go deleted file mode 100644 index da72c26..0000000 --- a/pkg/generator/draw/draw.go +++ /dev/null @@ -1,148 +0,0 @@ -package draw - -import ( - "fmt" - "math" -) - -const batchSize = 32 - -type Plane struct { - Width uint - Height uint - pixels []uint32 -} - -func (p *Plane) pixelsValue() []uint32 { - return p.pixels -} - -func New(width uint, height uint) Plane { - elements := int(math.Ceil(float64(width*height) / batchSize)) - return Plane{Width: width, Height: height, pixels: make([]uint32, elements)} -} - -func (p Plane) Mark(x, y int) { - boundX := (p.Width + uint(x)) % p.Width - boundY := (p.Height + uint(y)) % p.Height - p.mark(boundX + boundY*p.Width) - - // p.mark(x + y*p.Width) - - // number := x + y*p.width - // index := number / batchSize - // bit := number % batchSize - // p.pixels[index] |= (0b1 << bit) -} - -func (p Plane) mark(number uint) { - // index := number / batchSize - // bit := number % batchSize - p.pixels[number/batchSize] |= (0b1 << (number % batchSize)) -} - -func (p Plane) Marked(x, y uint) bool { - return p.marked(x + y*p.Width) - // number := x + y*p.width - // index := number / batchSize - // bit := number % batchSize - // return p.pixels[index]&(0b1< 0 -} - -func (p Plane) marked(number uint) bool { - // index := number / batchSize - // bit := number % batchSize - return p.pixels[number/batchSize]&(0b1<<(number%batchSize)) > 0 -} - -func (p Plane) Circle(x, y int, r float64) { - plotX := 0 - plotY := int(math.Ceil(r)) - delta := 3 - 2*plotY - lastY := plotY - for plotX <= plotY { - p.octant(x, y, plotX, plotY) - if plotY < lastY { - for lineX := 0; lineX < plotX; lineX++ { - p.octant(x, y, lineX, plotY) - } - lastY = plotY - } - if delta < 0 { - delta += 4*plotX + 6 - } else { - delta += 4*(plotX-plotY) + 10 - plotY -= 1 - } - plotX += 1 - } - for fillX := 0; fillX < plotX; fillX++ { - for fillY := 0; fillY <= fillX; fillY++ { - p.octant(x, y, fillX, fillY) - } - } -} - -func (p Plane) CircleAdjacent(x, y int, r float64) { - plotX := 0 - plotY := int(math.Ceil(r)) - delta := 1 - 2*plotY - err := 0 - for plotX <= plotY { - p.octant(x, y, plotX, plotY) - err = 2*(delta+plotY) - 1 - if delta < 0 && err <= 0 { - plotX += 1 - delta += 2*plotX + 1 - continue - } - if delta > 0 && err > 0 { - plotY -= 1 - delta -= 2*plotY + 1 - continue - } - plotX += 1 - plotY -= 1 - delta += 2 * (plotX - plotY) - } -} - -func (p Plane) octant(x, y int, plotX, plotY int) { - p.Mark(x+plotX, y+plotY) - p.Mark(x+plotX, y-plotY) - p.Mark(x-plotX, y+plotY) - p.Mark(x-plotX, y-plotY) - p.Mark(x+plotY, y+plotX) - p.Mark(x+plotY, y-plotX) - p.Mark(x-plotY, y+plotX) - p.Mark(x-plotY, y-plotX) -} - -func (p Plane) Clear() { - for i := range p.pixels { - p.pixels[i] &= 0 - } -} - -func (p Plane) String() string { - px := map[bool]string{true: "x", false: "_"} - var result string - // for y := 0; y < int(p.height); y++ { - // for x := 0; x < int(p.width); x++ { - // result += px[p.Marked(uint(x), uint(y))] + " " - // } - // result += "\n" - // } - // result += "\n" - cnt := 0 - for i := 0; i < len(p.pixels); i++ { - for bit := 0; bit < batchSize && cnt < int(p.Width*p.Height); bit++ { - result += fmt.Sprintf("%s ", px[p.pixels[i]&(0b1< 0]) - cnt++ - if cnt%int(p.Width) == 0 { - result += "\n" - } - } - } - return result -} diff --git a/pkg/generator/draw/draw_test.go b/pkg/generator/draw/draw_test.go deleted file mode 100644 index 0a60269..0000000 --- a/pkg/generator/draw/draw_test.go +++ /dev/null @@ -1,82 +0,0 @@ -package draw_test - -import ( - "fmt" - "testing" - - "github.com/iliadenisov/galaxy/pkg/generator/draw" -) - -func Test_CreatePlot(t *testing.T) { - var pane = draw.New(10, 10) - if len(draw.PixelsHolder(&pane)) != 4 { - t.Errorf("wrong Pane data size, expected: %d given: %d", 4, len(draw.PixelsHolder(&pane))) - } - - pane = draw.New(1, 1) - if len(draw.PixelsHolder(&pane)) != 1 { - t.Errorf("wrong Pane data size, expected: %d given: %d", 4, len(draw.PixelsHolder(&pane))) - } - - pane = draw.New(32, 32) - if len(draw.PixelsHolder(&pane)) != 32 { - t.Errorf("wrong Pane data size, expected: %d given: %d", 4, len(draw.PixelsHolder(&pane))) - } -} - -func Test_Mark(t *testing.T) { - var size int = 7 - var pane = draw.New(uint(size), uint(size)) - for i := 0; i < int(size); i++ { - pane.Mark(0, i) - pane.Mark(i, 0) - pane.Mark(size-1, i) - pane.Mark(i, size-1) - pane.Mark(i, i) - pane.Mark(size-1-i, i) - } - - pixelsHolder := draw.PixelsHolder(&pane) - - if len(pixelsHolder) != 2 { - t.Errorf("expected len: %d given: %d", 2, len(pixelsHolder)) - } - - // if !pane.Marked(0, 0) { - // t.Errorf("should be marked at x=%d y=%d", 0, 0) - // } - - fmt.Println(pane) -} - -func Test_Cleat(t *testing.T) { - var pane = draw.New(10, 10) - pane.Mark(5, 5) - pane.Mark(0, 0) - pane.Mark(9, 9) - if !pane.Marked(0, 0) { - t.Errorf("should be marked at x=%d y=%d", 0, 0) - } - if !pane.Marked(5, 5) { - t.Errorf("should be marked at x=%d y=%d", 5, 5) - } - if !pane.Marked(9, 9) { - t.Errorf("should be marked at x=%d y=%d", 9, 9) - } - pane.Clear() - for _, holder := range draw.PixelsHolder(&pane) { - if holder != 0 { - t.Errorf("should be all bits clear") - } - } -} - -func Test_Circle(t *testing.T) { - var size int = 40 - var pane1 = draw.New(uint(size), uint(size)) - pane1.Circle(size/2+5, size/2-5, float64(size/2)-3) - fmt.Println(pane1) - var pane2 = draw.New(uint(size), uint(size)) - pane2.CircleAdjacent(size/2+20, size/2, float64(size/2)-5) - // fmt.Println(pane2) -} diff --git a/pkg/generator/draw/export_test.go b/pkg/generator/draw/export_test.go deleted file mode 100644 index 1c71f99..0000000 --- a/pkg/generator/draw/export_test.go +++ /dev/null @@ -1,3 +0,0 @@ -package draw - -var PixelsHolder = (*Plane).pixelsValue diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 61704a8..2301ab5 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -1,12 +1,11 @@ package generator import ( - "errors" "fmt" "math" "math/rand" - "github.com/iliadenisov/galaxy/pkg/generator/draw" + "github.com/iliadenisov/galaxy/pkg/bitmap" ) type Map struct { @@ -33,8 +32,11 @@ type PlanetarySystem struct { } type Plotter struct { - factor float64 - sectors draw.Plane + factor float64 + clearFn func() + circleFn func(x, y int, r float64) + freeCountFn func() int + freeNumberToCoordFn func(int) (int, int) } func Generate(param MapParameter) (result Map) { @@ -69,20 +71,16 @@ func Generate(param MapParameter) (result Map) { coord := result.newPlanet(float64(param.BigPlanets.MinDistanceHW)) planet := pl(coord, param.BigPlanets) result.addPlanet(planet) - // result.FreePlanets = append(result.FreePlanets, planet) } for player := 0; player < int(param.Players); player++ { fmt.Println("generating HW #", player) coord := result.newPlanet(float64(param.HW_MinDistance)) planet := Planet{Position: coord, Size: float64(param.HW_Size), Resources: float64(param.HW_Resources)} - // fmt.Println("HW: ", planet) result.HomePlanets[player] = PlanetarySystem{HW: planet} } - fmt.Println("free sectors left: ", len(result.plotter.freeSectors())) - - result.plotter.sectors.Clear() + result.plotter.clearFn() for _, hw := range result.HomePlanets { result.plotter.markNoGoZone(hw.HW.Position.X, hw.HW.Position.Y, 5) @@ -96,21 +94,16 @@ func Generate(param MapParameter) (result Map) { } - fmt.Println("free sectors after reset: ", len(result.plotter.freeSectors())) - return } func (m Map) newPlanet(deadZoneRaduis float64) Coordinate { - fs := m.plotter.freeSectors() - fmt.Println("free sectors: ", len(fs)) - fsCount := len(fs) + fsCount := m.plotter.freeCountFn() if fsCount == 0 { panic("no more space for planets") } next := rand.Intn(fsCount) - x := fs[next][0] - y := fs[next][1] + x, y := m.plotter.freeNumberToCoordFn(next) fmt.Println("planet on plot: x =", x, "y =", y) planetX := float64(x)*m.plotter.factor + rand.Float64()*m.plotter.factor planetY := float64(y)*m.plotter.factor + rand.Float64()*m.plotter.factor @@ -122,39 +115,35 @@ func (m *Map) addPlanet(planet Planet) { m.FreePlanets = append(m.FreePlanets, planet) } -func (p Plotter) freeSectors() (result [][]uint) { - result = make([][]uint, 0) - for x := uint(0); x < p.sectors.Width; x++ { - for y := uint(0); y < p.sectors.Height; y++ { - if !p.sectors.Marked(x, y) { - result = append(result, []uint{x, y}) - } - } - } - return -} - -func (p Plotter) markDeadZone(x, y int, radius float64) { - p.sectors.Circle(x, y, radius) -} - func (p Plotter) markNoGoZone(x, y float64, radius float64) { // TODO: test p.markDeadZone(int(x/p.factor), int(y/p.factor), radius) } +func (p Plotter) markDeadZone(x, y int, radius float64) { + p.circleFn(x, y, radius) +} + func NewMap(width, height, players uint) Map { var factor float64 = 1.0 - sectorsX := uint(float64(width) / factor) - sectorsY := uint(float64(height) / factor) + sectorsX := uint32(float64(width) / factor) + sectorsY := uint32(float64(height) / factor) + bm := bitmap.NewBitmap(sectorsX, sectorsY) return Map{ Width: width, Height: height, HomePlanets: make([]PlanetarySystem, players), plotter: Plotter{ - factor: factor, - sectors: draw.New(sectorsX, sectorsY)}} -} - -func errfmt(message string) error { - return errors.New("generator: " + message) + factor: factor, + clearFn: bm.Clear, + circleFn: func(x, y int, r float64) { bm.Circle(x, y, r, true) }, + freeCountFn: bm.FreeCount, + freeNumberToCoordFn: func(n int) (x int, y int) { + x, y, err := bm.GetFreeN(n) + if err != nil { + panic(err) + } + return + }, + }, + } }