Conway’s Game of life is a Cellular automata. The universe is an infinite two dimensional orthogonal grid consisting of square cells. At any given time each cell is either alive or dead. As time progresses discretely, the status of each cell is determined by the number of live cells in the 8 most adjacent squares of the cell.
Let n(x) be the number of lives cells in the 8 most adjacent squares of square x at time t. As time moves to t+1
In this implementation you can do the following:
<html>
<head>
<title>Conway's Game of Life</title>
<style>
body{
width:960px;
margin:0 auto;
}
rect{
stroke:rgba(204, 204,204,0.2);
shape-rendering:crispEdges;
}
.edit:hover{
stroke:steelblue;
cursor:pointer;
}
select{
width:80px;
}
button{
min-width:50px;
padding: 0 40px;
}
</style>
</head>
<body><section style="display:block;">
Sample Patterns: <select onchange="changeUniv(this)"></select>
<button type="button" onClick="newUniv()">New</button>
<button type="button" onClick="startUniv()" id='startBtn'>Start</button>
</section>
<svg width='796' height='448'></svg>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="goL.js"></script>
<script src="goL games.js"></script>
<script>
function newUniv(){
goL.setGrid();
goL.editMode(true);
d3.select("#startBtn").html("Start");
}
function startUniv(){
if(d3.select("#startBtn").html()=="Start"){
d3.select("#startBtn").html("Pause");
goL.editMode(false);
goL.update();
}else{
d3.select("#startBtn").html("Start");
goL.editMode(true);
goL.clearTimeout();
}
}
function changeUniv(t){
goL.setGrid(games[t.options[t.selectedIndex].value]);
d3.select("#startBtn").html("Start");
goL.editMode(true);
}
d3.select("select").selectAll("option").data(d3.keys(games))
.enter().append("option").attr("value",function(d){ return d;})
.text(function(d){return d;});
goL.setGrid(games.Planes);
startUniv();
</script>
var games ={// list of sample games.
Planes:(function(){
var r = [
[ , , , , , , , , ,1, , , , , , , , , , , , , , , , , , , , , , , , , , ,0],
[ , , , , , , ,1, ,1, , , , , , , , , , , , , , , , , , , , , , , , , , ,0],
[ , , , , , ,1, ,1, , , , , , , , , , , , , , , , , ,1, , , , , , , , , ,0],
[1,1, , , , 1, , ,1, , , , , , , , , , , , , , , , , 1,1, , , , , , , , , ,0],
[1,1, , , , ,1, ,1, , , , , , , , , , , , , , , ,1, 1, , , , , 1,1, , , , ,0],
[ , , , , , , ,1, ,1, , , , , , , , , , , , , ,1,1, 1, , , , , 1,1, , ,1, 1,0],
[ , , , , , , , , ,1, , , , , , , , , , , , , , ,1, 1, , , , , 1,1, , ,1, 1,0],
[ , , , , , , , , , , , , , , , , , , , , , , , , , 1,1, , , , , , , , , ,0],
[ , , , , , , , , , , , , , , , , , , , , , , , , , ,1, , , , , , , , , ,0]];
var ret = d3.range(0,64).map(function(y){ return d3.range(0,128).map(function(x){ return 0;})});
//make two copies of r in ret.
d3.range(0,r.length).forEach(function(y){d3.range(0,r[0].length)
.forEach(function(x){ ret[y+4][x+60]=(r[y][x]==undefined ? 0: r[y][x]); })});
d3.range(0,r.length).forEach(function(y){d3.range(0,r[0].length)
.forEach(function(x){ ret[60-y][47-x]=(r[y][x]==undefined ? 0: r[y][x]); })});
return ret;
}()),
"Symm 4":(function(){
var r = [
[ ,1,1,1,0],
[1, , ,1,0],
[1, , , ,0],
[1,1,1, ,0]];
var ret = d3.range(0,64).map(function(y){ return d3.range(0,128).map(function(x){ return 0;})});
//make four copies of r.
d3.range(0,r.length).forEach(function(y){d3.range(0,r[0].length)
.forEach(function(x){ ret[y+26][x+40]=(r[y][x]==undefined ? 0: r[y][x]); })});
d3.range(0,r.length).forEach(function(y){d3.range(0,r[0].length)
.forEach(function(x){ ret[32-y][60-x]=(r[y][x]==undefined ? 0: r[y][x]); })});
d3.range(0,r.length).forEach(function(y){d3.range(0,r[0].length)
.forEach(function(x){ ret[39-x][47+y]=(r[y][x]==undefined ? 0: r[y][x]); })});
d3.range(0,r.length).forEach(function(y){d3.range(0,r[0].length)
.forEach(function(x){ ret[19+x][53-y]=(r[y][x]==undefined ? 0: r[y][x]); })});
return ret;
}())
}
var goL = (function(){
var goL ={},bits=64*128;
var dt; // grid bits
var i; // which dt is current?
var sp=20; // speed of animation. smaller = faster.
var timeClr ;// for clearing Timeout.
var editMode=false;
goL.clearGrid = function(){
dt = [ Array.apply(0, Array(bits/32)).map(function() { return 0; }),
Array.apply(0, Array(bits/32)).map(function() { return 0; })]; //enough bits for 64x128 grid
i =0;// 0 is current
}
goL.get = function(p){ // get status of pth bit
return (dt[i][p>>>5]&(0x80000000>>>(p&31))) ==0?0:1;
}
goL.put = function(p,s,j){ // set status of pth bit to s
s ? (dt[j][p>>>5]|=(0x80000000>>>(p&31))): (dt[j][p>>>5]&=~(0x80000000>>>(p&31)));
}
goL.clearTimeout = function(){
clearTimeout(timeClr);
}
goL.editMode = function(f){
editMode=f;
f? rects.attr('class',"edit") : rects.attr('class',"");
}
function switchSq(p){
if(!editMode) return;
goL.put(p,1-goL.get(p),i);
rects.style("fill",function(d){ return goL.get(d)==1? "steelblue":"white";});
}
goL.clearGrid();
var rects = d3.select("svg").selectAll("rect").data(d3.range(0,bits)).enter().append("rect")
.attr("x",function(d){ return (d&127)*7;})
.attr("y",function(d){ return (d>>>7)*7;})
.attr("width",7).attr("height",7)
.style("fill",function(d){ return goL.get(d)==1? "steelblue":"white";})
.on("click",function(d){ return switchSq(d);});
goL.setGrid = function(ar){ //set the initial bits
goL.clearGrid();
goL.clearTimeout();
if(arguments.length > 0){
d3.range(0,ar.length).forEach(function(y){d3.range(0,ar[0].length)
.forEach(function(x){goL.put(y*128+x,ar[y][x],i)})});
}
rects.style("fill",function(d){ return goL.get(d)==1? "steelblue":"white";});
}
goL.update = function(){
for(var p=0; p<bits; p++){
var q = p>>>7, r=p&127;// quotient and reminder
var n= (q>0 && r>0 ? goL.get(p-129): 0) + // number of neighbours
(q>0 ? goL.get(p-128): 0) +
(q>0 && r<127 ? goL.get(p-127): 0)+
(r>0 ? goL.get(p-1): 0) +
(r<127 ? goL.get(p+1): 0)+
(q<63 && r>0 ? goL.get(p+127): 0)+
(q<63 ? goL.get(p+128): 0)+
(q<63 && r<127 ? goL.get(p+129): 0);
if(n<=1 || n>3) goL.put(p, 0, 1-i);
else if(n==2) goL.put(p, goL.get(p), 1-i);
else goL.put(p, 1, 1-i);
}
i=1-i;// switch current
rects.style("fill",function(d){ return goL.get(d)==1? "steelblue":"white";});
timeClr = setTimeout(function(){goL.update()},sp);
}
return goL;
}());