mirror of
https://gitlab1.ptb.de/waltem01/Matrix
synced 2024-12-27 04:21:45 +00:00
Compare commits
22 Commits
fd35af10ac
...
6eeba8f9d0
Author | SHA1 | Date | |
---|---|---|---|
6eeba8f9d0 | |||
2bb893e9a8 | |||
b462335db4 | |||
00886d2e07 | |||
0c3d18afbe | |||
93322ad555 | |||
27f84eca71 | |||
9f2f76aa70 | |||
60a7e38c67 | |||
0ad98fe992 | |||
1138458e0a | |||
c97d6c68e9 | |||
34d9491421 | |||
287c65c28e | |||
511a837495 | |||
6e88f0f750 | |||
3403886e48 | |||
30e6c4a35b | |||
80984f8243 | |||
b66f12b7c6 | |||
e57b501178 | |||
cbae0f6732 |
99
conway.go
99
conway.go
@ -1,7 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-resty/resty/v2"
|
"errors"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Cell struct {
|
type Cell struct {
|
||||||
@ -10,20 +12,101 @@ type Cell struct {
|
|||||||
live bool
|
live bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cell) NeighborCount() int {
|
func (c *Cell) NeighborCount(arr [][]Cell) int {
|
||||||
|
// Read grid dimensions
|
||||||
|
width := len(arr)
|
||||||
|
height := len(arr[0])
|
||||||
|
|
||||||
|
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 coordinatesToIndex(x int, y int) int {
|
func initGrid(width, height int, parent ...[][]Cell) ([][]Cell, error) {
|
||||||
return x + y*width
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
var grid []Cell
|
func setup(callback func([][]Cell), width, height int, FPS time.Duration) chan bool {
|
||||||
|
// Initialize grid
|
||||||
|
grid, _ := initGrid(width, height)
|
||||||
|
|
||||||
func setup(client *resty.Client, url, width int, height int) {
|
// Prepare ticker and finishing flag
|
||||||
|
ticker := time.NewTicker((1000 / FPS) * time.Millisecond)
|
||||||
|
done := make(chan bool)
|
||||||
|
|
||||||
|
// 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() {
|
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
|
||||||
}
|
}
|
||||||
|
11
go.mod
11
go.mod
@ -3,7 +3,12 @@ module example.com/MatrixGameOfLife
|
|||||||
go 1.22.1
|
go 1.22.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-resty/resty/v2 v2.12.0 // indirect
|
github.com/go-resty/resty/v2 v2.12.0
|
||||||
github.com/joho/godotenv v1.5.1 // indirect
|
github.com/joho/godotenv v1.5.1
|
||||||
golang.org/x/net v0.24.0 // indirect
|
github.com/buger/goterm v1.0.4
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
golang.org/x/net v0.24.0 // indirect
|
||||||
|
golang.org/x/sys v0.19.0 // indirect
|
||||||
)
|
)
|
||||||
|
6
go.sum
6
go.sum
@ -1,3 +1,5 @@
|
|||||||
|
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 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA=
|
||||||
github.com/go-resty/resty/v2 v2.12.0/go.mod h1:o0yGPrkS3lOe1+eFajk6kBW8ScXzwU3hD69/gt2yB/0=
|
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=
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
@ -23,6 +25,7 @@ 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/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-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-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-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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -30,6 +33,8 @@ 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.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.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.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-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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
@ -42,6 +47,7 @@ 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.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.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
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/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
54
main.go
54
main.go
@ -1,13 +1,42 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"github.com/buger/goterm"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
"github.com/joho/godotenv"
|
"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() {
|
func main() {
|
||||||
|
const FPS = 10
|
||||||
|
|
||||||
// Load .env file if it exists
|
// Load .env file if it exists
|
||||||
err := godotenv.Load(".env")
|
err := godotenv.Load(".env")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -16,23 +45,20 @@ func main() {
|
|||||||
|
|
||||||
// Load env server data
|
// Load env server data
|
||||||
url, width, height := loadMatrixData()
|
url, width, height := loadMatrixData()
|
||||||
log.Printf("At '%s': %d x %d\n", url, width, height)
|
goterm.Printf("On '%s' at [%d x %d] with %d FPS\n", url, width, height, FPS)
|
||||||
|
|
||||||
// Initialize resty client
|
// Initialize resty client
|
||||||
client := resty.New()
|
client := resty.New()
|
||||||
|
// Initialize pixel color
|
||||||
|
sendRequest(client, url, []interface{}{Color{R: 255, G: 255, B: 255, Endpoint: COLOR}})
|
||||||
|
|
||||||
// Initialize custom matrix data
|
// Run Game of Life
|
||||||
col := Color{R: 255, G: 0, B: 255, Endpoint: COLOR}
|
done := setup(func(c [][]Cell) {
|
||||||
rct := Rectangle{X: 0, Y: 0, W: 10, H: 10, Endpoint: RECTANGLE}
|
output(client, url, width, height, c)
|
||||||
|
}, width, height, FPS)
|
||||||
|
|
||||||
// Send request to remote server
|
// Wait for user input to quit
|
||||||
sendRequest(client, url, []interface{}{col, rct})
|
fmt.Scanln()
|
||||||
|
// Stop Game of Life, wait for routine
|
||||||
// Initialize custom matrix data
|
done <- true
|
||||||
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})
|
|
||||||
}
|
}
|
||||||
|
23
types.go
23
types.go
@ -9,24 +9,31 @@ type Endpoint string
|
|||||||
const (
|
const (
|
||||||
RECTANGLE Endpoint = "rectangle"
|
RECTANGLE Endpoint = "rectangle"
|
||||||
UPDATE Endpoint = "update"
|
UPDATE Endpoint = "update"
|
||||||
|
PIXEL Endpoint = "pixel"
|
||||||
COLOR Endpoint = "color"
|
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 {
|
type Update struct {
|
||||||
Endpoint Endpoint `json:"endpoint"`
|
Endpoint Endpoint `json:"endpoint"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Pixel struct {
|
||||||
|
X int `json:"x"`
|
||||||
|
Y int `json:"y"`
|
||||||
|
Endpoint Endpoint `json:"endpoint"`
|
||||||
|
}
|
||||||
|
|
||||||
type Color struct {
|
type Color struct {
|
||||||
R uint8 `json:"r"`
|
R uint8 `json:"r"`
|
||||||
G uint8 `json:"g"`
|
G uint8 `json:"g"`
|
||||||
B uint8 `json:"b"`
|
B uint8 `json:"b"`
|
||||||
Endpoint Endpoint `json:"endpoint"`
|
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"`
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user