Cells can have their values set when ranging over them
plus more replacement of y, x loops with cell ranges, adding static neighbor coords.
This commit is contained in:
parent
078efbe057
commit
8ba87ccc81
@ -377,14 +377,78 @@ func TestStateCanMutate(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
curCksum := state.Checksum()
|
curCksum, err := state.Checksum()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err = state.Mutate()
|
err = state.Mutate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if curCksum == state.Checksum() {
|
newCksum, err := state.Checksum()
|
||||||
t.Errorf("Checksum did not change! %v", curCksum)
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if curCksum == newCksum {
|
||||||
|
t.Errorf("Checksum did not change! %v", newCksum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStateProvidesCellIteratorChannel(t *testing.T) {
|
||||||
|
state, err := newTestGameState()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cells, err := state.Cells()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cellCount := 0
|
||||||
|
for _ = range cells {
|
||||||
|
cellCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
if cellCount != 256 {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGameStateCellsCanHaveTheirValueSet(t *testing.T) {
|
||||||
|
state, err := newTestGameState()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cells, err := state.Cells()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for cell := range cells {
|
||||||
|
cell.SetValue(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cells, err = state.Cells()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for cell := range cells {
|
||||||
|
if cell.Value != 1 {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,12 @@ func main() {
|
|||||||
|
|
||||||
checksums := make([]string, 4)
|
checksums := make([]string, 4)
|
||||||
checksums[0], checksums[1], checksums[2], checksums[3] = "foo", "bar", "baz", "qwx"
|
checksums[0], checksums[1], checksums[2], checksums[3] = "foo", "bar", "baz", "qwx"
|
||||||
pushChecksum(game.Checksum(), checksums)
|
ck, err := game.Checksum()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "NAY NAY: %v\n", err)
|
||||||
|
os.Exit(3)
|
||||||
|
}
|
||||||
|
pushChecksum(ck, checksums)
|
||||||
|
|
||||||
ticks := time.Tick(time.Duration(*sleepMs) * time.Millisecond)
|
ticks := time.Tick(time.Duration(*sleepMs) * time.Millisecond)
|
||||||
generations := 0
|
generations := 0
|
||||||
@ -50,7 +55,11 @@ func main() {
|
|||||||
|
|
||||||
game.EvaluateGeneration()
|
game.EvaluateGeneration()
|
||||||
|
|
||||||
curChecksum := game.Checksum()
|
curChecksum, err := game.Checksum()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to calculate current game checksum: %v\n", err)
|
||||||
|
os.Exit(4)
|
||||||
|
}
|
||||||
|
|
||||||
if checksums[0] == curChecksum || checksums[1] == curChecksum {
|
if checksums[0] == curChecksum || checksums[1] == curChecksum {
|
||||||
fmt.Println("Stasis!")
|
fmt.Println("Stasis!")
|
||||||
|
@ -15,10 +15,28 @@ const (
|
|||||||
LIVE_CELL = " "
|
LIVE_CELL = " "
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
neighbors = []neighbor{
|
||||||
|
neighbor{-1, -1},
|
||||||
|
neighbor{-1, 0},
|
||||||
|
neighbor{-1, 1},
|
||||||
|
neighbor{0, -1},
|
||||||
|
neighbor{0, 1},
|
||||||
|
neighbor{1, -1},
|
||||||
|
neighbor{1, 0},
|
||||||
|
neighbor{1, 1},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rand.Seed(time.Now().UTC().UnixNano())
|
rand.Seed(time.Now().UTC().UnixNano())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type neighbor struct {
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
}
|
||||||
|
|
||||||
type GameOfLife struct {
|
type GameOfLife struct {
|
||||||
State *GameState
|
State *GameState
|
||||||
}
|
}
|
||||||
@ -27,6 +45,7 @@ type GameStateCell struct {
|
|||||||
Value int
|
Value int
|
||||||
X int
|
X int
|
||||||
Y int
|
Y int
|
||||||
|
cols []int
|
||||||
}
|
}
|
||||||
|
|
||||||
type gameGridRow struct {
|
type gameGridRow struct {
|
||||||
@ -124,31 +143,43 @@ func (state *GameState) Import(other *GameState) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (state *GameState) Cells(cells chan *GameStateCell) error {
|
func (state *GameState) Cells() (<-chan *GameStateCell, error) {
|
||||||
height := state.Height()
|
height := state.Height()
|
||||||
width := state.Width()
|
width := state.Width()
|
||||||
|
|
||||||
if height < 0 || width < 0 {
|
if height < 0 || width < 0 {
|
||||||
return errors.New("state has invalid dimensions!")
|
return nil, errors.New("state has invalid dimensions!")
|
||||||
}
|
}
|
||||||
|
|
||||||
defer close(cells)
|
cells := make(chan *GameStateCell)
|
||||||
|
|
||||||
for y := 0; y < height; y++ {
|
go func(state *GameState, c chan *GameStateCell) {
|
||||||
for x := 0; x < width; x++ {
|
defer close(c)
|
||||||
value, err := state.Get(x, y)
|
height := state.Height()
|
||||||
|
width := state.Width()
|
||||||
|
|
||||||
|
for y := 0; y < height; y++ {
|
||||||
|
row, err := state.GetRow(y)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
cells <- &GameStateCell{
|
|
||||||
Value: value,
|
for x := 0; x < width; x++ {
|
||||||
X: x,
|
value, err := state.Get(x, y)
|
||||||
Y: y,
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
c <- &GameStateCell{
|
||||||
|
Value: value,
|
||||||
|
X: x,
|
||||||
|
Y: y,
|
||||||
|
cols: row.Cols,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}(state, cells)
|
||||||
|
|
||||||
return nil
|
return (<-chan *GameStateCell)(cells), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (game *GameOfLife) Mutate() error {
|
func (game *GameOfLife) Mutate() error {
|
||||||
@ -169,20 +200,21 @@ func (state *GameState) Mutate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (game *GameOfLife) Checksum() string {
|
func (game *GameOfLife) Checksum() (string, error) {
|
||||||
return game.State.Checksum()
|
return game.State.Checksum()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (state *GameState) Checksum() string {
|
func (state *GameState) Checksum() (string, error) {
|
||||||
ck := sha1.New()
|
ck := sha1.New()
|
||||||
cells := make(chan *GameStateCell)
|
cells, err := state.Cells()
|
||||||
|
if err != nil {
|
||||||
go state.Cells(cells)
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
for cell := range cells {
|
for cell := range cells {
|
||||||
fmt.Fprintf(ck, "%v", cell.Value)
|
fmt.Fprintf(ck, "%v", cell.Value)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%x", ck.Sum(nil))
|
return fmt.Sprintf("%x", ck.Sum(nil)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGameOfLife(height, width int) *GameOfLife {
|
func NewGameOfLife(height, width int) *GameOfLife {
|
||||||
@ -197,50 +229,50 @@ func (game *GameOfLife) EvaluateGeneration() error {
|
|||||||
genScore := NewGenerationScoreCard(height, width)
|
genScore := NewGenerationScoreCard(height, width)
|
||||||
genScore.Calculate(game.State)
|
genScore.Calculate(game.State)
|
||||||
|
|
||||||
for y := 0; y < height; y++ {
|
cells, err := genScore.Cells()
|
||||||
for x := 0; x < width; x++ {
|
if err != nil {
|
||||||
score, err := genScore.Get(x, y)
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
|
||||||
|
for cell := range cells {
|
||||||
|
score := cell.Value
|
||||||
|
|
||||||
|
curState, err := game.State.Get(cell.X, cell.Y)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if curState == 1 {
|
||||||
|
|
||||||
|
if score < 2 {
|
||||||
|
err = game.State.Deaden(cell.X, cell.Y)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
curState, err := game.State.Get(x, y)
|
if score == 2 || score == 3 {
|
||||||
if err != nil {
|
continue
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if curState == 1 {
|
if score > 3 {
|
||||||
|
err = game.State.Deaden(cell.X, cell.Y)
|
||||||
if score < 2 {
|
if err != nil {
|
||||||
err = game.State.Deaden(x, y)
|
return err
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if curState == 0 {
|
||||||
|
|
||||||
if score == 2 || score == 3 {
|
if score == 3 {
|
||||||
continue
|
err = game.State.Enliven(cell.X, cell.Y)
|
||||||
}
|
if err != nil {
|
||||||
|
return err
|
||||||
if score > 3 {
|
|
||||||
err = game.State.Deaden(x, y)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
} else if curState == 0 {
|
|
||||||
|
|
||||||
if score == 3 {
|
|
||||||
err = game.State.Enliven(x, y)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,13 +296,13 @@ func (game *GameOfLife) ImportRandomState() error {
|
|||||||
|
|
||||||
randState := NewGameState(height, width)
|
randState := NewGameState(height, width)
|
||||||
|
|
||||||
for y := 0; y < height; y++ {
|
cells, err := randState.Cells()
|
||||||
for x := 0; x < width; x++ {
|
if err != nil {
|
||||||
err := randState.Set(x, y, rand.Intn(2))
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
for cell := range cells {
|
||||||
}
|
cell.SetValue(rand.Intn(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
return game.ImportState(randState)
|
return game.ImportState(randState)
|
||||||
@ -280,6 +312,10 @@ func (game *GameOfLife) String() string {
|
|||||||
return fmt.Sprintf("%s\n", game.State)
|
return fmt.Sprintf("%s\n", game.State)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cell *GameStateCell) SetValue(value int) {
|
||||||
|
cell.cols[cell.X] = value
|
||||||
|
}
|
||||||
|
|
||||||
func (state *GameState) String() string {
|
func (state *GameState) String() string {
|
||||||
var rows []string
|
var rows []string
|
||||||
|
|
||||||
@ -319,42 +355,37 @@ func NewGenerationScoreCard(height, width int) *GenerationScoreCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (genScore *GenerationScoreCard) Calculate(state *GameState) error {
|
func (genScore *GenerationScoreCard) Calculate(state *GameState) error {
|
||||||
stateHeight, stateWidth := state.Height(), state.Width()
|
stateWidth := state.Width()
|
||||||
for y := 0; y < stateHeight; y++ {
|
stateCells, err := state.Cells()
|
||||||
for x := 0; x < stateWidth; x++ {
|
if err != nil {
|
||||||
value, err := state.Get(x, y)
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
|
||||||
|
for stateCell := range stateCells {
|
||||||
|
if stateCell.Value == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, neighbor := range neighbors {
|
||||||
|
xTarget := stateCell.X + neighbor.X
|
||||||
|
yTarget := stateCell.Y + neighbor.Y
|
||||||
|
|
||||||
|
if xTarget < 0 || yTarget < 0 {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if value == 1 {
|
if xTarget+1 > stateWidth || yTarget+1 > stateWidth {
|
||||||
for yOffset := -1; yOffset < 2; yOffset++ {
|
continue
|
||||||
for xOffset := -1; xOffset < 2; xOffset++ {
|
}
|
||||||
xTarget := x + xOffset
|
|
||||||
yTarget := y + yOffset
|
|
||||||
|
|
||||||
if xTarget < 0 || yTarget < 0 {
|
curScore, err := genScore.Get(xTarget, yTarget)
|
||||||
continue
|
if err != nil {
|
||||||
}
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if xTarget+1 > stateWidth || yTarget+1 > stateWidth {
|
err = genScore.Set(xTarget, yTarget, curScore+1)
|
||||||
continue
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
|
||||||
if xTarget == x && yTarget == y {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
curScore, err := genScore.Get(xTarget, yTarget)
|
|
||||||
if err != nil {
|
|
||||||
continue // assume out of bounds, which is stinky
|
|
||||||
}
|
|
||||||
err = genScore.Set(xTarget, yTarget, curScore+1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user