-
Notifications
You must be signed in to change notification settings - Fork 1
/
gof.js
191 lines (170 loc) · 4.53 KB
/
gof.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
var gamejs = require('gamejs');
var SurfaceArray = require('gamejs/surfacearray').SurfaceArray;
var blitArray = require('gamejs/surfacearray').blitArray;
var CELL_SIZE = 5; // pixel size of cell
var DIRS = [
[1,0],
[0,1],
[1,1],
[-1,0],
[0, -1],
[-1,-1],
[-1,1],
[1,-1]
];
var DIRS_LENGTH = DIRS.length;
/*
*
* For a space that is 'populated':
* Each cell with one or no neighbors dies, as if by loneliness.
* Each cell with two or three neighbors survives.
* Each cell with four or more neighbors dies, as if by overpopulation.
*
* For a space that is 'empty' or 'unpopulated'
* Each cell with three neighbors becomes populated.
*/
exports.Map = function (dims) {
var W = parseInt(dims[0] / CELL_SIZE, 10);
var H = parseInt(dims[1] / CELL_SIZE, 10);
var paused = true;
this.togglePaused = function() {
paused = !paused;
};
this.forceUpdate = function() {
// FIXME force on update() but then we'd have update(ms, force)
paused = false;
this.update();
paused = true;
return;
};
/**
* Set cell at mousePos to alive. Transforms passed mouse position
* to map position.
*/
this.setAt = function(mousePos) {
var x = parseInt(mousePos[1] / CELL_SIZE, 10);
var y = parseInt(mousePos[0] / CELL_SIZE, 10);
if (x<0 || y<0) return;
if (y>=W || x>=H) return;
set(map, x, y, true);
return;
}
/**
* Draw game of life map to screen.
*/
this.draw = function(display) {
var x, y;
var color = null;
var m = null;
for (var i=0; i<H; i++) {
for (var j=0; j<W; j++) {
m = map[i][j];
if (m.modified === true) {
color = [255, 100, 255];
if (m.alive === false) {
color = [255, 255, 255];
}
y = i * CELL_SIZE;
x = j * CELL_SIZE;
srfarray.set(x, y, color);
srfarray.set(x-1, y-1, color);
srfarray.set(x+1, y+1, color);
srfarray.set(x-1, y+1, color);
srfarray.set(x+1, y-1, color);
}
}
}
blitArray(display, srfarray);
};
/**
* set position to alive and update the neighbors
* caches.
*/
function set(cMap, x, y, alive) {
if (cMap[x][y].alive === alive) {
return;
}
cMap[x][y].alive = alive;
cMap[x][y].modified = true;
for (var i=0; i < DIRS_LENGTH; i++) {
var dir = DIRS[i];
var nx = x + dir[0];
var ny = y + dir[1];
if (nx < 0 || ny < 0) continue;
if (nx >= H || ny >= W) continue;
if (alive) {
cMap[nx][ny].neighbors += 1;
} else if (cMap[nx][ny].neighbors > 0) {
cMap[nx][ny].neighbors -= 1;
}
}
return;
}
/**
* Update map according to game of life rules
*/
this.update = function() {
if (paused === true) return;
// copy
var newMap = getMapClone();
for (var i=0; i<H; i++) {
for (var j=0; j<W; j++) {
var neighbors = map[i][j].neighbors;
var alive = map[i][j].alive;
if (alive === true) {
if (neighbors != 2 && neighbors != 3) {
set(newMap, i, j, false);
}
} else if (neighbors === 3) {
set(newMap, i, j, true);
}
}
}
map = newMap;
return;
};
this.clear = function() {
initMap();
};
function initMap() {
map = [];
for (var i=0; i<H; i++) {
map[i] = [];
for (var j=0; j<W; j++) {
map[i][j] = {
alive: false,
neighbors: 0,
modified: true
};
}
}
return;
};
function getMapClone() {
return map.map(function(r) {
return r.map(function(i) {
return {
alive: i.alive,
neighbors: i.neighbors
};
});
});
}
this.random = function() {
var c= ((W * H) / 5);
for (var i=0;i<c;i++) {
var x = parseInt(Math.random() * H, 10);
var y = parseInt(Math.random() * W, 10);
set(map, x, y, true);
}
};
/**
* Constructor randomly sets some cells alive.
*/
var map = [];
initMap();
this.random();
this.rect = new gamejs.Rect([0,0], [W * CELL_SIZE, H * CELL_SIZE]);
var srfarray = SurfaceArray([this.rect.width, this.rect.height]);
return this;
};