Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
Signed-off-by: Simon Waldherr <[email protected]>
  • Loading branch information
SimonWaldherr committed Aug 30, 2024
1 parent 8d325ed commit a70bb55
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 31 deletions.
12 changes: 6 additions & 6 deletions cmd/cgol/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import (
)

var (
framesPerSecond int
framesPerSecond int
terminalWidth int
terminalHeight int
gameDuration int
gifOutputLength int
inputFilename string
gifOutputFilename string
port string
gameDuration int
gifOutputLength int
inputFilename string
gifOutputFilename string
port string
)

var field *life.Field
Expand Down
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module simonwaldherr.de/go/cgolGo

go 1.23.0

require simonwaldherr.de/go/golibs v0.18.0
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
simonwaldherr.de/go/golibs v0.18.0 h1:l01hMHmY8A/j2Nf6nx75f5/dTofUSGUiSNKwKrEIvqM=
simonwaldherr.de/go/golibs v0.18.0/go.mod h1:sW7x4PAds/r6rLt/THqsZhpFxoq2n6cBb5QtlZ44eVk=
14 changes: 7 additions & 7 deletions life/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ import (
"strconv"
)

// Field contains all informations about the current status of all cells
// Field represents the grid in the Game of Life.
type Field struct {
cells [][]int
width int
height int
width, height int
cells [][]int
}

// newField initializes a new Field with the given width and height.
func newField(width, height int) *Field {
cells := make([][]int, height)
for cols := range cells {
cells[cols] = make([]int, width)
for i := range cells {
cells[i] = make([]int, width)
}
return &Field{cells: cells, width: width, height: height}
return &Field{width: width, height: height, cells: cells}
}

// GenerateFirstRound generates a new field with a (pseudo) random seed
Expand Down
98 changes: 80 additions & 18 deletions life/life.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,61 @@ package life

import (
"bytes"
"errors"
"fmt"
"math/rand"
)

// GetCells returns the non-public cells value of the field
// GetCells returns a copy of the cells in the Field to prevent external modification.
func (field *Field) GetCells() [][]int {
return field.cells
cellsCopy := make([][]int, field.height)
for i := range field.cells {
cellsCopy[i] = append([]int(nil), field.cells[i]...)
}
return cellsCopy
}

// SetCells allows setting the cells of the field directly if the dimensions match.
func (field *Field) SetCells(cells [][]int) error {
if len(cells) != field.height || (len(cells) > 0 && len(cells[0]) != field.width) {
return errors.New("dimensions of the provided cells do not match the field")
}
field.cells = cells
return nil
}

func (field *Field) setVitality(x, y int, vitality int) {
x += field.width
x %= field.width
y += field.height
y %= field.height
// setVitality sets the vitality (alive or dead) of the cell at the given coordinates.
// Coordinates are wrapped around the field dimensions.
func (field *Field) setVitality(x, y, vitality int) {
x = (x + field.width) % field.width
y = (y + field.height) % field.height
field.cells[y][x] = vitality
}

// getVitality returns the vitality (alive or dead) of the cell at the given coordinates.
// Coordinates are wrapped around the field dimensions.
func (field *Field) getVitality(x, y int) int {
x += field.width
x %= field.width
y += field.height
y %= field.height
x = (x + field.width) % field.width
y = (y + field.height) % field.height
return field.cells[y][x]
}

// LivingNeighbors returns the number of living neighbors of a cell
// LivingNeighbors counts and returns the number of living neighbors for the cell at (x, y).
func (field *Field) LivingNeighbors(x, y int) int {
alive := 0
for i := -1; i <= 1; i++ {
for j := -1; j <= 1; j++ {
if (j != 0 || i != 0) && (field.getVitality(x+i, y+j) > 0) {
alive++
if i != 0 || j != 0 { // skip the cell itself
if field.getVitality(x+i, y+j) > 0 {
alive++
}
}
}
}
return alive
}

// NextVitality returns the vitality of a cell in the next round
// NextVitality determines and returns the vitality of the cell at (x, y) in the next round.
func (field *Field) NextVitality(x, y int) int {
livingNeighbors := field.LivingNeighbors(x, y)
isLiving := field.getVitality(x, y) > 0
Expand All @@ -48,7 +66,7 @@ func (field *Field) NextVitality(x, y int) int {
return 0
}

// NextRound looks at every cell and calculates its new value, it returns the new field
// NextRound calculates and returns the field state in the next round of the game.
func (field *Field) NextRound() *Field {
newFieldVar := newField(field.width, field.height)
for y := 0; y < field.height; y++ {
Expand All @@ -59,18 +77,62 @@ func (field *Field) NextRound() *Field {
return newFieldVar
}

// PrintField returns a string representing the value of all cells
// PrintField returns a string representation of the field's current state.
// Living cells are represented by "█" and dead cells by " ".
func (field *Field) PrintField() string {
var buffer bytes.Buffer
for y := 0; y < field.height; y++ {
for x := 0; x < field.width; x++ {
if field.getVitality(x, y) > 0 {
buffer.WriteString("█")
} else {
buffer.WriteByte(byte(' '))
buffer.WriteString(" ")
}
}
buffer.WriteByte('\n')
}
return buffer.String()
}

// IsEmpty checks if the field is completely empty (no living cells).
func (field *Field) IsEmpty() bool {
for y := 0; y < field.height; y++ {
for x := 0; x < field.width; x++ {
if field.getVitality(x, y) > 0 {
return false
}
}
}
return true
}

// PopulateRandomly populates the field with random cells set to alive based on a given density.
func (field *Field) PopulateRandomly(density float64) error {
if density < 0 || density > 1 {
return errors.New("density must be between 0 and 1")
}
for y := 0; y < field.height; y++ {
for x := 0; x < field.width; x++ {
if rand.Float64() < density {
field.setVitality(x, y, 1)
} else {
field.setVitality(x, y, 0)
}
}
}
return nil
}

// PrintSummary prints a summary of the field's current state including dimensions and number of living cells.
func (field *Field) PrintSummary() {
livingCells := 0
for y := 0; y < field.height; y++ {
for x := 0; x < field.width; x++ {
if field.getVitality(x, y) > 0 {
livingCells++
}
}
}
fmt.Printf("Field Dimensions: %dx%d\n", field.width, field.height)
fmt.Printf("Living Cells: %d\n", livingCells)
}

0 comments on commit a70bb55

Please sign in to comment.