Compare commits

..

No commits in common. "6eeba8f9d05123f7c3f150cd599478d3424dba22" and "fd35af10acfd12fb0f1915c64575ee2defb03ef2" have entirely different histories.

5 changed files with 32 additions and 159 deletions

View File

@ -1,9 +1,7 @@
package main
import (
"errors"
"math/rand"
"time"
"github.com/go-resty/resty/v2"
)
type Cell struct {
@ -12,101 +10,20 @@ type Cell struct {
live bool
}
func (c *Cell) NeighborCount(arr [][]Cell) int {
// Read grid dimensions
width := len(arr)
height := len(arr[0])
func (c *Cell) NeighborCount() int {
count := 0
// Iterate through 3x3 neighboring grid
for i := -1; i <= 1; i++ {
for j := -1; j <= 1; j++ {
// Ignore own position
if i == 0 && j == 0 {
continue
}
// Get neighbor coordinates
nx := (c.x + i + width) % width
ny := (c.y + j + height) % height
// Count if neighbor is alive
if arr[nx][ny].live {
count++
}
}
}
return count
}
func initGrid(width, height int, parent ...[][]Cell) ([][]Cell, error) {
exists := len(parent) == 1
if exists && len(parent) > 1 {
return nil, errors.New("Too many parents specified")
}
// Make first dimension
cells := make([][]Cell, width)
for i := 0; i < width; i++ {
// Make second dimension
cells[i] = make([]Cell, height)
for j := 0; j < height; j++ {
// Make cells
cells[i][j].x = i
cells[i][j].y = j
// If specified, copy state from parent
if exists {
cells[i][j].live = parent[0][i][j].live
} else {
cells[i][j].live = rand.Intn(2) == 1
}
}
}
return cells, nil
func coordinatesToIndex(x int, y int) int {
return x + y*width
}
func setup(callback func([][]Cell), width, height int, FPS time.Duration) chan bool {
// Initialize grid
grid, _ := initGrid(width, height)
var grid []Cell
// Prepare ticker and finishing flag
ticker := time.NewTicker((1000 / FPS) * time.Millisecond)
done := make(chan bool)
func setup(client *resty.Client, url, width int, height int) {
// Run game loop
go func() {
for {
select {
case <-done:
return
case <-ticker.C:
grid = draw(grid, callback)
}
}
}()
// Return flag to be stopped outside
return done
}
func draw(grid [][]Cell, callback func([][]Cell)) [][]Cell {
generation, _ := initGrid(len(grid), len(grid[0]), grid)
// Iterate through grid
for i := 0; i < len(grid); i++ {
for j := 0; j < len(grid[0]); j++ {
// Count neighbors
cout := grid[i][j].NeighborCount(grid)
// Get state
curr := grid[i][j].live
// Apply rules
died := curr && (cout < 2 || cout > 3)
born := !curr && cout == 3
next := curr && !died || born
// Set state
generation[i][j].live = next
// A * !(A * (B + C)) + !A * D
// = A * !B * !C + !A * D
// curr && cout >= 2 && cout <= 3 || !curr && cout == 3
}
}
callback(generation)
return generation
func draw() {
}

9
go.mod
View File

@ -3,12 +3,7 @@ module example.com/MatrixGameOfLife
go 1.22.1
require (
github.com/go-resty/resty/v2 v2.12.0
github.com/joho/godotenv v1.5.1
github.com/buger/goterm v1.0.4
)
require (
github.com/go-resty/resty/v2 v2.12.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.19.0 // indirect
)

6
go.sum
View File

@ -1,5 +1,3 @@
github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY=
github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE=
github.com/go-resty/resty/v2 v2.12.0 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA=
github.com/go-resty/resty/v2 v2.12.0/go.mod h1:o0yGPrkS3lOe1+eFajk6kBW8ScXzwU3hD69/gt2yB/0=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
@ -25,7 +23,6 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -33,8 +30,6 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@ -47,7 +42,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=

54
main.go
View File

@ -1,42 +1,13 @@
package main
import (
"fmt"
"log"
"github.com/buger/goterm"
"github.com/go-resty/resty/v2"
"github.com/joho/godotenv"
)
func output(client *resty.Client, url string, width, height int, arr [][]Cell) {
goterm.MoveCursor(1, 2)
// Prepare instructions for matrix
instructions := make([]interface{}, 0)
// Append all live cells as pixel instructions
for j := 0; j < height; j++ {
for i := 0; i < width; i++ {
if arr[i][j].live {
instructions = append(instructions, Pixel{X: i, Y: j, Endpoint: PIXEL})
goterm.Print("X")
continue
}
goterm.Print(" ")
}
goterm.Println()
}
// Append update instruction
instructions = append(instructions, Update{Endpoint: UPDATE})
// Send to matrix
sendRequest(client, url, instructions)
// Update terminal UI
goterm.Flush()
}
func main() {
const FPS = 10
// Load .env file if it exists
err := godotenv.Load(".env")
if err != nil {
@ -45,20 +16,23 @@ func main() {
// Load env server data
url, width, height := loadMatrixData()
goterm.Printf("On '%s' at [%d x %d] with %d FPS\n", url, width, height, FPS)
log.Printf("At '%s': %d x %d\n", url, width, height)
// Initialize resty client
client := resty.New()
// Initialize pixel color
sendRequest(client, url, []interface{}{Color{R: 255, G: 255, B: 255, Endpoint: COLOR}})
// Run Game of Life
done := setup(func(c [][]Cell) {
output(client, url, width, height, c)
}, width, height, FPS)
// Initialize custom matrix data
col := Color{R: 255, G: 0, B: 255, Endpoint: COLOR}
rct := Rectangle{X: 0, Y: 0, W: 10, H: 10, Endpoint: RECTANGLE}
// Wait for user input to quit
fmt.Scanln()
// Stop Game of Life, wait for routine
done <- true
// Send request to remote server
sendRequest(client, url, []interface{}{col, rct})
// Initialize custom matrix data
col = Color{R: 255, G: 255, B: 0, Endpoint: COLOR}
rct = Rectangle{X: 15, Y: 15, W: 15, H: 15, Endpoint: RECTANGLE}
upd := Update{Endpoint: UPDATE}
// Send request to remote server
sendRequest(client, url, []interface{}{col, rct, upd})
}

View File

@ -9,31 +9,24 @@ type Endpoint string
const (
RECTANGLE Endpoint = "rectangle"
UPDATE Endpoint = "update"
PIXEL Endpoint = "pixel"
COLOR Endpoint = "color"
)
type Rectangle struct {
X int `json:"x"`
Y int `json:"y"`
W uint `json:"w"`
H uint `json:"h"`
Endpoint Endpoint `json:"endpoint"`
}
type Update struct {
Endpoint Endpoint `json:"endpoint"`
}
type Pixel struct {
X int `json:"x"`
Y int `json:"y"`
Endpoint Endpoint `json:"endpoint"`
}
type Color struct {
R uint8 `json:"r"`
G uint8 `json:"g"`
B uint8 `json:"b"`
Endpoint Endpoint `json:"endpoint"`
}
type Rectangle struct {
X int `json:"x"`
Y int `json:"y"`
W uint `json:"w"`
H uint `json:"h"`
Endpoint Endpoint `json:"endpoint"`
}