Skip to content

Instantly share code, notes, and snippets.

@wwymak
Last active July 2, 2017 18:00
Show Gist options
  • Save wwymak/50db576a2537c1b37f60ef373d344009 to your computer and use it in GitHub Desktop.
Save wwymak/50db576a2537c1b37f60ef373d344009 to your computer and use it in GitHub Desktop.
simple cellular automata
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<div id="canvas"></div>
<script>
const cellsize = 10;
const cellNumberX = 100;
const cellNumberY = 100;
let cellArray = [];
for (let i = 0; i< cellNumberX; i++) {
for (let j = 0; j< cellNumberY; j++) {
let cell = {
x: i,
y: j,
alive: 0,
above: j -1,
below: j + 1,
left: i -1,
right: i+1,
aliveNext: 0
};
if(cell.above < 0) {
cell.above = cellNumberY - 1;
}
if(cell.below > cellNumberY - 1) {
cell.below = 0;
}
if(cell.left < 0) {
cell.left = cellNumberX -1
}
if(cell.right > cellNumberX - 1) {
cell.right = 0
}
cellArray.push(cell)
}
}
cellArray.forEach(d => {
if(Math.random() > 0.5) {
d.alive = 1
}
d.neighbours = [];
d.neighbours.push(cellArray.filter(j => j.x ===d.x && j.y === d.above)[0])
d.neighbours.push(cellArray.filter(j => j.x ===d.x && j.y === d.below)[0])
d.neighbours.push(cellArray.filter(j => j.x ===d.left && j.y === d.y )[0])
d.neighbours.push(cellArray.filter(j => j.x ===d.right&& j.y === d.above)[0])
d.neighbours.push(cellArray.filter(j => j.x ===d.left && j.y === d.above)[0])
d.neighbours.push(cellArray.filter(j => j.x ===d.left && j.y === d.below)[0])
d.neighbours.push(cellArray.filter(j => j.x ===d.right&& j.y === d.above)[0])
d.neighbours.push(cellArray.filter(j => j.x ===d.right&& j.y === d.below)[0])
});
let canvasObj = d3.select('#canvas')
.append('canvas')
.attr('width', cellsize * cellNumberX)
.attr('height', cellsize * cellNumberY);
let context = canvasObj.node().getContext('2d');
// databinding
let dataHolder = d3.select(document.createElement('dataHolder'));
function dataBind(data){
let join = dataHolder.selectAll('dataRect.rect').data(data);
let enterSelection = join.enter().append('dataRect')
.attr('class', 'rect')
.attr('width', cellsize)
.attr('height', cellsize)
.attr('x', d => d.x * cellsize)
.attr('y', d => d.y * cellsize)
// .attr('stroke-style', 'black')
let mergeSelection = join.merge(enterSelection)
// .transition()
.attr('width', cellsize)
.attr('height', cellsize)
.attr('fillStyle', d => d.alive ===1? 'black': 'white');
let exitSelection = join.exit().remove()//.transition().attr('width', 0).attr('height', 0).remove();
}
function draw() {
context.clearRect(0, 0, cellsize * cellNumberX, cellsize * cellNumberY);
let elements = dataHolder.selectAll('dataRect.rect');
elements.each(function (d, i) {
let cell = d3.select(this);
context.fillStyle = cell.attr('fillStyle');
context.fillRect(cell.attr('x'), cell.attr('y'), cellsize, cellsize)
})
}
function updateCells(cellArray) {
cellArray.forEach(cell => {
let numberOfLiveNeighbours = cell.neighbours.filter(d => d.alive ===1).length;
if(cell.alive ===1 ) {
if (numberOfLiveNeighbours === 2 || numberOfLiveNeighbours === 3){
cell.aliveNext = 1;
} else {
cell.aliveNext = 0
}
}
if(cell.alive === 0) {
if(numberOfLiveNeighbours === 3) {
cell.aliveNext = 1;
}
}
});
cellArray.forEach(cell => {
cell.alive = cell.aliveNext;
})
return cellArray;
}
setInterval(() => {
updateCells(cellArray);
dataBind(cellArray);
draw();
}, 1000);
// dataBind(cellArray);
// draw();
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment