sdl2-life

Conway's Game of Life with go-sdl2
git clone https://www.brianlane.com/git/sdl2-life
Log | Files | Refs | README

commit 356043566b7e4dde94e5303fddf50563d7909aea
parent 93f8ef6a0726d3491a60a37052cb80b8c30bc5e0
Author: Brian C. Lane <bcl@brianlane.com>
Date:   Sun, 12 Apr 2020 16:21:22 -0700

Add pattern file type detection

Support Life 1.05 and Plaintext formats initially.

https://www.conwaylife.com/wiki/Category:File_formats

Diffstat:
Mmain.go | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 74 insertions(+), 22 deletions(-)

diff --git a/main.go b/main.go @@ -1,6 +1,9 @@ +// sdl2-life +// by Brian C. Lane <bcl@brianlane.com> package main import ( + "bufio" "flag" "fmt" "log" @@ -20,30 +23,32 @@ const ( /* commandline flags */ type cmdlineArgs struct { - Width int // Width of window in pixels - Height int // Height of window in pixels - Rows int // Number of cell rows - Columns int // Number of cell columns - Seed int64 // Seed for PRNG - Border bool // Border around cells - Font string // Path to TTF to use for status bar - FontSize int // Size of font in points - Rule string // Rulestring to use - Fps int // Frames per Second + Width int // Width of window in pixels + Height int // Height of window in pixels + Rows int // Number of cell rows + Columns int // Number of cell columns + Seed int64 // Seed for PRNG + Border bool // Border around cells + Font string // Path to TTF to use for status bar + FontSize int // Size of font in points + Rule string // Rulestring to use + Fps int // Frames per Second + PatternFile string // File with initial pattern } /* commandline defaults */ var cfg = cmdlineArgs{ - Width: 500, - Height: 500, - Rows: 100, - Columns: 100, - Seed: 0, - Border: false, - Font: "", - FontSize: 14, - Rule: "B3/S23", - Fps: 10, + Width: 500, + Height: 500, + Rows: 100, + Columns: 100, + Seed: 0, + Border: false, + Font: "", + FontSize: 14, + Rule: "B3/S23", + Fps: 10, + PatternFile: "", } /* parseArgs handles parsing the cmdline args and setting values in the global cfg struct */ @@ -58,6 +63,7 @@ func parseArgs() { flag.IntVar(&cfg.FontSize, "font-size", cfg.FontSize, "Size of font in points") flag.StringVar(&cfg.Rule, "rule", cfg.Rule, "Rulestring Bn.../Sn... (B3/S23)") flag.IntVar(&cfg.Fps, "fps", cfg.Fps, "Frames per Second update rate (10fps)") + flag.StringVar(&cfg.PatternFile, "pattern", cfg.PatternFile, "File with initial pattern to load") flag.Parse() } @@ -111,8 +117,39 @@ func (g *LifeGame) cleanup() { sdl.Quit() } -// InitializeCells resets the world to a random state +// InitializeCells resets the world, either randomly or from a pattern file func (g *LifeGame) InitializeCells() { + g.age = 0 + + if len(cfg.PatternFile) == 0 { + g.InitializeRandomCells() + return + } + + // Read all of the pattern file for parsing + f, err := os.Open(cfg.PatternFile) + if err != nil { + log.Fatalf("Error reading pattern file: %s", err) + } + defer f.Close() + + scanner := bufio.NewScanner(f) + if !scanner.Scan() { + log.Fatalf("%s is empty.", cfg.PatternFile) + } + header := scanner.Text() + if strings.HasPrefix(header, "#Life 1.05") { + g.cells, err = ParseLife105(scanner) + } else if strings.HasPrefix(header, "#Life 1.06") { + log.Fatal("Life 1.06 file format is not supported") + } else if strings.HasPrefix(header, "!Name:") { + g.cells, err = ParsePlaintext(scanner) + } +} + +// InitializeRandomCells resets the world to a random state +func (g *LifeGame) InitializeRandomCells() { + if cfg.Seed == 0 { seed := time.Now().UnixNano() log.Printf("seed = %d\n", seed) @@ -122,7 +159,6 @@ func (g *LifeGame) InitializeCells() { rand.Seed(cfg.Seed) } - g.age = 0 g.cells = make([][]*Cell, cfg.Rows, cfg.Rows) for x := 0; x < cfg.Rows; x++ { for y := 0; y < cfg.Columns; y++ { @@ -135,6 +171,22 @@ func (g *LifeGame) InitializeCells() { } } +// ParseLife105 pattern file +// The header has already been read from the buffer when this is called +func ParseLife105(scanner *bufio.Scanner) ([][]*Cell, error) { + cells := make([][]*Cell, cfg.Rows, cfg.Rows) + + return cells, nil +} + +// ParsePlaintext pattern file +// The header has already been read from the buffer when this is called +func ParsePlaintext(scanner *bufio.Scanner) ([][]*Cell, error) { + cells := make([][]*Cell, cfg.Rows, cfg.Rows) + + return cells, nil +} + // checkState determines the state of the cell for the next tick of the game. func (g *LifeGame) checkState(c *Cell) { liveCount := g.liveNeighbors(c)