renamed, added logo

This commit is contained in:
2024-05-23 18:25:02 +02:00
parent 62c38be1df
commit 19e45c9f60
12 changed files with 193 additions and 43 deletions

BIN
.github/assets/gol.xcf vendored Normal file

Binary file not shown.

BIN
.github/assets/golsky.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

7
.github/assets/track.pal vendored Normal file
View File

@@ -0,0 +1,7 @@
JASC-PAL
0100
4
25 17 0
43 27 0
66 35 0
82 38 0

BIN
.github/assets/track.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 713 B

7
.github/assets/tracklight.pal vendored Normal file
View File

@@ -0,0 +1,7 @@
JASC-PAL
0100
4
255 195 97
255 211 140
255 227 181
255 240 224

BIN
.github/assets/tracklight.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 735 B

2
.gitignore vendored
View File

@@ -1,3 +1,3 @@
gameoflife golsky
bak bak
dump* dump*

87
Makefile Normal file
View File

@@ -0,0 +1,87 @@
# Copyright © 2024 Thomas von Dein
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# no need to modify anything below
tool = golsky
VERSION = $(shell grep VERSION config.go | head -1 | cut -d '"' -f2)
archs = darwin freebsd linux windows
PREFIX = /usr/local
UID = root
GID = 0
HAVE_POD := $(shell pod2text -h 2>/dev/null)
all: buildlocal
buildlocal:
go build -o $(tool)
install: buildlocal
install -d -o $(UID) -g $(GID) $(PREFIX)/bin
install -d -o $(UID) -g $(GID) $(PREFIX)/man/man1
install -o $(UID) -g $(GID) -m 555 $(tool) $(PREFIX)/sbin/
install -o $(UID) -g $(GID) -m 444 $(tool).1 $(PREFIX)/man/man1/
clean:
rm -rf $(tool) coverage.out testdata t/out
test: clean
mkdir -p t/out
go test ./... $(ARGS)
testlint: test lint
lint:
golangci-lint run
lint-full:
golangci-lint run --enable-all --exclude-use-default --disable exhaustivestruct,exhaustruct,depguard,interfacer,deadcode,golint,structcheck,scopelint,varcheck,ifshort,maligned,nosnakecase,godot,funlen,gofumpt,cyclop,noctx,gochecknoglobals,paralleltest
testfuzzy: clean
go test -fuzz ./... $(ARGS)
singletest:
@echo "Call like this: make singletest TEST=TestPrepareColumns ARGS=-v"
go test -run $(TEST) $(ARGS)
cover-report:
go test ./... -cover -coverprofile=coverage.out
go tool cover -html=coverage.out
goupdate:
go get -t -u=patch ./...
buildall:
./mkrel.sh $(tool) $(VERSION)
release: buildall
gh release create v$(VERSION) --generate-notes releases/*
show-versions: buildlocal
@echo "### golsky version:"
@./golsky -V
@echo
@echo "### go module versions:"
@go list -m all
@echo
@echo "### go version used for building:"
@grep -m 1 go go.mod
# lint:
# golangci-lint run -p bugs -p unused

View File

@@ -1,13 +1,21 @@
# Conway's game of life # golsky - Conway's game of life written in GO
I wanted to play around a little bit with GOL in golang and here's the ![Golsky Logo](https://github.com/TLINDEN/golsky/blob/main/.github/assets/golsky.png)
result. It's a simple game using
[![License](https://img.shields.io/badge/license-GPL-blue.svg)](https://github.com/tlinden/golsky/blob/master/LICENSE)
[![Go Report Card](https://goreportcard.com/badge/github.com/tlinden/golsky)](https://goreportcard.com/report/github.com/tlinden/golsky)
I wanted to play around a little bit with [**Conways Game of
Life**](https://conwaylife.com/)
in golang and here's the result. It's a simple game using
[ebitengine](https://github.com/hajimehoshi/ebiten/). [ebitengine](https://github.com/hajimehoshi/ebiten/).
# Features # Features
* flexible parameters as grid and cell size * flexible parameters as grid and cell size
* colors can be inverted * colors can be inverted
* evolution tracks can be shown, with age the cells color fades and
old life cells will be drawn in red
* game grid lines can be enabled or disabled * game grid lines can be enabled or disabled
* game speed can be adjusted on startup and in-game * game speed can be adjusted on startup and in-game
* you can zoom in and out of the canvas and move it around * you can zoom in and out of the canvas and move it around
@@ -19,7 +27,12 @@ result. It's a simple game using
* you can paint your own patterns in the game * you can paint your own patterns in the game
* the game can also be started with an empty grid, which is easier to paint patterns * the game can also be started with an empty grid, which is easier to paint patterns
# Build and install # Install
In the github releases page you can find ready to use binaries for
your OS. Just download the one you need and use it.
# Build from source
Just execute: `go build .` and use the resulting executable. Just execute: `go build .` and use the resulting executable.
@@ -30,7 +43,7 @@ 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 ./golsky:
-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
-D, --density int density of random cells (default 10) -D, --density int density of random cells (default 10)
@@ -64,7 +77,7 @@ While it runs, there are a couple of commands you can use:
# Report bugs # Report bugs
[Please open an issue](https://github.com/TLINDEN/gameoflife/issues). Thanks! [Please open an issue](https://github.com/TLINDEN/golsky/issues). Thanks!
# License # License

100
game.go
View File

@@ -11,35 +11,36 @@ import (
"github.com/hajimehoshi/ebiten/v2/ebitenutil" "github.com/hajimehoshi/ebiten/v2/ebitenutil"
"github.com/hajimehoshi/ebiten/v2/inpututil" "github.com/hajimehoshi/ebiten/v2/inpututil"
"github.com/hajimehoshi/ebiten/v2/vector" "github.com/hajimehoshi/ebiten/v2/vector"
"github.com/tlinden/gameoflife/rle" "github.com/tlinden/golsky/rle"
"golang.org/x/image/math/f64" "golang.org/x/image/math/f64"
) )
type Images struct { type Images struct {
Black, White, Beige *ebiten.Image Black, White, Age1, Age2, Age3, Age4, Old *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 // holds state of past dead cells for evolution tracks History *Grid // holds state of past dead cells for evolution tracks
Index int // points to current grid Index int // points to current grid
Width, Height, Cellsize, Density int // measurements Width, Height, Cellsize, Density int // measurements
ScreenWidth, ScreenHeight int ScreenWidth, ScreenHeight int
Generations int64 // Stats Generations int64 // Stats
Black, White, Grey, Beige color.RGBA Black, White, Grey, Old color.RGBA
TPG int // ticks per generation/game speed, 1==max AgeColor1, AgeColor2, AgeColor3, AgeColor4 color.RGBA
TicksElapsed int // tick counter for game speed TPG int // ticks per generation/game speed, 1==max
Debug, Paused, Empty, Invert bool // game modi TicksElapsed int // tick counter for game speed
ShowEvolution, NoGrid, RunOneStep bool // flags Debug, Paused, Empty, Invert bool // game modi
Rule *Rule // which rule to use, default: B3/S23 ShowEvolution, NoGrid, RunOneStep bool // flags
Tiles Images // pre-computed tiles for dead and alife cells Rule *Rule // which rule to use, default: B3/S23
RLE *rle.RLE // loaded GOL pattern from RLE file Tiles Images // pre-computed tiles for dead and alife cells
Camera Camera // for zoom+move RLE *rle.RLE // loaded GOL pattern from RLE file
World *ebiten.Image // actual image we render to Camera Camera // for zoom+move
WheelTurned bool // when user turns wheel multiple times, zoom faster World *ebiten.Image // actual image we render to
Dragging bool // middle mouse is pressed, move canvas WheelTurned bool // when user turns wheel multiple times, zoom faster
LastCursorPos []int // used to check if the user is dragging Dragging bool // middle mouse is pressed, move canvas
Statefile string // load game state from it if non-nil LastCursorPos []int // used to check if the user is dragging
Statefile string // load game state from it if non-nil
} }
func (game *Game) Layout(outsideWidth, outsideHeight int) (int, int) { func (game *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
@@ -91,7 +92,10 @@ func (game *Game) UpdateCells() {
// change state of current cell in next grid // change state of current cell in next grid
game.Grids[next].Data[y][x] = nextstate game.Grids[next].Data[y][x] = nextstate
if state == Alive && nextstate == Dead { // set history to current generation so we can infer the
// age of the cell's state during rendering and use it to
// deduce the color to use if evolution tracking is enabled
if state != nextstate {
game.History.Data[y][x] = game.Generations game.History.Data[y][x] = game.Generations
} }
} }
@@ -272,13 +276,27 @@ func (game *Game) Draw(screen *ebiten.Image) {
op.GeoM.Reset() op.GeoM.Reset()
op.GeoM.Translate(float64(x*game.Cellsize), float64(y*game.Cellsize)) op.GeoM.Translate(float64(x*game.Cellsize), float64(y*game.Cellsize))
age := game.Generations - game.History.Data[y][x]
switch game.Grids[game.Index].Data[y][x] { switch game.Grids[game.Index].Data[y][x] {
case 1: case 1:
if age > 50 && game.ShowEvolution {
game.World.DrawImage(game.Tiles.Black, op) game.World.DrawImage(game.Tiles.Old, op)
} else {
game.World.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 {
game.World.DrawImage(game.Tiles.Beige, op) switch {
case age < 10:
game.World.DrawImage(game.Tiles.Age1, op)
case age < 20:
game.World.DrawImage(game.Tiles.Age2, op)
case age < 30:
game.World.DrawImage(game.Tiles.Age3, op)
default:
game.World.DrawImage(game.Tiles.Age4, op)
}
} else { } else {
game.World.DrawImage(game.Tiles.White, op) game.World.DrawImage(game.Tiles.White, op)
} }
@@ -365,25 +383,43 @@ func (game *Game) InitGrid(grid *Grid) {
// prepare tile images // prepare tile images
func (game *Game) InitTiles() { func (game *Game) InitTiles() {
game.Grey = color.RGBA{128, 128, 128, 0xff}
game.Old = color.RGBA{255, 30, 30, 0xff}
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.AgeColor1 = color.RGBA{255, 195, 97, 0xff} // FIXME: use slice!
game.Beige = color.RGBA{0xff, 0xf8, 0xdc, 0xff} game.AgeColor2 = color.RGBA{255, 211, 140, 0xff}
game.AgeColor3 = color.RGBA{255, 227, 181, 0xff}
game.AgeColor4 = color.RGBA{255, 240, 224, 0xff}
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{0x30, 0x1c, 0x11, 0xff}
game.AgeColor1 = color.RGBA{82, 38, 0, 0xff}
game.AgeColor2 = color.RGBA{66, 35, 0, 0xff}
game.AgeColor3 = color.RGBA{43, 27, 0, 0xff}
game.AgeColor4 = color.RGBA{25, 17, 0, 0xff}
} }
game.Tiles.Beige = ebiten.NewImage(game.Cellsize, game.Cellsize)
game.Tiles.Black = ebiten.NewImage(game.Cellsize, game.Cellsize) game.Tiles.Black = ebiten.NewImage(game.Cellsize, game.Cellsize)
game.Tiles.White = ebiten.NewImage(game.Cellsize, game.Cellsize) game.Tiles.White = ebiten.NewImage(game.Cellsize, game.Cellsize)
game.Tiles.Old = ebiten.NewImage(game.Cellsize, game.Cellsize)
game.Tiles.Age1 = ebiten.NewImage(game.Cellsize, game.Cellsize)
game.Tiles.Age2 = ebiten.NewImage(game.Cellsize, game.Cellsize)
game.Tiles.Age3 = ebiten.NewImage(game.Cellsize, game.Cellsize)
game.Tiles.Age4 = ebiten.NewImage(game.Cellsize, game.Cellsize)
cellsize := game.ScreenWidth / game.Cellsize cellsize := game.ScreenWidth / game.Cellsize
FillCell(game.Tiles.Beige, cellsize, game.Beige)
FillCell(game.Tiles.Black, cellsize, game.Black) FillCell(game.Tiles.Black, cellsize, game.Black)
FillCell(game.Tiles.White, cellsize, game.White) FillCell(game.Tiles.White, cellsize, game.White)
FillCell(game.Tiles.Old, cellsize, game.Old)
FillCell(game.Tiles.Age1, cellsize, game.AgeColor1)
FillCell(game.Tiles.Age2, cellsize, game.AgeColor2)
FillCell(game.Tiles.Age3, cellsize, game.AgeColor3)
FillCell(game.Tiles.Age4, cellsize, game.AgeColor4)
} }
func (game *Game) Init() { func (game *Game) Init() {

2
go.mod
View File

@@ -1,4 +1,4 @@
module github.com/tlinden/gameoflife module github.com/tlinden/golsky
go 1.22 go 1.22

View File

@@ -5,14 +5,14 @@ import (
"log" "log"
"os" "os"
"github.com/tlinden/gameoflife/rle" "github.com/tlinden/golsky/rle"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
const ( const (
VERSION = "v0.0.4" VERSION = "v0.0.5"
Alive = 1 Alive = 1
Dead = 0 Dead = 0
) )
@@ -64,7 +64,7 @@ func main() {
pflag.Parse() pflag.Parse()
if showversion { if showversion {
fmt.Printf("This is gameoflife version %s\n", VERSION) fmt.Printf("This is golsky version %s\n", VERSION)
os.Exit(0) os.Exit(0)
} }