added options -p and -n, using images not draw rects anymore

This commit is contained in:
2024-05-22 14:06:33 +02:00
parent 39d9eeeba9
commit c3b6139e19
3 changed files with 82 additions and 34 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
gameoflife gameoflife
bak

View File

@@ -15,7 +15,6 @@ You'll need the golang toolchain.
The game has a couple of commandline options: The game has a couple of commandline options:
```default ```default
Usage of ./gameoflife: Usage of ./gameoflife:
-c, --cellsize int cell size in pixels (default 8) -c, --cellsize int cell size in pixels (default 8)
-d, --debug show debug info -d, --debug show debug info
@@ -23,6 +22,8 @@ Usage of ./gameoflife:
-e, --empty start with an empty screen -e, --empty start with an empty screen
-H, --height int grid height in cells (default 40) -H, --height int grid height in cells (default 40)
-i, --invert invert colors (dead cell: black) -i, --invert invert colors (dead cell: black)
-n, --nogrid do not draw grid lines
-p, --paused do not start simulation (use space to start)
-r, --rule string game rule (default "B3/S23") -r, --rule string game rule (default "B3/S23")
-s, --show-evolution show evolution tracks -s, --show-evolution show evolution tracks
-t, --tps int game speed in ticks per second (default 60) -t, --tps int game speed in ticks per second (default 60)
@@ -35,6 +36,7 @@ While it runs, there are a couple of commands you can use:
* left mouse click: set a cell to alife * left mouse click: set a cell to alife
* right mouse click: set a cell to dead * right mouse click: set a cell to dead
* space: pause or resume the game * space: pause or resume the game
* while game is paused: press n to forward one step
* q: quit * q: quit
* up arrow: speed up * up arrow: speed up
* down arrow: slow down * down arrow: slow down

111
main.go
View File

@@ -27,17 +27,23 @@ type Grid struct {
Data [][]int Data [][]int
} }
type Images struct {
Black, White, Beige *ebiten.Image
}
type Game struct { type Game struct {
Grids []*Grid // 2 grids: one current, one next Grids []*Grid // 2 grids: one current, one next
History *Grid History *Grid
Index int // points to current grid Index int // points to current grid
Width, Height, Cellsize, Density int Width, Height, Cellsize, Density int
ScreenWidth, ScreenHeight int ScreenWidth, ScreenHeight int
Generations int Generations int
Black, White, Grey, Beige color.RGBA Black, White, Grey, Beige color.RGBA
Speed int Speed int
Debug, Paused, Empty, Invert, ShowEvolution bool Debug, Paused, Empty, Invert bool
Rule *Rule ShowEvolution, NoGrid, RunOneStep bool
Rule *Rule
Tiles Images
} }
func (game *Game) Layout(outsideWidth, outsideHeight int) (int, int) { func (game *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
@@ -101,6 +107,10 @@ func (game *Game) UpdateCells() {
// global counter // global counter
game.Generations++ game.Generations++
if game.RunOneStep {
game.RunOneStep = false
}
} }
// a GOL rule // a GOL rule
@@ -198,30 +208,24 @@ func (game *Game) CheckInput() {
ebiten.SetTPS(game.Speed) ebiten.SetTPS(game.Speed)
} }
} }
if game.Paused {
if inpututil.IsKeyJustPressed(ebiten.KeyN) {
game.RunOneStep = true
}
}
} }
func (game *Game) Update() error { func (game *Game) Update() error {
game.CheckInput() game.CheckInput()
if !game.Paused { if !game.Paused || game.RunOneStep {
game.UpdateCells() game.UpdateCells()
} }
return nil return nil
} }
// fill a cell with the given color
func FillCell(screen *ebiten.Image, x, y, cellsize int, col color.RGBA) {
vector.DrawFilledRect(
screen,
float32(x*cellsize+1),
float32(y*cellsize+1),
float32(cellsize-1),
float32(cellsize-1),
col, false,
)
}
// set a cell to alive or dead // set a cell to alive or dead
func ToggleCell(game *Game, alive int) { func ToggleCell(game *Game, alive int) {
xPX, yPX := ebiten.CursorPosition() xPX, yPX := ebiten.CursorPosition()
@@ -239,18 +243,27 @@ func (game *Game) Draw(screen *ebiten.Image) {
// we fill the whole screen with a background color, the cells // we fill the whole screen with a background color, the cells
// themselfes will be 1px smaller as their nominal size, producing // themselfes will be 1px smaller as their nominal size, producing
// a nice grey grid with grid lines // a nice grey grid with grid lines
screen.Fill(game.Grey) op := &ebiten.DrawImageOptions{}
if game.NoGrid {
screen.Fill(game.White)
} else {
screen.Fill(game.Grey)
}
for y := 0; y < game.Height; y++ { for y := 0; y < game.Height; y++ {
for x := 0; x < game.Width; x++ { for x := 0; x < game.Width; x++ {
op.GeoM.Reset()
op.GeoM.Translate(float64(x*game.Cellsize), float64(y*game.Cellsize))
switch game.Grids[game.Index].Data[y][x] { switch game.Grids[game.Index].Data[y][x] {
case 1: case 1:
FillCell(screen, x, y, game.Cellsize, game.Black)
screen.DrawImage(game.Tiles.Black, op)
case 0: case 0:
if game.History.Data[y][x] == 1 && game.ShowEvolution { if game.History.Data[y][x] == 1 && game.ShowEvolution {
FillCell(screen, x, y, game.Cellsize, game.Beige) screen.DrawImage(game.Tiles.Beige, op)
} else { } else {
FillCell(screen, x, y, game.Cellsize, game.White) screen.DrawImage(game.Tiles.White, op)
} }
} }
} }
@@ -270,11 +283,7 @@ func (game *Game) Draw(screen *ebiten.Image) {
} }
} }
func (game *Game) Init() { func (game *Game) InitGrid() {
// setup the game
game.ScreenWidth = game.Cellsize * game.Width
game.ScreenHeight = game.Cellsize * game.Height
grid := &Grid{Data: make([][]int, game.Height)} grid := &Grid{Data: make([][]int, game.Height)}
gridb := &Grid{Data: make([][]int, game.Height)} gridb := &Grid{Data: make([][]int, game.Height)}
history := &Grid{Data: make([][]int, game.Height)} history := &Grid{Data: make([][]int, game.Height)}
@@ -299,7 +308,22 @@ func (game *Game) Init() {
} }
game.History = history game.History = history
}
// fill a cell with the given color
func FillCell(tile *ebiten.Image, cellsize int, col color.RGBA) {
vector.DrawFilledRect(
tile,
float32(1),
float32(1),
float32(cellsize-1),
float32(cellsize-1),
col, false,
)
}
// prepare tile images
func (game *Game) InitTiles() {
game.Black = color.RGBA{0, 0, 0, 0xff} game.Black = color.RGBA{0, 0, 0, 0xff}
game.White = color.RGBA{200, 200, 200, 0xff} game.White = color.RGBA{200, 200, 200, 0xff}
game.Grey = color.RGBA{128, 128, 128, 0xff} game.Grey = color.RGBA{128, 128, 128, 0xff}
@@ -308,9 +332,28 @@ func (game *Game) Init() {
if game.Invert { if game.Invert {
game.White = color.RGBA{0, 0, 0, 0xff} game.White = color.RGBA{0, 0, 0, 0xff}
game.Black = color.RGBA{200, 200, 200, 0xff} game.Black = color.RGBA{200, 200, 200, 0xff}
game.Beige = color.RGBA{0x8b, 0x1a, 0x1a, 0xff} //game.Beige = color.RGBA{0x8b, 0x1a, 0x1a, 0xff}
game.Beige = color.RGBA{0x30, 0x1c, 0x11, 0xff}
} }
game.Tiles.Beige = ebiten.NewImage(game.Cellsize, game.Cellsize)
game.Tiles.Black = ebiten.NewImage(game.Cellsize, game.Cellsize)
game.Tiles.White = ebiten.NewImage(game.Cellsize, game.Cellsize)
cellsize := game.ScreenWidth / game.Cellsize
FillCell(game.Tiles.Beige, cellsize, game.Beige)
FillCell(game.Tiles.Black, cellsize, game.Black)
FillCell(game.Tiles.White, cellsize, game.White)
}
func (game *Game) Init() {
// setup the game
game.ScreenWidth = game.Cellsize * game.Width
game.ScreenHeight = game.Cellsize * game.Height
game.InitGrid()
game.InitTiles()
game.Index = 0 game.Index = 0
} }
@@ -347,7 +390,9 @@ func main() {
pflag.IntVarP(&game.Density, "density", "D", 10, "density of random cells") pflag.IntVarP(&game.Density, "density", "D", 10, "density of random cells")
pflag.StringVarP(&rule, "rule", "r", "B3/S23", "game rule") pflag.StringVarP(&rule, "rule", "r", "B3/S23", "game rule")
pflag.BoolVarP(&showversion, "version", "v", false, "show version") pflag.BoolVarP(&showversion, "version", "v", false, "show version")
pflag.BoolVarP(&game.Paused, "paused", "p", false, "do not start simulation (use space to start)")
pflag.BoolVarP(&game.Debug, "debug", "d", false, "show debug info") pflag.BoolVarP(&game.Debug, "debug", "d", false, "show debug info")
pflag.BoolVarP(&game.NoGrid, "nogrid", "n", false, "do not draw grid lines")
pflag.BoolVarP(&game.Empty, "empty", "e", false, "start with an empty screen") pflag.BoolVarP(&game.Empty, "empty", "e", false, "start with an empty screen")
pflag.BoolVarP(&game.Invert, "invert", "i", false, "invert colors (dead cell: black)") pflag.BoolVarP(&game.Invert, "invert", "i", false, "invert colors (dead cell: black)")
pflag.BoolVarP(&game.ShowEvolution, "show-evolution", "s", false, "show evolution tracks") pflag.BoolVarP(&game.ShowEvolution, "show-evolution", "s", false, "show evolution tracks")