diff --git a/conway/conway_test.go b/conway/conway_test.go index d2ce709..d7215e3 100644 --- a/conway/conway_test.go +++ b/conway/conway_test.go @@ -31,122 +31,68 @@ func init() { s.Set(15, 15, 1) } -func newTestGameState() (*GameState, error) { +func newTestGameState() *GameState { state := NewGameState(16, 16) - - err := state.Import(TEST_SIMPLE_INITIAL_STATE) - if err != nil { - return nil, err - } - - return state, nil + state.Import(TEST_SIMPLE_INITIAL_STATE) + return state } -func newTestGameOfLife() (*GameOfLife, error) { +func newTestGameOfLife() *GameOfLife { game := NewGameOfLife(16, 16) - - err := game.State.Import(TEST_SIMPLE_INITIAL_STATE) - if err != nil { - return nil, err - } - - return game, nil + game.State.Import(TEST_SIMPLE_INITIAL_STATE) + return game } func TestLiveCellWithFewerThanTwoLiveNeighborsDies(t *testing.T) { - game, err := newTestGameOfLife() - if err != nil { - t.Error(err) - return - } + game := newTestGameOfLife() game.EvaluateGeneration() - value, err := game.State.Get(3, 2) - if err != nil { - t.Error(err) - return - } - - if value != 0 { - t.Errorf("%v != 0", value) + cell := game.State.Get(3, 2) + if cell.Value != 0 { + t.Errorf("%v != 0", cell.Value) return } } func TestLiveCellWithTwoOrThreeLiveNeighborsLivesOn(t *testing.T) { - game, err := newTestGameOfLife() - - if err != nil { - t.Error(err) - return - } + game := newTestGameOfLife() game.EvaluateGeneration() - value, err := game.State.Get(0, 0) - if err != nil { - t.Error(err) - return - } - - if value != 1 { - t.Errorf("%v != 1", value) + cell := game.State.Get(0, 0) + if cell.Value != 1 { + t.Errorf("%v != 1", cell.Value) return } } func TestLiveCellWithMoreThanThreeLiveNeighborsDies(t *testing.T) { - game, err := newTestGameOfLife() - - if err != nil { - t.Error(err) - return - } + game := newTestGameOfLife() game.EvaluateGeneration() - value, err := game.State.Get(0, 1) - if err != nil { - t.Error(err) - return - } - - if value != 0 { - t.Errorf("%v != 0", value) + cell := game.State.Get(0, 1) + if cell.Value != 0 { + t.Errorf("%v != 0", cell.Value) return } } func TestDeadCellWithExactlyThreeLiveNeighborsBecomesAlive(t *testing.T) { - game, err := newTestGameOfLife() - - if err != nil { - t.Error(err) - return - } + game := newTestGameOfLife() game.EvaluateGeneration() - value, err := game.State.Get(3, 1) - if err != nil { - t.Error(err) - return - } - - if value != 1 { - t.Errorf("%v != 1", value) + cell := game.State.Get(3, 1) + if cell.Value != 1 { + t.Errorf("%v != 1", cell.Value) return } } func TestGameOfLifeCanDisplayItself(t *testing.T) { - game, err := newTestGameOfLife() - - if err != nil { - t.Error(err) - return - } + game := newTestGameOfLife() grid := fmt.Sprintf("%s\n", game) @@ -158,11 +104,7 @@ func TestGameOfLifeCanDisplayItself(t *testing.T) { } func TestNewGameOfLifeHasCorrectDimensions(t *testing.T) { - game, err := newTestGameOfLife() - if err != nil { - t.Error(err) - return - } + game := newTestGameOfLife() if game.State.Height() != 16 || game.State.Width() != 16 { t.Fail() @@ -170,12 +112,7 @@ func TestNewGameOfLifeHasCorrectDimensions(t *testing.T) { } func TestNewGameOfLifeHasGameStateOfSameDimensions(t *testing.T) { - game, err := newTestGameOfLife() - - if err != nil { - t.Error(err) - return - } + game := newTestGameOfLife() if len(game.State.Rows) < 16 { t.Fail() @@ -187,41 +124,33 @@ func TestNewGameOfLifeHasGameStateOfSameDimensions(t *testing.T) { } func TestGameStateCanImportState(t *testing.T) { - game, err := newTestGameOfLife() - - if err != nil { - t.Fail() - } + game := newTestGameOfLife() - if value, err := game.State.Get(0, 0); err != nil || value != 1 { + if game.State.Get(0, 0).Value != 1 { t.Fail() } - if value, err := game.State.Get(1, 0); err != nil || value != 1 { + if game.State.Get(1, 0).Value != 1 { t.Fail() } - if value, err := game.State.Get(0, 1); err != nil || value != 1 { + if game.State.Get(0, 1).Value != 1 { t.Fail() } - if value, err := game.State.Get(1, 1); err != nil || value != 1 { + if game.State.Get(1, 1).Value != 1 { t.Fail() } - if value, err := game.State.Get(2, 2); err != nil || value != 1 { + if game.State.Get(2, 2).Value != 1 { t.Fail() } } func TestGameOfLifeCanImportRandomState(t *testing.T) { - game, err := newTestGameOfLife() - if err != nil { - t.Error(err) - return - } + game := newTestGameOfLife() - err = game.ImportRandomState() + err := game.ImportRandomState() if err != nil { t.Error(err) return @@ -231,13 +160,8 @@ func TestGameOfLifeCanImportRandomState(t *testing.T) { for y := 0; y < 16; y++ { for x := 0; x < 16; x++ { - value, err := game.State.Get(x, y) - if err != nil { - t.Error(err) - return - } - - if value == 0 { + cell := game.State.Get(x, y) + if cell.Value == 0 { zeroCount++ } } @@ -249,11 +173,7 @@ func TestGameOfLifeCanImportRandomState(t *testing.T) { } func TestGameStateCanDisplayItself(t *testing.T) { - state, err := newTestGameState() - if err != nil { - t.Error(err) - return - } + state := newTestGameState() grid := fmt.Sprintf("%s\n", state) lenGrid := len(grid) @@ -274,7 +194,7 @@ func TestNewGameStatesAreAllDead(t *testing.T) { state := NewGameState(4, 4) for x := 0; x < 3; x++ { for y := 0; y < 3; y++ { - if value, err := state.Get(x, y); err != nil || value != 0 { + if state.Get(x, y).Value != 0 { t.Fail() } } @@ -283,29 +203,25 @@ func TestNewGameStatesAreAllDead(t *testing.T) { func TestGameStateCanGetCellValueByCoords(t *testing.T) { state := NewGameState(8, 8) - if value, err := state.Get(2, 2); err != nil || value != 0 { + if state.Get(2, 2).Value != 0 { t.Fail() } } func TestGameStateCanSetCellValueByCoords(t *testing.T) { state := NewGameState(8, 8) - if err := state.Set(2, 5, 1); err != nil { - t.Fail() - } + state.Set(2, 5, 1) - if value, err := state.Get(2, 5); err != nil || value != 1 { + if state.Get(2, 5).Value != 1 { t.Fail() } } func TestGameStateCanEnlivenCellsByCoords(t *testing.T) { state := NewGameState(8, 8) - if err := state.Enliven(0, 1); err != nil { - t.Fail() - } + state.Enliven(0, 1) - if value, err := state.Get(0, 1); err != nil || value != 1 { + if state.Get(0, 1).Value != 1 { t.Fail() } } @@ -313,19 +229,15 @@ func TestGameStateCanEnlivenCellsByCoords(t *testing.T) { func TestGameStateCanDeadenCellsByCoords(t *testing.T) { state := NewGameState(8, 8) - if err := state.Enliven(0, 1); err != nil { - t.Fail() - } + state.Enliven(0, 1) - if value, err := state.Get(0, 1); err != nil || value != 1 { + if state.Get(0, 1).Value != 1 { t.Fail() } - if err := state.Deaden(0, 1); err != nil { - t.Fail() - } + state.Deaden(0, 1) - if value, err := state.Get(0, 1); err != nil || value != 0 { + if state.Get(0, 1).Value != 0 { t.Fail() } } @@ -335,7 +247,7 @@ func TestNewGenerationScoreCardIsAllZeros(t *testing.T) { for y := 0; y < gen.Height(); y++ { for x := 0; x < gen.Width(); x++ { - if value, err := gen.Get(x, y); err != nil || value != 0 { + if gen.Get(x, y).Value != 0 { t.Fail() } } @@ -345,38 +257,25 @@ func TestNewGenerationScoreCardIsAllZeros(t *testing.T) { func TestGenerationScoreCardCalculateResultsInCorrectNeighborCounts(t *testing.T) { genScore := NewGenerationScoreCard(16, 16) - state, err := newTestGameState() - if err != nil { - t.Error(err) - return - } + state := newTestGameState() genScore.Calculate(state) - value, err := genScore.Get(0, 0) - if err != nil { - t.Error(err) - return - } else if value != 3 { - t.Errorf("[0, 0] value %v != 3", value) + + cell := genScore.Get(0, 0) + if cell.Value != 3 { + t.Errorf("[0, 0] value %v != 3", cell.Value) return } - value, err = genScore.Get(3, 2) - if err != nil { - t.Error(err) - return - } else if value != 1 { - t.Errorf("[3, 2] value %d != 1", value) + cell = genScore.Get(3, 2) + if cell.Value != 1 { + t.Errorf("[3, 2] value %d != 1", cell.Value) return } } func TestStateCanMutate(t *testing.T) { - state, err := newTestGameState() - if err != nil { - t.Error(err) - return - } + state := newTestGameState() curCksum, err := state.Checksum() if err != nil { @@ -384,11 +283,7 @@ func TestStateCanMutate(t *testing.T) { return } - err = state.Mutate() - if err != nil { - t.Error(err) - return - } + state.Mutate() newCksum, err := state.Checksum() if err != nil { @@ -402,11 +297,7 @@ func TestStateCanMutate(t *testing.T) { } func TestStateProvidesCellIteratorChannel(t *testing.T) { - state, err := newTestGameState() - if err != nil { - t.Error(err) - return - } + state := newTestGameState() cells, err := state.Cells() if err != nil { @@ -425,11 +316,7 @@ func TestStateProvidesCellIteratorChannel(t *testing.T) { } func TestGameStateCellsCanHaveTheirValueSet(t *testing.T) { - state, err := newTestGameState() - if err != nil { - t.Error(err) - return - } + state := newTestGameState() cells, err := state.Cells() if err != nil { @@ -438,7 +325,7 @@ func TestGameStateCellsCanHaveTheirValueSet(t *testing.T) { } for cell := range cells { - cell.SetValue(1) + cell.Value = 1 } cells, err = state.Cells() @@ -454,12 +341,16 @@ func TestGameStateCellsCanHaveTheirValueSet(t *testing.T) { } } -func TestGameOfLifeEmitsGenerationTicksUntilStasis(t *testing.T) { - game, err := newTestGameOfLife() - if err != nil { - t.Error(err) - return +func TestGameStateCellsCanBeFetchedByXAndYCoords(t *testing.T) { + state := newTestGameState() + + if state.Get(3, 4) == nil { + t.Fail() } +} + +func TestGameOfLifeEmitsGenerationTicksUntilStasis(t *testing.T) { + game := newTestGameOfLife() genTicks, err := game.Generations() if err != nil { @@ -482,85 +373,21 @@ func TestGameOfLifeEmitsGenerationTicksUntilStasis(t *testing.T) { } } -func TestGameStateRowsCanBeGottenByYCoord(t *testing.T) { - state, err := newTestGameState() - if err != nil { - t.Error(err) - return - } - - row := state.GetRow(1) +func TestGameStateCoordsAreNeverOutOfBounds(t *testing.T) { + state := newTestGameState() - if len(row.Cells) < 1 { - t.Fail() - } -} - -func TestGameStateRowsCanBeGottenByYCoordsBeyondBounds(t *testing.T) { - state, err := newTestGameState() - if err != nil { - t.Error(err) - return - } - - newVal := rand.Intn(9999) - - err = state.Set(0, 2, newVal) - if err != nil { - t.Error(err) - return - } - - row := state.GetRow(state.Height() + 2) - - if row.Cells[0] != newVal { - t.Errorf("(0, 2) != %d: %d", newVal, row.Cells[0]) - return - } -} - -func TestGameStateRowCellsCanBeGottenByXCoord(t *testing.T) { - state, err := newTestGameState() - if err != nil { - t.Error(err) - return - } + oobX, oobY := state.Width()+rand.Intn(99), state.Height()+rand.Intn(99) newVal := rand.Intn(9999) - err = state.Set(4, 0, newVal) - if err != nil { - t.Error(err) - return - } - - row := state.GetRow(0) - cell := row.GetCell(4) + state.Set(oobX, oobY, newVal) + cell := state.Get(oobX, oobY) - if cell.Value != newVal { - t.Errorf("(0, 4) != %d: %d", newVal, cell.Value) - } -} - -func TestGameStateRowCellsCanBeGottenByXCoordBeyondBounds(t *testing.T) { - state, err := newTestGameState() - if err != nil { - t.Error(err) - return - } - - newVal := rand.Intn(9999) - - err = state.Set(9, 2, newVal) - if err != nil { - t.Error(err) - return + if cell == nil { + t.Fail() } - row := state.GetRow(2) - cell := row.GetCell(state.Width() + 9) - if cell.Value != newVal { - t.Errorf("(9, 2) != %d: %d", newVal, cell.Value) + t.Errorf("(%d, %d) != %d: %d", oobX, oobY, newVal, cell.Value) } } diff --git a/conway/game_of_life.go b/conway/game_of_life.go index ed35fd4..8b85256 100644 --- a/conway/game_of_life.go +++ b/conway/game_of_life.go @@ -51,8 +51,8 @@ func RunConsoleGame(height, width, sleepMs int, mutate bool) (int, error) { return 0, nil } -func (game *GameOfLife) Mutate() error { - return game.State.Mutate() +func (game *GameOfLife) Mutate() { + game.State.Mutate() } func (game *GameOfLife) Checksum() (string, error) { @@ -79,18 +79,11 @@ func (game *GameOfLife) EvaluateGeneration() error { for cell := range cells { score := cell.Value - curState, err := game.State.Get(cell.X, cell.Y) - if err != nil { - return err - } - - if curState == 1 { + cell := game.State.Get(cell.X, cell.Y) + if cell.Value == 1 { if score < 2 { - err = game.State.Deaden(cell.X, cell.Y) - if err != nil { - return err - } + game.State.Deaden(cell.X, cell.Y) continue } @@ -99,19 +92,13 @@ func (game *GameOfLife) EvaluateGeneration() error { } if score > 3 { - err = game.State.Deaden(cell.X, cell.Y) - if err != nil { - return err - } + game.State.Deaden(cell.X, cell.Y) continue } - } else if curState == 0 { + } else if cell.Value == 0 { if score == 3 { - err = game.State.Enliven(cell.X, cell.Y) - if err != nil { - return err - } + game.State.Enliven(cell.X, cell.Y) continue } else { continue @@ -122,8 +109,8 @@ func (game *GameOfLife) EvaluateGeneration() error { return nil } -func (game *GameOfLife) ImportState(state *GameState) error { - return game.State.Import(state) +func (game *GameOfLife) ImportState(state *GameState) { + game.State.Import(state) } func (game *GameOfLife) ImportRandomState() error { @@ -144,10 +131,11 @@ func (game *GameOfLife) ImportRandomState() error { } for cell := range cells { - cell.SetValue(rand.Intn(2)) + cell.Value = rand.Intn(2) } - return game.ImportState(randState) + game.ImportState(randState) + return nil } func (game *GameOfLife) String() string { diff --git a/conway/game_state.go b/conway/game_state.go index 38327a2..0438fba 100644 --- a/conway/game_state.go +++ b/conway/game_state.go @@ -14,6 +14,17 @@ const ( LIVE_CELL = " " ) +type GameStateCell struct { + Value int + X int + Y int +} + +type GameStateRow struct { + Y int + Cells []*GameStateCell +} + type GameState struct { Rows []*GameStateRow } @@ -23,7 +34,11 @@ func NewGameState(height, width int) *GameState { for i := 0; i < height; i++ { row := &GameStateRow{Y: i} for j := 0; j < width; j++ { - row.Cells = append(row.Cells, 0) + row.Cells = append(row.Cells, &GameStateCell{ + Value: 0, + X: j, + Y: i, + }) } state.Rows = append(state.Rows, row) } @@ -51,50 +66,36 @@ func (state *GameState) GetRow(y int) *GameStateRow { return state.Rows[y] } -func (state *GameState) Set(x, y, value int) error { - if x < 0 || y < 0 { - errMsg := fmt.Sprintf("coordinates (%v, %v) are out of bounds!", x, y) - return errors.New(errMsg) - } - - row := state.GetRow(y) - - if x+1 > len(row.Cells) { - errMsg := fmt.Sprintf("x coordinate %v is out of bounds!", x) - return errors.New(errMsg) - } - - row.Cells[x] = value - return nil +func (state *GameState) Set(x, y, value int) { + cell := state.Get(x, y) + cell.Value = value } -func (state *GameState) Get(x, y int) (int, error) { +func (state *GameState) Get(x, y int) *GameStateCell { row := state.GetRow(y) + lenCells := len(row.Cells) - if len(row.Cells) < x+1 { - return -1, errors.New("x coordinate is out of bounds!") + if x+1 > lenCells { + return state.Get(x%lenCells, row.Y) } - return row.Cells[x], nil + return row.Cells[x] } -func (state *GameState) Enliven(x, y int) error { - return state.Set(x, y, 1) +func (state *GameState) Enliven(x, y int) { + state.Set(x, y, 1) } -func (state *GameState) Deaden(x, y int) error { - return state.Set(x, y, 0) +func (state *GameState) Deaden(x, y int) { + state.Set(x, y, 0) } -func (state *GameState) Import(other *GameState) (err error) { +func (state *GameState) Import(other *GameState) { for y, row := range other.Rows { for x, cell := range row.Cells { - if err = state.Set(x, y, cell); err != nil { - return err - } + state.Set(x, y, cell.Value) } } - return nil } func (state *GameState) Cells() (<-chan *GameStateCell, error) { @@ -113,19 +114,8 @@ func (state *GameState) Cells() (<-chan *GameStateCell, error) { width := state.Width() for y := 0; y < height; y++ { - row := state.GetRow(y) - for x := 0; x < width; x++ { - value, err := state.Get(x, y) - if err != nil { - panic(err) - } - c <- &GameStateCell{ - Value: value, - X: x, - Y: y, - cellmates: row.Cells, - } + c <- state.Get(x, y) } } }(state, cells) @@ -133,18 +123,12 @@ func (state *GameState) Cells() (<-chan *GameStateCell, error) { return (<-chan *GameStateCell)(cells), nil } -func (state *GameState) Mutate() error { +func (state *GameState) Mutate() { randX := rand.Intn(state.Width()) randY := rand.Intn(state.Height()) - curVal, err := state.Get(randX, randY) - if err != nil { - return err - } - - err = state.Set(randX, randY, int(math.Abs(float64(curVal-1)))) - - return nil + cell := state.Get(randX, randY) + state.Set(randX, randY, int(math.Abs(float64(cell.Value-1)))) } func (state *GameState) Checksum() (string, error) { @@ -171,12 +155,8 @@ func (state *GameState) String() string { for x := 0; x < width; x++ { stringVal := DEAD_CELL - value, err := state.Get(x, y) - if err != nil { - return "" - } - - if value == 1 { + cell := state.Get(x, y) + if cell.Value == 1 { stringVal = LIVE_CELL } cells = append(cells, stringVal) diff --git a/conway/game_state_cell.go b/conway/game_state_cell.go deleted file mode 100644 index 1458c22..0000000 --- a/conway/game_state_cell.go +++ /dev/null @@ -1,12 +0,0 @@ -package conway - -type GameStateCell struct { - Value int - X int - Y int - cellmates []int -} - -func (cell *GameStateCell) SetValue(value int) { - cell.cellmates[cell.X] = value -} diff --git a/conway/game_state_row.go b/conway/game_state_row.go deleted file mode 100644 index 358b23f..0000000 --- a/conway/game_state_row.go +++ /dev/null @@ -1,21 +0,0 @@ -package conway - -type GameStateRow struct { - Y int - Cells []int -} - -func (row *GameStateRow) GetCell(x int) *GameStateCell { - lenCells := len(row.Cells) - - if x+1 > lenCells { - return row.GetCell(x % lenCells) - } - - return &GameStateCell{ - Value: row.Cells[x], - X: x, - Y: row.Y, - cellmates: row.Cells, - } -} diff --git a/conway/generation_score_card.go b/conway/generation_score_card.go index 347c2e9..bc055df 100644 --- a/conway/generation_score_card.go +++ b/conway/generation_score_card.go @@ -27,7 +27,11 @@ func NewGenerationScoreCard(height, width int) *GenerationScoreCard { for i := 0; i < height; i++ { row := &GameStateRow{Y: i} for j := 0; j < width; j++ { - row.Cells = append(row.Cells, 0) + row.Cells = append(row.Cells, &GameStateCell{ + Value: 0, + X: j, + Y: i, + }) } genScore.Rows = append(genScore.Rows, row) } @@ -58,15 +62,8 @@ func (genScore *GenerationScoreCard) Calculate(state *GameState) error { continue } - curScore, err := genScore.Get(xTarget, yTarget) - if err != nil { - continue - } - - err = genScore.Set(xTarget, yTarget, curScore+1) - if err != nil { - return err - } + cell := genScore.Get(xTarget, yTarget) + genScore.Set(xTarget, yTarget, cell.Value+1) } }