block by NPashaP f1e73faef87bee899b47

Conway's Game of Life

Full Screen

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:

index.html

<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>

goL games.js

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;
	}())
}

goL.js

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;
}());