GOLang Game of Life Implementation
I decided to give Go a try and implemented a Game of Life Kata exercise in GOLang. I have no prior experience in Go and the majority of my experience comes from Java, C#, and Python. My code appears to be working as intended but not sure if I've implemented it in the GO way, or idiomatic Go.
I've seen a few Go examples online where the properties of the struct were always public, but that feels foreign coming from the object-orient world. The way I've implemented it the Board struct should never be able to get into an invalid state. I don't know if that is a mindset that is shared by the Go community.
I have a colleague who is big into Go and favors immutability and no side effects. I can see how that would be ideal for concurrency, but does the general Go community prefer avoiding mutations? As an example I could have implemented my Evolve method to return a new Board struct rather than mutate its state property.
Is there anything else that stands out as not being Go like?
package board
import (
"errors"
"math/rand"
"strconv"
"time"
)
const CellDead = 0
const CellAlive = 1
type board struct {
state int
rows int
columns int
}
/* Creates a new Board with the given dimensions. The dimensions, rows and columns,
must be positive integers greater than 0.
Returns a board populated with a random state. */
func NewRandomBoard(rows, columns int) (board, error) {
if rows < 1 || columns < 1 {
return board{}, errors.New("rows and columns must be a positive integer greater than 0")
}
initState := make(int, rows)
for i := range initState {
initState[i] = make(int, columns)
}
rand.Seed(time.Now().UnixNano())
// Populate random state
for i := range initState {
for j := range initState[i] {
initState[i][j] = rand.Intn((1 -0 + 1) + 0)
}
}
return board{state: initState, rows:rows, columns:columns}, nil
}
func NewBoard(initialState int) (board, error) {
if initialState == nil {
return board{}, errors.New("initialState cannot be nil")
}
if len(initialState) < 1 || len(initialState[0]) < 1 {
return board{}, errors.New("initialState must contain at least 1 row and 1 column")
}
colSize := len(initialState[0])
for i := 0; i < len(initialState); i++ {
if colSize != len(initialState[i]) {
return board{}, errors.New("initialState is a jagged 2D array, initialState cannot be jagged")
}
for j := 0; j < len(initialState[i]); j++ {
cellValue := initialState[i][j]
if cellValue < 0 || cellValue > 1 {
return board{}, errors.New("initialState may only contain values 0 or 1")
}
}
}
return board{state:initialState, rows: len(initialState), columns: len(initialState[0])}, nil
}
func (b *board) Evolve() {
newState := make(int, b.rows)
for i := range newState {
newState[i] = make(int, b.columns)
for j := range newState[i] {
newState[i][j] = nextStateForCell(b,i,j)
}
}
b.state = newState
}
func (b *board) State() int {
return b.state
}
func (b *board) Rows() int {
return b.rows
}
func (b *board) Columns() int {
return b.columns
}
func (b *board) PrettyPrint() {
for i := range b.state {
for j := range b.state[i] {
print(" " + strconv.Itoa(b.state[i][j]) + "")
}
println()
}
}
func nextStateForCell(b *board, i,j int) int {
neighborsAlive := 0
cellValue := b.state[i][j]
for x := -1; x <= 1; x++ {
for y := -1; y <= 1; y++ {
if i + x < 0 || i + x > (b.rows - 1) || y + j < 0 || y + j > (b.columns - 1) {
continue
}
neighborsAlive += b.state[i + x][y + j]
}
}
neighborsAlive -= cellValue
if cellValue == CellDead && neighborsAlive == 3 {
return CellAlive
} else if cellValue == CellAlive && (neighborsAlive < 2 || neighborsAlive > 3) {
return CellDead
} else {
return cellValue
}
}
The main file
package main
import (
"io.jkratz/katas/life/board"
)
func main() {
myBoard, err := board.NewRandomBoard(10, 10)
if err != nil {
panic("Failed to instantiate board")
}
myBoard.PrettyPrint()
println()
myBoard.Evolve()
myBoard.PrettyPrint()
}
go game-of-life
add a comment |
I decided to give Go a try and implemented a Game of Life Kata exercise in GOLang. I have no prior experience in Go and the majority of my experience comes from Java, C#, and Python. My code appears to be working as intended but not sure if I've implemented it in the GO way, or idiomatic Go.
I've seen a few Go examples online where the properties of the struct were always public, but that feels foreign coming from the object-orient world. The way I've implemented it the Board struct should never be able to get into an invalid state. I don't know if that is a mindset that is shared by the Go community.
I have a colleague who is big into Go and favors immutability and no side effects. I can see how that would be ideal for concurrency, but does the general Go community prefer avoiding mutations? As an example I could have implemented my Evolve method to return a new Board struct rather than mutate its state property.
Is there anything else that stands out as not being Go like?
package board
import (
"errors"
"math/rand"
"strconv"
"time"
)
const CellDead = 0
const CellAlive = 1
type board struct {
state int
rows int
columns int
}
/* Creates a new Board with the given dimensions. The dimensions, rows and columns,
must be positive integers greater than 0.
Returns a board populated with a random state. */
func NewRandomBoard(rows, columns int) (board, error) {
if rows < 1 || columns < 1 {
return board{}, errors.New("rows and columns must be a positive integer greater than 0")
}
initState := make(int, rows)
for i := range initState {
initState[i] = make(int, columns)
}
rand.Seed(time.Now().UnixNano())
// Populate random state
for i := range initState {
for j := range initState[i] {
initState[i][j] = rand.Intn((1 -0 + 1) + 0)
}
}
return board{state: initState, rows:rows, columns:columns}, nil
}
func NewBoard(initialState int) (board, error) {
if initialState == nil {
return board{}, errors.New("initialState cannot be nil")
}
if len(initialState) < 1 || len(initialState[0]) < 1 {
return board{}, errors.New("initialState must contain at least 1 row and 1 column")
}
colSize := len(initialState[0])
for i := 0; i < len(initialState); i++ {
if colSize != len(initialState[i]) {
return board{}, errors.New("initialState is a jagged 2D array, initialState cannot be jagged")
}
for j := 0; j < len(initialState[i]); j++ {
cellValue := initialState[i][j]
if cellValue < 0 || cellValue > 1 {
return board{}, errors.New("initialState may only contain values 0 or 1")
}
}
}
return board{state:initialState, rows: len(initialState), columns: len(initialState[0])}, nil
}
func (b *board) Evolve() {
newState := make(int, b.rows)
for i := range newState {
newState[i] = make(int, b.columns)
for j := range newState[i] {
newState[i][j] = nextStateForCell(b,i,j)
}
}
b.state = newState
}
func (b *board) State() int {
return b.state
}
func (b *board) Rows() int {
return b.rows
}
func (b *board) Columns() int {
return b.columns
}
func (b *board) PrettyPrint() {
for i := range b.state {
for j := range b.state[i] {
print(" " + strconv.Itoa(b.state[i][j]) + "")
}
println()
}
}
func nextStateForCell(b *board, i,j int) int {
neighborsAlive := 0
cellValue := b.state[i][j]
for x := -1; x <= 1; x++ {
for y := -1; y <= 1; y++ {
if i + x < 0 || i + x > (b.rows - 1) || y + j < 0 || y + j > (b.columns - 1) {
continue
}
neighborsAlive += b.state[i + x][y + j]
}
}
neighborsAlive -= cellValue
if cellValue == CellDead && neighborsAlive == 3 {
return CellAlive
} else if cellValue == CellAlive && (neighborsAlive < 2 || neighborsAlive > 3) {
return CellDead
} else {
return cellValue
}
}
The main file
package main
import (
"io.jkratz/katas/life/board"
)
func main() {
myBoard, err := board.NewRandomBoard(10, 10)
if err != nil {
panic("Failed to instantiate board")
}
myBoard.PrettyPrint()
println()
myBoard.Evolve()
myBoard.PrettyPrint()
}
go game-of-life
add a comment |
I decided to give Go a try and implemented a Game of Life Kata exercise in GOLang. I have no prior experience in Go and the majority of my experience comes from Java, C#, and Python. My code appears to be working as intended but not sure if I've implemented it in the GO way, or idiomatic Go.
I've seen a few Go examples online where the properties of the struct were always public, but that feels foreign coming from the object-orient world. The way I've implemented it the Board struct should never be able to get into an invalid state. I don't know if that is a mindset that is shared by the Go community.
I have a colleague who is big into Go and favors immutability and no side effects. I can see how that would be ideal for concurrency, but does the general Go community prefer avoiding mutations? As an example I could have implemented my Evolve method to return a new Board struct rather than mutate its state property.
Is there anything else that stands out as not being Go like?
package board
import (
"errors"
"math/rand"
"strconv"
"time"
)
const CellDead = 0
const CellAlive = 1
type board struct {
state int
rows int
columns int
}
/* Creates a new Board with the given dimensions. The dimensions, rows and columns,
must be positive integers greater than 0.
Returns a board populated with a random state. */
func NewRandomBoard(rows, columns int) (board, error) {
if rows < 1 || columns < 1 {
return board{}, errors.New("rows and columns must be a positive integer greater than 0")
}
initState := make(int, rows)
for i := range initState {
initState[i] = make(int, columns)
}
rand.Seed(time.Now().UnixNano())
// Populate random state
for i := range initState {
for j := range initState[i] {
initState[i][j] = rand.Intn((1 -0 + 1) + 0)
}
}
return board{state: initState, rows:rows, columns:columns}, nil
}
func NewBoard(initialState int) (board, error) {
if initialState == nil {
return board{}, errors.New("initialState cannot be nil")
}
if len(initialState) < 1 || len(initialState[0]) < 1 {
return board{}, errors.New("initialState must contain at least 1 row and 1 column")
}
colSize := len(initialState[0])
for i := 0; i < len(initialState); i++ {
if colSize != len(initialState[i]) {
return board{}, errors.New("initialState is a jagged 2D array, initialState cannot be jagged")
}
for j := 0; j < len(initialState[i]); j++ {
cellValue := initialState[i][j]
if cellValue < 0 || cellValue > 1 {
return board{}, errors.New("initialState may only contain values 0 or 1")
}
}
}
return board{state:initialState, rows: len(initialState), columns: len(initialState[0])}, nil
}
func (b *board) Evolve() {
newState := make(int, b.rows)
for i := range newState {
newState[i] = make(int, b.columns)
for j := range newState[i] {
newState[i][j] = nextStateForCell(b,i,j)
}
}
b.state = newState
}
func (b *board) State() int {
return b.state
}
func (b *board) Rows() int {
return b.rows
}
func (b *board) Columns() int {
return b.columns
}
func (b *board) PrettyPrint() {
for i := range b.state {
for j := range b.state[i] {
print(" " + strconv.Itoa(b.state[i][j]) + "")
}
println()
}
}
func nextStateForCell(b *board, i,j int) int {
neighborsAlive := 0
cellValue := b.state[i][j]
for x := -1; x <= 1; x++ {
for y := -1; y <= 1; y++ {
if i + x < 0 || i + x > (b.rows - 1) || y + j < 0 || y + j > (b.columns - 1) {
continue
}
neighborsAlive += b.state[i + x][y + j]
}
}
neighborsAlive -= cellValue
if cellValue == CellDead && neighborsAlive == 3 {
return CellAlive
} else if cellValue == CellAlive && (neighborsAlive < 2 || neighborsAlive > 3) {
return CellDead
} else {
return cellValue
}
}
The main file
package main
import (
"io.jkratz/katas/life/board"
)
func main() {
myBoard, err := board.NewRandomBoard(10, 10)
if err != nil {
panic("Failed to instantiate board")
}
myBoard.PrettyPrint()
println()
myBoard.Evolve()
myBoard.PrettyPrint()
}
go game-of-life
I decided to give Go a try and implemented a Game of Life Kata exercise in GOLang. I have no prior experience in Go and the majority of my experience comes from Java, C#, and Python. My code appears to be working as intended but not sure if I've implemented it in the GO way, or idiomatic Go.
I've seen a few Go examples online where the properties of the struct were always public, but that feels foreign coming from the object-orient world. The way I've implemented it the Board struct should never be able to get into an invalid state. I don't know if that is a mindset that is shared by the Go community.
I have a colleague who is big into Go and favors immutability and no side effects. I can see how that would be ideal for concurrency, but does the general Go community prefer avoiding mutations? As an example I could have implemented my Evolve method to return a new Board struct rather than mutate its state property.
Is there anything else that stands out as not being Go like?
package board
import (
"errors"
"math/rand"
"strconv"
"time"
)
const CellDead = 0
const CellAlive = 1
type board struct {
state int
rows int
columns int
}
/* Creates a new Board with the given dimensions. The dimensions, rows and columns,
must be positive integers greater than 0.
Returns a board populated with a random state. */
func NewRandomBoard(rows, columns int) (board, error) {
if rows < 1 || columns < 1 {
return board{}, errors.New("rows and columns must be a positive integer greater than 0")
}
initState := make(int, rows)
for i := range initState {
initState[i] = make(int, columns)
}
rand.Seed(time.Now().UnixNano())
// Populate random state
for i := range initState {
for j := range initState[i] {
initState[i][j] = rand.Intn((1 -0 + 1) + 0)
}
}
return board{state: initState, rows:rows, columns:columns}, nil
}
func NewBoard(initialState int) (board, error) {
if initialState == nil {
return board{}, errors.New("initialState cannot be nil")
}
if len(initialState) < 1 || len(initialState[0]) < 1 {
return board{}, errors.New("initialState must contain at least 1 row and 1 column")
}
colSize := len(initialState[0])
for i := 0; i < len(initialState); i++ {
if colSize != len(initialState[i]) {
return board{}, errors.New("initialState is a jagged 2D array, initialState cannot be jagged")
}
for j := 0; j < len(initialState[i]); j++ {
cellValue := initialState[i][j]
if cellValue < 0 || cellValue > 1 {
return board{}, errors.New("initialState may only contain values 0 or 1")
}
}
}
return board{state:initialState, rows: len(initialState), columns: len(initialState[0])}, nil
}
func (b *board) Evolve() {
newState := make(int, b.rows)
for i := range newState {
newState[i] = make(int, b.columns)
for j := range newState[i] {
newState[i][j] = nextStateForCell(b,i,j)
}
}
b.state = newState
}
func (b *board) State() int {
return b.state
}
func (b *board) Rows() int {
return b.rows
}
func (b *board) Columns() int {
return b.columns
}
func (b *board) PrettyPrint() {
for i := range b.state {
for j := range b.state[i] {
print(" " + strconv.Itoa(b.state[i][j]) + "")
}
println()
}
}
func nextStateForCell(b *board, i,j int) int {
neighborsAlive := 0
cellValue := b.state[i][j]
for x := -1; x <= 1; x++ {
for y := -1; y <= 1; y++ {
if i + x < 0 || i + x > (b.rows - 1) || y + j < 0 || y + j > (b.columns - 1) {
continue
}
neighborsAlive += b.state[i + x][y + j]
}
}
neighborsAlive -= cellValue
if cellValue == CellDead && neighborsAlive == 3 {
return CellAlive
} else if cellValue == CellAlive && (neighborsAlive < 2 || neighborsAlive > 3) {
return CellDead
} else {
return cellValue
}
}
The main file
package main
import (
"io.jkratz/katas/life/board"
)
func main() {
myBoard, err := board.NewRandomBoard(10, 10)
if err != nil {
panic("Failed to instantiate board")
}
myBoard.PrettyPrint()
println()
myBoard.Evolve()
myBoard.PrettyPrint()
}
go game-of-life
go game-of-life
asked 20 mins ago
jkratz55
1133
1133
add a comment |
add a comment |
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210620%2fgolang-game-of-life-implementation%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210620%2fgolang-game-of-life-implementation%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown