refactored grid stuff, fixed font size calculation

This commit is contained in:
2024-05-30 10:11:44 +02:00
parent 56880014eb
commit 1ec4b9e257
3 changed files with 78 additions and 52 deletions

13
game.go
View File

@@ -5,11 +5,11 @@ import (
) )
type Game struct { type Game struct {
ScreenWidth, ScreenHeight, Cellsize int ScreenWidth, ScreenHeight, ReadlWidth, Cellsize int
Scenes map[SceneName]Scene Scenes map[SceneName]Scene
CurrentScene SceneName CurrentScene SceneName
Config *Config Config *Config
Scale int Scale float32
} }
func NewGame(config *Config, startscene SceneName) *Game { func NewGame(config *Config, startscene SceneName) *Game {
@@ -37,7 +37,8 @@ func (game *Game) GetCurrentScene() Scene {
} }
func (game *Game) Layout(outsideWidth, outsideHeight int) (int, int) { func (game *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
game.Scale = outsideWidth / 100 game.ReadlWidth = outsideWidth
game.Scale = float32(game.ScreenWidth) / float32(outsideWidth)
return game.ScreenWidth, game.ScreenHeight return game.ScreenWidth, game.ScreenHeight
} }

52
grid.go
View File

@@ -9,6 +9,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/tlinden/golsky/rle"
) )
type Grid struct { type Grid struct {
@@ -34,6 +36,7 @@ func NewGrid(width, height, density int, empty bool) *Grid {
return grid return grid
} }
// Create a 1:1 copy
func (grid *Grid) Clone() *Grid { func (grid *Grid) Clone() *Grid {
newgrid := &Grid{} newgrid := &Grid{}
@@ -44,6 +47,7 @@ func (grid *Grid) Clone() *Grid {
return newgrid return newgrid
} }
// delete all contents
func (grid *Grid) Clear() { func (grid *Grid) Clear() {
for y := range grid.Data { for y := range grid.Data {
for x := range grid.Data[y] { for x := range grid.Data[y] {
@@ -52,6 +56,7 @@ func (grid *Grid) Clear() {
} }
} }
// initialize with random life cells using the given density
func (grid *Grid) FillRandom(game *ScenePlay) { func (grid *Grid) FillRandom(game *ScenePlay) {
if !grid.Empty { if !grid.Empty {
for y := range grid.Data { for y := range grid.Data {
@@ -64,16 +69,28 @@ func (grid *Grid) FillRandom(game *ScenePlay) {
} }
} }
func GetFilename(generations int64) string { // initialize using a given RLE pattern
now := time.Now() func (grid *Grid) LoadRLE(pattern *rle.RLE) {
return fmt.Sprintf("dump-%s-%d.gol", now.Format("20060102150405"), generations) if pattern != nil {
} startX := (grid.Width / 2) - (pattern.Width / 2)
startY := (grid.Height / 2) - (pattern.Height / 2)
func GetFilenameRLE(generations int64) string { var y, x int
now := time.Now()
return fmt.Sprintf("rect-%s-%d.rle", now.Format("20060102150405"), generations) for rowIndex, patternRow := range pattern.Pattern {
for colIndex := range patternRow {
if pattern.Pattern[rowIndex][colIndex] > 0 {
x = colIndex + startX
y = rowIndex + startY
grid.Data[y][x] = 1
}
}
}
}
} }
// save the contents of the whole grid as a simple mcell alike
// file. One line per row, 0 for dead and 1 for life cell.
func (grid *Grid) SaveState(filename string) error { func (grid *Grid) SaveState(filename string) error {
file, err := os.Create(filename) file, err := os.Create(filename)
if err != nil { if err != nil {
@@ -81,7 +98,7 @@ func (grid *Grid) SaveState(filename string) error {
} }
defer file.Close() defer file.Close()
for y, _ := range grid.Data { for y := range grid.Data {
for _, cell := range grid.Data[y] { for _, cell := range grid.Data[y] {
_, err := file.WriteString(strconv.FormatInt(cell, 10)) _, err := file.WriteString(strconv.FormatInt(cell, 10))
if err != nil { if err != nil {
@@ -94,6 +111,7 @@ func (grid *Grid) SaveState(filename string) error {
return nil return nil
} }
// the reverse of the above, load a mcell file
func LoadState(filename string) (*Grid, error) { func LoadState(filename string) (*Grid, error) {
fd, err := os.Open(filename) fd, err := os.Open(filename)
if err != nil { if err != nil {
@@ -139,8 +157,9 @@ func LoadState(filename string) (*Grid, error) {
} }
if explen != length { if explen != length {
return nil, fmt.Errorf(fmt.Sprintf("all rows must be in the same length, got: %d, expected: %d", return nil, fmt.Errorf(
length, explen)) fmt.Sprintf("all rows must be in the same length, got: %d, expected: %d",
length, explen))
} }
rows++ rows++
@@ -151,3 +170,14 @@ func LoadState(filename string) (*Grid, error) {
return grid, nil return grid, nil
} }
// generate filenames for dumps
func GetFilename(generations int64) string {
now := time.Now()
return fmt.Sprintf("dump-%s-%d.gol", now.Format("20060102150405"), generations)
}
func GetFilenameRLE(generations int64) string {
now := time.Now()
return fmt.Sprintf("rect-%s-%d.rle", now.Format("20060102150405"), generations)
}

View File

@@ -26,7 +26,7 @@ type ScenePlay struct {
Whoami SceneName Whoami SceneName
Grids []*Grid // 2 grids: one current, one next Grids []*Grid // 2 grids: one current, one next
History *Grid // holds state of past dead cells for evolution tracks History *Grid // holds state of past dead cells for evolution traces
Index int // points to current grid Index int // points to current grid
Generations int64 // Stats Generations int64 // Stats
Black, White, Grey, Old color.RGBA Black, White, Grey, Old color.RGBA
@@ -125,7 +125,7 @@ func (scene *ScenePlay) UpdateCells() {
// set history to current generation so we can infer the // set history to current generation so we can infer the
// age of the cell's state during rendering and use it to // age of the cell's state during rendering and use it to
// deduce the color to use if evolution tracking is enabled // deduce the color to use if evolution tracing is enabled
if state != nextstate { if state != nextstate {
scene.History.Data[y][x] = scene.Generations scene.History.Data[y][x] = scene.Generations
} }
@@ -401,22 +401,28 @@ func (scene *ScenePlay) Draw(screen *ebiten.Image) {
op.GeoM.Translate(0, 0) op.GeoM.Translate(0, 0)
scene.World.DrawImage(scene.Cache, op) scene.World.DrawImage(scene.Cache, op)
var age int64
for y := 0; y < scene.Config.Height; y++ { for y := 0; y < scene.Config.Height; y++ {
for x := 0; x < scene.Config.Width; x++ { for x := 0; x < scene.Config.Width; x++ {
op.GeoM.Reset() op.GeoM.Reset()
op.GeoM.Translate(float64(x*scene.Config.Cellsize), float64(y*scene.Config.Cellsize)) op.GeoM.Translate(
float64(x*scene.Config.Cellsize),
float64(y*scene.Config.Cellsize),
)
age := scene.Generations - scene.History.Data[y][x] age = scene.Generations - scene.History.Data[y][x]
switch scene.Grids[scene.Index].Data[y][x] { switch scene.Grids[scene.Index].Data[y][x] {
case 1: case Alive:
if age > 50 && scene.Config.ShowEvolution { if age > 50 && scene.Config.ShowEvolution {
scene.World.DrawImage(scene.Tiles.Old, op) scene.World.DrawImage(scene.Tiles.Old, op)
} else { } else {
scene.World.DrawImage(scene.Tiles.Black, op) scene.World.DrawImage(scene.Tiles.Black, op)
} }
case 0: case Dead:
// only draw dead cells in case evolution trace is enabled
if scene.History.Data[y][x] > 1 && scene.Config.ShowEvolution { if scene.History.Data[y][x] > 1 && scene.Config.ShowEvolution {
switch { switch {
case age < 10: case age < 10:
@@ -433,15 +439,20 @@ func (scene *ScenePlay) Draw(screen *ebiten.Image) {
} }
} }
scene.DrawMark(scene.World)
scene.Camera.Render(scene.World, screen)
scene.DrawDebug(screen)
}
func (scene *ScenePlay) DrawMark(screen *ebiten.Image) {
if scene.Markmode && scene.MarkTaken { if scene.Markmode && scene.MarkTaken {
x := float32(scene.Mark.X * scene.Config.Cellsize) x := float32(scene.Mark.X * scene.Config.Cellsize)
y := float32(scene.Mark.Y * scene.Config.Cellsize) y := float32(scene.Mark.Y * scene.Config.Cellsize)
w := float32((scene.Point.X - scene.Mark.X) * scene.Config.Cellsize) w := float32((scene.Point.X - scene.Mark.X) * scene.Config.Cellsize)
h := float32((scene.Point.Y - scene.Mark.Y) * scene.Config.Cellsize) h := float32((scene.Point.Y - scene.Mark.Y) * scene.Config.Cellsize)
// fmt.Printf("%d,%d=>%0.0f,%0.0f to %d,%d=>%0.0f,%0.0f\n",
// scene.Mark.X, scene.Mark.Y, x, y, scene.Point.X, scene.Point.Y, w, h)
vector.StrokeRect( vector.StrokeRect(
scene.World, scene.World,
x+1, y+1, x+1, y+1,
@@ -449,20 +460,21 @@ func (scene *ScenePlay) Draw(screen *ebiten.Image) {
1.0, scene.Old, false, 1.0, scene.Old, false,
) )
} }
}
scene.Camera.Render(scene.World, screen) func (scene *ScenePlay) DrawDebug(screen *ebiten.Image) {
if scene.Config.Debug { if scene.Config.Debug {
paused := "" paused := ""
if scene.Paused { if scene.Paused {
paused = "-- paused --" paused = "-- paused --"
} }
debug := fmt.Sprintf("FPS: %0.2f, TPG: %d, Mem: %0.2f MB, Generations: %d %s", debug := fmt.Sprintf(
ebiten.ActualTPS(), scene.TPG, GetMem(), scene.Generations, paused) "FPS: %0.2f, TPG: %d, Mem: %0.2fMB, Gen: %d, Scale: %.02f %s",
ebiten.ActualTPS(), scene.TPG, GetMem(), scene.Generations,
scene.Game.Scale, paused)
FontRenderer.Renderer.SetSizePx(10 + scene.Game.Scale/2) FontRenderer.Renderer.SetSizePx(10 + int(scene.Game.Scale*10))
FontRenderer.Renderer.SetTarget(screen) FontRenderer.Renderer.SetTarget(screen)
FontRenderer.Renderer.SetColor(scene.Black) FontRenderer.Renderer.SetColor(scene.Black)
@@ -471,31 +483,14 @@ func (scene *ScenePlay) Draw(screen *ebiten.Image) {
FontRenderer.Renderer.SetColor(scene.Old) FontRenderer.Renderer.SetColor(scene.Old)
FontRenderer.Renderer.Draw(debug, 30, 30) FontRenderer.Renderer.Draw(debug, 30, 30)
//ebitenutil.DebugPrint(screen, debug) fmt.Println(debug)
fmt.Println(debug, scene.Game.Scale)
} }
} }
// FIXME: move these into Grid
// load a pre-computed pattern from RLE file // load a pre-computed pattern from RLE file
func (scene *ScenePlay) InitPattern() { func (scene *ScenePlay) InitPattern() {
if scene.Config.RLE != nil { scene.Grids[0].LoadRLE(scene.Config.RLE)
startX := (scene.Config.Width / 2) - (scene.Config.RLE.Width / 2) scene.History.LoadRLE(scene.Config.RLE)
startY := (scene.Config.Height / 2) - (scene.Config.RLE.Height / 2)
var y, x int
for rowIndex, patternRow := range scene.Config.RLE.Pattern {
for colIndex := range patternRow {
if scene.Config.RLE.Pattern[rowIndex][colIndex] > 0 {
x = colIndex + startX
y = rowIndex + startY
scene.History.Data[y][x] = 1
scene.Grids[0].Data[y][x] = 1
}
}
}
}
} }
func (scene *ScenePlay) InitCache() { func (scene *ScenePlay) InitCache() {