Skip to content

Instantly share code, notes, and snippets.

@glena
Last active August 29, 2015 14:18
Show Gist options
  • Save glena/eb6dce8a38241912f9b2 to your computer and use it in GitHub Desktop.
Save glena/eb6dce8a38241912f9b2 to your computer and use it in GitHub Desktop.
Game of Life
{"description":"Game of Life","endpoint":"","display":"svg","public":true,"require":[],"fileconfigs":{"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":12},"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"style.css":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"fullscreen":false,"play":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"pingpong","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"ajax-caching":true,"thumbnail":"http://i.imgur.com/gB69Prj.png"}
var svg = d3.select("svg");
var rows = 60;
var cols = 90;
var marginBottom = 152;
var totalWidth = tributary.sw;
var totalHeight = tributary.sh - marginBottom;
var width = parseInt(totalWidth / cols);
var height = parseInt(totalHeight / rows);
function GameOflife(options) {
this.rows = options.rows;
this.cols = options.cols;
}
GameOflife.prototype.setInitialState = function(init) {
this.data = [];
for(var i = 0; i < this.rows; i++) {
for(var j = 0; j < this.cols; j++) {
this.data.push({ x: j, y: i, live: 0 });
}
}
for(i = 0; i < init.length; i++) {
var pos = this.getPos(init[i][0], init[i][1]);
this.data[pos].live = 1;
}
};
GameOflife.prototype.getPos = function(x, y) {
if ( x >= 0 && x < this.cols && y >= 0 && y < this.rows ) {
return (y * this.cols) + x;
}
return -1;
};
GameOflife.prototype.getCell = function(x, y) {
var pos = this.getPos(x, y);
if (pos >= 0 && pos < this.data.length ) {
return this.data[pos];
}
return {};
};
GameOflife.prototype.getNeighbours = function(cell) {
var x = cell.x;
var y = cell.y;
var cells = [];
cells.push(this.getCell(x - 1, y - 1));
cells.push(this.getCell(x - 1, y));
cells.push(this.getCell(x - 1, y + 1));
cells.push(this.getCell(x, y - 1));
cells.push(this.getCell(x, y + 1));
cells.push(this.getCell(x + 1, y - 1));
cells.push(this.getCell(x + 1, y));
cells.push(this.getCell(x + 1, y + 1));
return cells;
};
GameOflife.prototype.nextGeneration = function() {
var newData = [];
for(var i = 0; i < this.data.length; i++) {
var cell = this.data[i];
var live = 0;
var livesCount = 0;
var neighbours = this.getNeighbours(cell);
for (var j = 0; j < neighbours.length; j++) {
if (neighbours[j].live && neighbours[j].live == 1) {
livesCount = livesCount + 1;
}
}
//Rule 1; Any live cell with fewer than two live neighbours dies, as if
//caused by under-population.
if (livesCount < 2 && cell.live == 1) {
//console.log('dies');
live = 0;
}
//Rule 2: Any live cell with two or three live neighbours lives on to the
//next generation.
if ((livesCount == 2 || livesCount == 3) && cell.live == 1) {
//console.log('keep living');
live = 1;
}
//Rule 3; Any live cell with more than three live neighbours dies,
//as if by overcrowding.
if ((livesCount > 3) && cell.live == 1) {
//console.log('dies');
live = 0;
}
//Rule 4: Any dead cell with exactly three live neighbours becomes a live cell,
//as if by reproduction.
if (livesCount == 3 && cell.live === 0) {
//console.log('born!');
live = 1;
}
newData.push({x: cell.x, y: cell.y, live: live});
}
this.data = newData;
}
GameOflife.prototype.draw = function() {
d3.selectAll("rect")
.data(this.data)
.attr('class', function(d) { return "live" + d.live; });
}
GameOflife.prototype.start = function() {
this.nextGeneration();
this.draw();
}
svg.attr("width", totalWidth).
attr("height", totalHeight + marginBottom);
var gameOfLife = new GameOflife({ rows: rows, cols: cols});
var graph = svg.append("g").
attr("width", totalWidth).
attr("height", totalHeight);
var x = d3.scale.linear().domain([0, cols]).range([0, totalWidth]);
var y = d3.scale.linear().domain([0, rows]).range([0, totalHeight]);
function addButton(x, y, text, callback) {
var button = svg.append('g')
.classed('btn', true)
.attr('transform', 'translate('+[x,y]+')');
button.append('rect')
.attr("width", 100)
.attr("height", 50)
.attr("x", 0)
.attr("y", 0);
button.append('text')
.attr("x", 20)
.attr("y", 30)
.text(text)
.on('click', callback);
}
var initialized = false;
function init() {
var state = [];
var maxInitailcells = parseInt(Math.random()*(rows*cols));
for (var a = 0; a < maxInitailcells; a++) {
var item = [
parseInt(Math.random()*cols),
parseInt(Math.random()*rows)
];
state.push(item);
}
gameOfLife.setInitialState(state);
if (!initialized) {
var data = graph.selectAll("g.cell")
.data(gameOfLife.data);
data.enter().append("rect")
.classed('cell',true)
.attr("width", width - 0.3)
.attr("height", height - 0.3)
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y); });
}
gameOfLife.draw();
initialized = true;
}
var interval = null;
addButton(10, totalHeight + 20, 'Start >>', function(){
interval = setInterval(function(){ gameOfLife.start(); }, 500);
});
addButton(123, totalHeight + 20, 'RESET', function(){
clearInterval(interval);
init();
});
addButton(250, totalHeight + 20, 'Stop', function(){
clearInterval(interval);
});
init();
rect {
background: #e1e1e1 !important;
}
.live0 {
fill: #e1e1e1;
}
.live1 {
fill: steelblue;
}
.btn rect {
border:1px solid black;
fill:#FFFFFF;
cursor:pointer;
}
.btn text {
cursor:pointer;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment