Skip to content

Instantly share code, notes, and snippets.

@NPashaP
Last active August 29, 2015 14:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NPashaP/f1e73faef87bee899b47 to your computer and use it in GitHub Desktop.
Save NPashaP/f1e73faef87bee899b47 to your computer and use it in GitHub Desktop.
Conway's Game of Life

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

  • If n(x) <= 1, then x dies or stays dead (from under population).
  • If n(x) > 3, then x dies or stays dead (from over population).
  • if n(x) = 3, then x is born or stays alive.
  • if n(x) = 2, then x maintains status.

In this implementation you can do the following:

  • Select one of the Sample patterns and click start to let time progress.
  • or Click new and create a pattern by clicking squares and then press start button.
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;
}());
<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="http://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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment