Last active
August 29, 2015 14:03
-
-
Save AverageMarcus/f5e34825ef89e11443be to your computer and use it in GitHub Desktop.
An example of Conway's Game of Life
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Marcus Noble - Conway's Game Of Life</title> | |
<style type="text/css"> | |
* { | |
box-sizing:border; | |
} | |
body{ | |
text-align:center; | |
} | |
#gameBoard { | |
margin: 0 auto; | |
border:2px solid #ccc; | |
line-height:10px; | |
display:table; | |
} | |
.cell { | |
width:10px; | |
height:10px; | |
display:inline-block; | |
border:1px solid #ccc; | |
} | |
.row { | |
display:block; | |
margin:0; | |
} | |
</style> | |
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> | |
</head> | |
<body id="home"> | |
<h1>Conways Game of Life</h1> | |
<div id="gameBoard"></div> | |
<p> | |
Read my blog post regarding <a href="http://blog.marcusnoble.co.uk/14-07-2014-conways-game-of-life/">Conway's Game of Life</a> | |
</p> | |
<script type="text/javascript"> | |
(function(){ | |
var cells = []; | |
var boardWidth = 20; | |
var boardHeight = 20; | |
var intervalID; | |
var gameOverBoard = [ | |
{x:2,y:4}, | |
{x:2,y:5}, | |
{x:2,y:6}, | |
{x:3,y:3}, | |
{x:4,y:3}, | |
{x:3,y:7}, | |
{x:4,y:7}, | |
{x:4,y:5}, | |
{x:5,y:5}, | |
{x:5,y:6}, | |
{x:7,y:4}, | |
{x:7,y:5}, | |
{x:7,y:6}, | |
{x:7,y:7}, | |
{x:8,y:3}, | |
{x:9,y:3}, | |
{x:8,y:5}, | |
{x:9,y:5}, | |
{x:10,y:4}, | |
{x:10,y:5}, | |
{x:10,y:6}, | |
{x:10,y:7}, | |
{x:12,y:4}, | |
{x:12,y:5}, | |
{x:12,y:6}, | |
{x:12,y:7}, | |
{x:13,y:3}, | |
{x:14,y:4}, | |
{x:15,y:3}, | |
{x:16,y:4}, | |
{x:16,y:5}, | |
{x:16,y:6}, | |
{x:16,y:7}, | |
{x:18,y:3}, | |
{x:18,y:4}, | |
{x:18,y:5}, | |
{x:18,y:6}, | |
{x:18,y:7}, | |
{x:19,y:3}, | |
{x:19,y:5}, | |
{x:19,y:7}, | |
{x:3,y:9}, | |
{x:4,y:9}, | |
{x:2,y:10}, | |
{x:2,y:11}, | |
{x:2,y:12}, | |
{x:3,y:13}, | |
{x:4,y:13}, | |
{x:5,y:10}, | |
{x:5,y:11}, | |
{x:5,y:12}, | |
{x:7,y:9}, | |
{x:7,y:10}, | |
{x:8,y:11}, | |
{x:8,y:12}, | |
{x:9,y:13}, | |
{x:10,y:12}, | |
{x:10,y:11}, | |
{x:11,y:10}, | |
{x:11,y:9}, | |
{x:13,y:9}, | |
{x:13,y:10}, | |
{x:13,y:11}, | |
{x:13,y:12}, | |
{x:13,y:13}, | |
{x:14,y:9}, | |
{x:14,y:11}, | |
{x:14,y:13}, | |
{x:16,y:9}, | |
{x:16,y:10}, | |
{x:16,y:11}, | |
{x:16,y:12}, | |
{x:16,y:13}, | |
{x:17,y:9}, | |
{x:17,y:11}, | |
{x:18,y:9}, | |
{x:18,y:11}, | |
{x:18,y:12}, | |
{x:19,y:10}, | |
{x:19,y:13} | |
]; | |
function init(){ | |
var cell = $('<div/>').addClass('cell'); | |
var row = $('<div/>').addClass('row'); | |
var board = $('#gameBoard'); | |
var currentRow, i, j, newCell; | |
$('#gameBoard').empty().on('click', function(){ | |
clearInterval(intervalID); | |
init(); | |
}); | |
cells = []; | |
for(i=0;i<boardHeight;i++){ | |
currentRow = row.clone(); | |
board.append(currentRow); | |
for(j=0;j<boardHeight;j++){ | |
currentRow.append(cell.clone()); | |
} | |
} | |
for(i=0;i<50;i++){ | |
newCell = { | |
x: (Math.floor(Math.random() * (boardWidth - 1) + 1)), | |
y: (Math.floor(Math.random() * (boardHeight - 1) + 1)) | |
}; | |
cells.push(newCell) | |
} | |
render(); | |
intervalID = setInterval(function(){ | |
tick(); | |
}, 1000); | |
} | |
function render(){ | |
$('.cell').css('background','white'); | |
for(var i=0; i<cells.length;i++){ | |
$($($('.row').get(cells[i].y-1)).find('.cell').get(cells[i].x-1)).css('background', 'black'); | |
} | |
} | |
function tick(){ | |
var neighbourCount = 0; | |
var nextIteration = []; | |
var candidates = []; | |
var neighbours = []; | |
var i, j; | |
// All cells are dead, lets restart | |
if(cells.length === 0){ | |
clearInterval(intervalID); | |
cells = gameOverBoard; | |
render(); | |
setTimeout(function(){ | |
init(); | |
}, 5000); | |
return; | |
} | |
for(i=0; i<cells.length;i++){ | |
neighbourCount = countNeighbours(cells[i]); | |
if(neighbourCount >= 2 && neighbourCount <= 3){ | |
nextIteration.push(cells[i]); | |
} | |
// For each cell that is alive, find its neighbours | |
neighbours = []; | |
neighbours.push({x:cells[i].x-1,y:cells[i].y-1}); | |
neighbours.push({x:cells[i].x-1,y:cells[i].y}); | |
neighbours.push({x:cells[i].x-1,y:cells[i].y+1}); | |
neighbours.push({x:cells[i].x,y:cells[i].y-1}); | |
neighbours.push({x:cells[i].x,y:cells[i].y+1}); | |
neighbours.push({x:cells[i].x+1,y:cells[i].y-1}); | |
neighbours.push({x:cells[i].x+1,y:cells[i].y}); | |
neighbours.push({x:cells[i].x+1,y:cells[i].y+1}); | |
for(j=0;j<neighbours.length;j++){ | |
// Keep the neighbour cells if they are dead | |
// We don't want to keep multiple copies of the neighbour cell | |
if(!isAlive(neighbours[j]) && candidates.filter(function(currentCell){ | |
return (currentCell.x === neighbours[j].x && currentCell.y == neighbours[j].y); | |
}).length === 0) { | |
candidates.push(neighbours[j]); | |
} | |
} | |
} | |
// Now we have a list of dead neighbours of at least 1 live neighbour (candidates) | |
// Bring the cell to life if we find that each neighbour has 3 other live neighbouring cells | |
for(i=0; i<candidates.length;i++){ | |
if(countNeighbours(candidates[i]) === 3){ | |
nextIteration.push(candidates[i]); | |
} | |
} | |
cells = nextIteration; | |
render(); | |
} | |
function isAlive(cell){ | |
return (cells.filter(function(currentCell){ | |
return (currentCell.x === cell.x && currentCell.y === cell.y); | |
}).length > 0); | |
} | |
function countNeighbours(cell){ | |
var x1 = cell.x-1, | |
x2 = cell.x+1, | |
y1 = cell.y-1, | |
y2 = cell.y+1; | |
var neighbours = cells.filter(function(possibleNeighbour){ | |
if(possibleNeighbour.x === cell.x && possibleNeighbour.y === cell.y){ | |
return false; | |
} | |
return (possibleNeighbour.x >= x1 && possibleNeighbour.x <= x2 && possibleNeighbour.y >= y1 && possibleNeighbour.y <= y2); | |
}); | |
return neighbours.length; | |
} | |
init(); | |
}()); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updated based on @danielthepope fork but improved by removing second loop