/
life.js
144 lines (127 loc) · 4.1 KB
/
life.js
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
import { glider, nextState } from './lifeCommon.js'
import {
Command,
GUI,
Integer,
Key,
Control
} from '../libraries/gui/gui.js'
import { getLargeCanvas } from '../libraries/misc.js'
// Simple and non-optimised (no hashlife) version of Conway's Game of Life. You
// can control cell size with i (increase) and d (decrease). Use c to toggle an
// overlay with the current cell size
const sketch = (s) => {
const gapX = 10
const gapY = 10
let rectSize = 10
let cells, rows, columns, cnt = 0
let stateMatrix = [],
nextStateMatrix = []
let gui
s.setup = () => {
let {w, h} = getLargeCanvas(s, 1600)
let canvas = s.createCanvas(w, h)
canvas.mousePressed (() => {
// Touch to add a glider. Why not
let i = s.int(s.mouseX/rectSize)
let j = s.int(s.mouseY/rectSize)
glider(i, j, stateMatrix, rows, columns)
})
s.frameRate(20)
setupMatrix()
randomise()
gui = createGUI()
gui.toggle()
}
function setupMatrix() {
// Prepares two empty arrays to store states (current and next)
columns = s.int(s.windowWidth / rectSize)
rows = s.int(s.windowHeight / rectSize)
stateMatrix = Array(columns)
nextStateMatrix = Array(columns)
for (let i = 0; i < columns; i++) {
stateMatrix[i] = Array(rows)
.fill(0);
nextStateMatrix[i] = Array(rows)
.fill(0);
}
// Prepares a static indexer, somehow this runs faster on iOS Safari than
// usual for loops. Go figure
cells = []
for (let j = 0; j < rows; j++) {
for (let i = 0; i < columns; i++) {
cells.push([i, j])
}
}
}
function randomise() {
// Randomise current state matrix
for (let cell of cells) {
let [i, j] = cell
stateMatrix[i][j] = s.int(s.random(2))
}
}
s.draw = () => {
s.rectMode(s.CENTER);
s.strokeWeight(2);
s.stroke(60, 60, 30)
for (let cell of cells) {
let [i, j] = cell
s.push()
s.translate(gapX / 2 + i * rectSize, gapY / 2 + j * rectSize)
s.beginShape()
if (stateMatrix[i][j] == 1) {
s.fill(20, 20, 20)
} else {
s.fill(100, 100, 100)
}
nextStateMatrix[i][j] = nextState(i, j, stateMatrix, rows, columns)
s.rect(0, 0, rectSize, rectSize)
s.endShape();
s.pop()
}
// Advance states and clean next
for (let cell of cells) {
let [i, j] = cell
stateMatrix[i][j] = nextStateMatrix[i][j]
nextStateMatrix[i][j] = 0
}
}
function createGUI(){
let info =
`Tap/click on the canvas generate a glider`
let subinfo = ""
let G = new Key("g", () => {
setupMatrix()
glider(s.int(s.random(rows)), s.int(s.random(columns)), stateMatrix, rows, columns)
})
let resetCanvas = new Command(G, "clear the canvas and place a random glider")
let incR = new Key(")", () => {
rectSize++
setupMatrix()
randomise()
})
let decR = new Key("(", () => {
if (rectSize > 4) {
rectSize--
}
setupMatrix()
randomise()
})
let rectSizeInt = new Integer(() => rectSize)
let rectSizeControl = new Control([decR, incR],
"+/- cell size", rectSizeInt)
let gui = new GUI("Conway's Game of Life, RB 2020/05", info, subinfo, [resetCanvas],
[rectSizeControl])
let QM = new Key("?", () => gui.toggle())
let hide = new Command(QM, "hide this")
gui.addCmd(hide)
gui.update()
return gui
}
s.keyReleased = () => {
gui.dispatch(s.key)
}
}
p5.disableFriendlyErrors = true
let p5sketch = new p5(sketch)