Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

256 lines (228 sloc) 7.631 kb
<!DOCTYPE html>
<html>
<head>
<title>Geoff Buesing</title>
<meta name="viewport" content="width=device-width, maximum-scale=1.0" />
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.428571429;
color: #333;
background-color: #fff;
margin: 0;
border: 0;
}
a {
color: #428bca;
text-decoration: none;
}
p {
text-align: center;
}
pre {
width: 560px;
height: 400px;
border: 1px dotted #ccc;
cursor: pointer;
}
</style>
</head>
<body>
<p>
<strong>Geoff Buesing</strong> &nbsp;
<a href="https://github.com/gbuesing">Github</a> &nbsp;
<a href="https://twitter.com/gbuesing">Twitter</a> &nbsp;
<a href="mailto:gbuesing@gmail.com">Email</a>
</p>
<center>
<pre></pre>
<h3>Projects</h3>
<p><a href="http://mnist-ruby-test.herokuapp.com/">Handwritten Digit Classifier</a></p>
<p><a href="https://github.com/gbuesing/neural-net-ruby">Neural Network in Ruby</a></p>
<p><a href="https://github.com/gbuesing/arduino-cta-tracker">Arduino CTA Tracker</a></p>
<p><a href="https://github.com/gbuesing/hookforward">Hookforward</a></p>
<p><a href="https://github.com/gbuesing/rack-host-redirect">rack-host-redirect</a></p>
<p><a href="https://github.com/gbuesing/mustache.couch.js">mustache.couch.js</a></p>
<p><a href="https://github.com/gbuesing/duoconsole">Duoconsole</a></p>
<p><a href="https://github.com/gbuesing/rackables">Rackables</a></p>
<p><a href="https://github.com/gbuesing/couchdb-rack">CouchDB-Rack</a></p>
<p><a href="https://github.com/gbuesing/Bayes.rb">Bayes.rb</a></p>
<br></br>
</center>
</body>
<script>
// http://www.radicaleye.com/lifepage/glossary.html
// TODO: add more!
var patterns = {
'acorn': [
'.*.....',
'...*...',
'**..***'
],
'ants': [
'**........**...**...**...**...**...**..',
'..**.**.....**...**...**...**...**...**',
'..**...**...**...**...**...**...**...**',
'**.....**.**...**...**...**...**...**..',
'.....**................................'
],
'blinker': [
'...',
'***',
'...'
],
'glider': [
'..*',
'*.*',
'.**'
],
'gun': [
'.........................*..........',
'......................****....*.....',
'.............*.......****.....*.....',
'............*.*......*..*.........**',
'...........*...**....****.........**',
'**.........*...**.....****..........',
'**.........*...**........*..........',
'............*.*.....................',
'.............*......................'
],
'rabbits': [
'*...***',
'***..*.',
'.*.....'
]
};
function gameOfLife(width, height, aliveChar, emptyChar) {
aliveChar = aliveChar || '*'
emptyChar = emptyChar || ' '
var currentGeneration = stringMatrix(width, height, emptyChar);
var patternCellRegexp = /\*/g;
function addPattern(pattern, offset_x, offset_y) {
var patternWidth = pattern[0].length, patternHeight = pattern.length;
if (!offset_x) offset_x = Math.round((currentGeneration.width - patternWidth) / 2);
if (!offset_y) offset_y = Math.round((currentGeneration.height - patternHeight) / 2);
for (var y=0; y < pattern.length; y++) {
var match, line = pattern[y];
patternCellRegexp.lastIndex = 0;
while (match = patternCellRegexp.exec(line)) {
currentGeneration.setChar(match.index + offset_x, y + offset_y, aliveChar);
}
};
}
function calculateNextGeneration() {
var nextGeneration = [];
for (var y=0; y < currentGeneration.height; y++) {
var line = currentGeneration.lines[y];
var nextCells = [];
for (var x=0; x < line.length; x++) {
var nextCell = isCellAliveInNextGeneration(x,y) ? aliveChar : emptyChar;
nextCells.push(nextCell);
}
nextGeneration[y] = nextCells.join('');
}
return nextGeneration;
}
function isCellAlive(x,y) {
return currentGeneration.getChar(x,y) === aliveChar;
}
function isCellAliveInNextGeneration(x,y) {
switch ( countAliveNeighbors(x,y) ) {
case 2:
return isCellAlive(x,y);
case 3:
return true;
default:
return false;
}
}
var neighborOffsets = [[-1, 0],[1, 0],[-1, 1],[0, 1],[1, 1],[-1, -1],[0, -1], [1, -1]];
function countAliveNeighbors(x,y) {
var sum = 0;
neighborOffsets.forEach(function(pair) {
var offset_x = pair[0], offset_y = pair[1];
if (isCellAlive(x + offset_x, y + offset_y)) sum ++;
});
return sum;
}
function stringMatrix(w, h, initChar) {
// wraparound lookup on arrays and strings
// will not work on unicode strings!
function atIndex(arr, i) {
var length = arr.length;
return arr[(i + length) % length];
}
function replaceCharAtIndex(str, i, replacement) {
var length = str.length;
if (i >= length) return str;
return [str.slice(0,i), replacement, str.slice(i+1,length)].join('');
}
var matrix = {
width: w, height: h, lines: [],
init: function() {
var line = (new Array(this.width + 1)).join(initChar || ' ');
for (var i=0; i < this.height; i++) this.lines[i] = line;
},
getChar: function(x,y) {
var line = atIndex(this.lines, y);
return atIndex(line, x);
},
setChar: function(x,y,char) {
var line = this.lines[y];
if (!line) return;
this.lines[y] = replaceCharAtIndex(line, x, char);
},
toString: function() {
return this.lines.join("\n");
}
}
matrix.init();
return matrix;
}
return {
generation: 0,
next: function() {
currentGeneration.lines = calculateNextGeneration();
this.generation ++;
},
toString: function() {
return currentGeneration.toString();
},
addPattern: addPattern,
clear: function() {
currentGeneration.init();
}
}
}
var elem = document.getElementsByTagName("pre")[0];
var game = gameOfLife(40, 20, 'O', ' ');
game.addPattern(patterns['gun']);
var loop = setInterval(function() {
game.next();
elem.textContent = game.toString();
}, 100);
elem.addEventListener("touchstart", handleTouchstart, false);
elem.addEventListener("touchmove", handleTouchmove, false);
elem.addEventListener("click", handleClick, false);
function addPattern(pattern, offsetX, offsetY) {
var matrixX = Math.round((offsetX / 560) * 40);
var matrixY = Math.round((offsetY / 400) * 20);
game.addPattern(pattern, matrixX - 2, matrixY - 2);
}
function handleClick (e) {
e.preventDefault();
addPattern(patterns['glider'], e.offsetX, e.offsetY);
}
function handleTouchstart(e) {
e.preventDefault();
addPattern(patterns['glider'], e.changedTouches[0].pageX, e.changedTouches[0].pageY);
}
function handleTouchmove(e) {
e.preventDefault();
var matrixX = Math.round((e.changedTouches[0].pageX / 560) * 40);
var matrixY = Math.round((e.changedTouches[0].pageY / 400) * 20);
game.addPattern(['*'], matrixX, matrixY);
};
</script>
</html>
Jump to Line
Something went wrong with that request. Please try again.