-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcgol.go.wasm.go
158 lines (138 loc) · 4.53 KB
/
cgol.go.wasm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//go:build js && wasm
package main
import (
"math/rand"
"syscall/js"
"time"
)
// Configuration variables
var (
cellSize = 10 // Size of each cell in pixels
density = 0.2 // Probability that a cell starts alive
aliveColor = "lime" // Color of alive cells
deadColor = "#000000" // Color of dead cells (currently not used)
fps = 10 // Frames per second
)
// Variables for grid dimensions and state
var (
width, height int // Grid dimensions
grid [][]bool // The simulation grid
canvas js.Value // Canvas DOM element
ctx js.Value // Canvas rendering context
)
func main() {
// Seed the random number generator
rand.Seed(time.Now().UnixNano())
// Get references to the DOM and window objects
document := js.Global().Get("document")
window := js.Global().Get("window")
// Get the canvas element by ID
canvas = document.Call("getElementById", "gameCanvas")
ctx = canvas.Call("getContext", "2d")
// Initialize the canvas and grid
initialize()
// Set up an event listener for window resize to adjust the canvas and grid
window.Call("addEventListener", "resize", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
initialize()
return nil
}))
// Start the simulation loop
go startSimulation()
// Prevent the Go program from exiting
select {}
}
// initialize sets up the canvas size and initializes the grid
func initialize() {
// Get the window dimensions
window := js.Global().Get("window")
canvasWidth := window.Get("innerWidth").Int()
canvasHeight := window.Get("innerHeight").Int()
// Resize the canvas to fill the window
canvas.Set("width", canvasWidth)
canvas.Set("height", canvasHeight)
// Calculate the grid dimensions based on the canvas size and cell size
width = canvasWidth / cellSize
height = canvasHeight / cellSize
// Initialize the grid with random alive cells
grid = initializeGrid()
}
// initializeGrid creates a grid of specified dimensions with random alive cells
func initializeGrid() [][]bool {
newGrid := make([][]bool, height)
for y := 0; y < height; y++ {
row := make([]bool, width)
for x := 0; x < width; x++ {
// Randomly set cells to alive based on the density
row[x] = rand.Float64() < density
}
newGrid[y] = row
}
return newGrid
}
// countNeighbors counts the number of alive neighbors around a cell at (x, y)
func countNeighbors(grid [][]bool, x, y int) int {
count := 0
// Loop through neighboring cells
for dy := -1; dy <= 1; dy++ {
for dx := -1; dx <= 1; dx++ {
// Skip the current cell
if dx == 0 && dy == 0 {
continue
}
// Calculate neighbor coordinates with wrapping (toroidal grid)
nx := (x + dx + width) % width
ny := (y + dy + height) % height
if grid[ny][nx] {
count++
}
}
}
return count
}
// computeNextState calculates the next generation of the grid
func computeNextState(grid [][]bool) [][]bool {
newGrid := make([][]bool, height)
for y := 0; y < height; y++ {
row := make([]bool, width)
for x := 0; x < width; x++ {
alive := grid[y][x]
neighbors := countNeighbors(grid, x, y)
// Apply Game of Life rules
if alive {
row[x] = neighbors == 2 || neighbors == 3
} else {
row[x] = neighbors == 3
}
}
newGrid[y] = row
}
return newGrid
}
// drawGrid renders the grid onto the canvas
func drawGrid(grid [][]bool) {
// Clear the canvas
ctx.Call("clearRect", 0, 0, canvas.Get("width").Int(), canvas.Get("height").Int())
// Set the fill style for alive cells
ctx.Set("fillStyle", aliveColor)
// Loop through the grid cells
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
if grid[y][x] {
// Draw alive cells
ctx.Call("fillRect", x*cellSize, y*cellSize, cellSize, cellSize)
}
}
}
}
// startSimulation runs the game loop at a specified frames per second
func startSimulation() {
ticker := time.NewTicker(time.Duration(1000/fps) * time.Millisecond)
defer ticker.Stop()
for {
select {
case <-ticker.C:
grid = computeNextState(grid)
drawGrid(grid)
}
}
}