From 50cf1a0f6c220ac9bf5f246468739eddf73248e8 Mon Sep 17 00:00:00 2001 From: Alessandro Cifani Date: Mon, 13 Nov 2023 23:38:02 +0100 Subject: [PATCH] lib/game: custom life-like rules --- cmd/vita/main.go | 32 +++++++++++++++++++++++++------- lib/game/rules.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/cmd/vita/main.go b/cmd/vita/main.go index 22e7991..57317e4 100644 --- a/cmd/vita/main.go +++ b/cmd/vita/main.go @@ -3,6 +3,7 @@ package main import ( "flag" "fmt" + "strconv" "sync" "github.com/acifani/vita/lib/game" @@ -15,6 +16,8 @@ var ( population = flag.Int("pop", 45, "initial population percent of the universe") number = flag.Int("n", 1, "number of universes to run in parallel") rules = flag.String("rules", "conway", "rules to use for the universe") + b = flag.String("B", "3", "born") + s = flag.String("S", "23", "survive") ) func main() { @@ -35,11 +38,13 @@ func runSingleUniverse() { universe := game.NewUniverse(uint32(*height), uint32(*width)) switch *rules { case "dayandnight": - universe.Rules = game.DayAndNightRules + universe.Rules = universe.DayAndNightRules case "seeds": - universe.Rules = game.SeedsRules + universe.Rules = universe.SeedsRules case "wrap": - universe.Rules = game.ConwayRulesWrap + universe.Rules = universe.ConwayRulesWrap + case "custom": + universe.Rules = universe.NewLifeLikeRules(convertStringToUint8(*b), convertStringToUint8(*s), true) default: // just use conway } @@ -76,10 +81,10 @@ func createParallelUniverses() []*game.ParallelUniverse { for col := 0; col < *number; col++ { u := game.NewParallelUniverse(uint32(*height), uint32(*width)) switch *rules { - case "dayandnight": - u.Rules = game.DayAndNightRules - case "seeds": - u.Rules = game.SeedsRules + // case "dayandnight": + // u.Rules = game.DayAndNightRules + // case "seeds": + // u.Rules = game.SeedsRules default: // just use conway } @@ -160,3 +165,16 @@ func callMultiTick(wg *sync.WaitGroup, u *game.ParallelUniverse) { wg.Done() }() } + +func convertStringToUint8(input string) []uint8 { + output := make([]uint8, len(input)) + for i, c := range input { + n, err := strconv.Atoi(string(c)) + if err != nil { + panic(err) + } + output[i] = uint8(n) + } + + return output +} diff --git a/lib/game/rules.go b/lib/game/rules.go index 07de8fc..83eb4b7 100644 --- a/lib/game/rules.go +++ b/lib/game/rules.go @@ -1,5 +1,41 @@ package game +func (u *Universe) NewLifeLikeRules(B, S []uint8, wraps bool) func(cell uint8, row, column uint32) uint8 { + rule := NewRule(B, S) + return func(cell uint8, row, column uint32) uint8 { + var neighbors uint8 + if wraps { + neighbors = u.MooreNeighbors(row, column) + } else { + neighbors = u.MooreNeighborsWrap(row, column) + } + return rule(cell, neighbors) + } +} + +func NewRule(B, S []uint8) func(cell uint8, liveNeighbors uint8) uint8 { + return func(cell uint8, liveNeighbors uint8) uint8 { + if cell == Dead && contains(B, liveNeighbors) { + return Alive + } + + if cell == Alive && contains(S, liveNeighbors) { + return Alive + } + + return Dead + } +} + +func contains(slice []uint8, candidate uint8) bool { + for _, element := range slice { + if element == candidate { + return true + } + } + return false +} + // ConwayRules implements the classic Game of Life rules. func (u *Universe) ConwayRules(cell uint8, row, column uint32) uint8 { return RuleB3S23(cell, u.MooreNeighbors(row, column))