238 lines
5.1 KiB
JavaScript
238 lines
5.1 KiB
JavaScript
var grid = document.getElementById("grid");
|
|
|
|
var cellsize = 60;
|
|
|
|
function xCoord(i, j) {
|
|
var x = i + j/2;
|
|
if (x > width - 1) {
|
|
x = x - width;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
function yCoord(i, j) {
|
|
return Math.sqrt(3)*j/2;
|
|
}
|
|
|
|
var width;
|
|
var height;
|
|
var cells;
|
|
|
|
function initialize() {
|
|
width = Math.ceil(window.innerWidth / cellsize) + 1;
|
|
height = Math.ceil(window.innerHeight / (cellsize*Math.sqrt(3)/2)) + 1;
|
|
|
|
cells = new Array(width);
|
|
for (var i = 0; i < width; ++i) {
|
|
cells[i] = new Array(height);
|
|
for (var j = 0; j < height; ++j) {
|
|
cells[i][j] = document.createElement("div");
|
|
cells[i][j].classList.add("cell");
|
|
cells[i][j].classList.add("alive");
|
|
|
|
spiral = document.createElement("img");
|
|
spiral.classList.add("spiral");
|
|
spiral.src = "spiral.svg";
|
|
cells[i][j].appendChild(spiral);
|
|
|
|
hex = document.createElement("img");
|
|
hex.classList.add("hex");
|
|
hex.src = "hex.svg";
|
|
cells[i][j].appendChild(hex);
|
|
|
|
cells[i][j].style.position = "absolute";
|
|
cells[i][j].style.left = xCoord(i, j)*cellsize + "px";
|
|
cells[i][j].style.bottom = yCoord(i, j)*cellsize + "px";
|
|
grid.appendChild(cells[i][j]);
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < width; ++i) {
|
|
for (var j = 0; j < height; ++j) {
|
|
if (Math.floor(Math.random()*2) === 0) {
|
|
kill(i, j);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function cleanup() {
|
|
for (var i = width - 1; i >= 0; --i) {
|
|
for (var j = height - 1; j >= 0; --j) {
|
|
grid.removeChild(cells[i][j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
function prebirth(i, j) {
|
|
cells[i][j].classList.add("birthing");
|
|
}
|
|
function prekill(i, j) {
|
|
cells[i][j].classList.add("dying");
|
|
}
|
|
function birth(i, j) {
|
|
cells[i][j].classList.remove("dead");
|
|
cells[i][j].classList.add("alive");
|
|
}
|
|
function kill(i, j) {
|
|
cells[i][j].classList.remove("alive");
|
|
cells[i][j].classList.add("dead");
|
|
}
|
|
function update(i, j) {
|
|
var cl = cells[i][j].classList;
|
|
if (cl.contains("birthing")) {
|
|
cl.remove("birthing");
|
|
birth(i, j);
|
|
}
|
|
if (cl.contains("dying")) {
|
|
cl.remove("dying");
|
|
kill(i, j);
|
|
}
|
|
}
|
|
function isAlive(i, j) {
|
|
return !cells[i][j].classList.contains("dead");
|
|
}
|
|
|
|
function rotate(a) {
|
|
a.push(a.shift());
|
|
}
|
|
|
|
function arraysEq(a, b) {
|
|
if (a.length !== b.length) {
|
|
return false;
|
|
}
|
|
|
|
for (var i = 0; i < a.length; ++i) {
|
|
if (a[i] !== b[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function arraysRotatedEq(a, b) {
|
|
if (a.length !== b.length) {
|
|
return false;
|
|
}
|
|
|
|
for (var i = 0; i < a.length; ++i) {
|
|
if (arraysEq(a, b)) {
|
|
return true;
|
|
}
|
|
rotate(b);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function mod(m, n) {
|
|
return ((m % n) + n) % n;
|
|
}
|
|
|
|
function ip(i) {
|
|
return mod(i-1, width);
|
|
}
|
|
function is(i) {
|
|
return mod(i+1, width);
|
|
}
|
|
function jp(j) {
|
|
return mod(j-1, height);
|
|
}
|
|
function js(j) {
|
|
return mod(j+1, height);
|
|
}
|
|
|
|
function ll(i, j) {
|
|
return isAlive(ip(i), j);
|
|
}
|
|
function dl(i, j) {
|
|
return isAlive(i, jp(j));
|
|
}
|
|
function dr(i, j) {
|
|
return isAlive(is(i), jp(j));
|
|
}
|
|
function rr(i, j) {
|
|
return isAlive(is(i), j);
|
|
}
|
|
function ur(i, j) {
|
|
return isAlive(i, js(j));
|
|
}
|
|
function ul(i, j) {
|
|
return isAlive(ip(i), js(j));
|
|
}
|
|
|
|
function neighbors(i, j) {
|
|
return [ll(i, j), dl(i, j), dr(i, j), rr(i, j), ur(i, j), ul(i, j)];
|
|
}
|
|
|
|
function neighborsCount(i, j) {
|
|
return neighbors(i, j).filter(function (b) { return b; }).length;
|
|
}
|
|
|
|
function golay(i, j) {
|
|
var n = neighbors(i, j);
|
|
var g1 = [true, true, false, false, false, false];
|
|
var g2 = [true, false, true, false, false, false];
|
|
return (arraysRotatedEq(n, g1) || arraysRotatedEq(n, g2));
|
|
}
|
|
|
|
function preston(i, j) {
|
|
var n = neighbors(i, j);
|
|
var p1 = [true, true, false, false, false, false];
|
|
var p2 = [true, false, true, false, false, false];
|
|
return (isAlive(i, j) && (arraysRotatedEq(n, p1) || arraysRotatedEq(n, p2))) || (!isAlive(i, j) && neighborsCount(i, j) === 2);
|
|
}
|
|
|
|
function golayStep() {
|
|
for (var i = 0; i < width; ++i) {
|
|
for (var j = 0; j < height; ++j) {
|
|
if (golay(i, j)) {
|
|
prebirth(i, j);
|
|
} else {
|
|
prekill(i, j);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < width; ++i) {
|
|
for (var j = 0; j < height; ++j) {
|
|
update(i, j);
|
|
}
|
|
}
|
|
}
|
|
|
|
function prestonStep() {
|
|
for (var i = 0; i < width; ++i) {
|
|
for (var j = 0; j < height; ++j) {
|
|
if (preston(i, j)) {
|
|
prebirth(i, j);
|
|
} else {
|
|
prekill(i, j);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < width; ++i) {
|
|
for (var j = 0; j < height; ++j) {
|
|
update(i, j);
|
|
}
|
|
}
|
|
}
|
|
|
|
initialize();
|
|
|
|
setInterval(prestonStep, 1000);
|
|
|
|
var showControls = false;
|
|
|
|
window.onclick = function () {
|
|
document.getElementById("controls").style.display = showControls ? "none" : "block";
|
|
showControls = !showControls;
|
|
}
|
|
|
|
window.addEventListener('resize', function(event){
|
|
cleanup();
|
|
initialize();
|
|
});
|