sdl2-life

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

commit 513af793ccde5a9069b1b3f36e23101b6775bd54
parent 8d765322abc3dd25ca669da5e80c7613ee64cf43
Author: Brian C. Lane <bcl@brianlane.com>
Date:   Wed, 27 Nov 2019 17:04:29 -0800

Parse the rule from the cmdline

You can now pass a game rule using -rule, for example the default is
-rule B3/S23 or you can pass -rule B36/S23 for the HighLife variation.

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

diff --git a/main.go b/main.go @@ -5,6 +5,8 @@ import ( "fmt" "log" "math/rand" + "strconv" + "strings" "time" "github.com/veandco/go-sdl2/sdl" @@ -104,11 +106,6 @@ func (g *LifeGame) cleanup() { // InitializeCells resets the world to a random state func (g *LifeGame) InitializeCells() { - var err error - if g.birth, g.stayAlive, err = ParseRulestring(cfg.Rule); err != nil { - log.Fatalf("Failed to parse the rule string (%s): %s\n", cfg.Rule, err) - } - if cfg.Seed == 0 { seed := time.Now().UnixNano() log.Printf("seed = %d\n", seed) @@ -332,6 +329,10 @@ func InitializeGame() *LifeGame { game := &LifeGame{} var err error + if game.birth, game.stayAlive, err = ParseRulestring(cfg.Rule); err != nil { + log.Fatalf("Failed to parse the rule string (%s): %s\n", cfg.Rule, err) + } + if err = sdl.Init(sdl.INIT_EVERYTHING); err != nil { log.Fatalf("Problem initializing SDL: %s", err) } @@ -383,14 +384,80 @@ func InitializeGame() *LifeGame { return game } +// Parse digits into a map of ints from 0-9 +// +// Returns an error if they aren't digits, or if there are more than 10 of them +func parseDigits(digits string) (map[int]bool, error) { + ruleMap := make(map[int]bool, 10) + + var errors bool + var err error + var value int + if value, err = strconv.Atoi(digits); err != nil { + log.Printf("%s must be digits from 0-9\n", digits) + errors = true + } + if value > 9999999999 { + log.Printf("%d has more than 10 digits", value) + errors = true + } + if errors { + return nil, fmt.Errorf("ERROR: Problem parsing digits") + } + + // Add the digits to the map (order doesn't matter) + for value > 0 { + ruleMap[value%10] = true + value = value / 10 + } + + return ruleMap, nil +} + // ParseRulestring parses the rules that control the game // // Rulestrings are of the form Bn.../Sn... which list the number of neighbors to birth a new one, // and the number of neighbors to stay alive. // -func ParseRulestring(rule string) (birth map[int]bool, stayAlive map[int]bool, err error) { +func ParseRulestring(rule string) (birth map[int]bool, stayAlive map[int]bool, e error) { + var errors bool + + // Make sure the rule starts with a B + if !strings.HasPrefix(rule, "B") { + log.Println("ERROR: Rule must start with a 'B'") + errors = true + } + + // Make sure the rule has a /S in it + if !strings.Contains(rule, "/S") { + log.Println("ERROR: Rule must contain /S") + errors = true + } + if errors { + return nil, nil, fmt.Errorf("The Rule string should look similar to: B2/S23") + } + + // Split on the / returning 2 results like Bnn and Snn + fields := strings.Split(rule, "/") + if len(fields) != 2 { + return nil, nil, fmt.Errorf("ERROR: Problem splitting rule on /") + } + + var err error + // Convert the values to maps + birth, err = parseDigits(strings.TrimPrefix(fields[0], "B")) + if err != nil { + errors = true + } + stayAlive, err = parseDigits(strings.TrimPrefix(fields[1], "S")) + if err != nil { + errors = true + } + if errors { + return nil, nil, fmt.Errorf("ERROR: Problem with Birth or Stay alive values") + } - return map[int]bool{3: true}, map[int]bool{2: true, 3: true}, nil + return birth, stayAlive, nil } func main() {