/* * Copyright 2011 Julian Pulgarin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var Point = function(x, y) { this.x = x; this.y = y; }; var graphics = function() { var canvas; var ctx; var canvasId; var cellSize = 10; // pixels var onColour = 'rgb(0, 200, 0)'; var offColour = 'rgb(200, 0, 0)'; var gridColour = 'rgb(50, 50, 50)'; var initCanvas = function(canvasId) { this.canvas = $(canvasId).get(0); this.ctx = this.canvas.getContext('2d'); this.canvasId = canvasId; } var drawCell = function(x, y, alive) { var g = graphics; g.ctx.fillStyle = (alive)? onColour : offColour; g.ctx.fillRect(x * cellSize + 1, y * cellSize + 1, cellSize - 1, cellSize - 1); } var handleMouse = function(e) { var l = life; var g = graphics; var that = this; var cell = getCellPointUnderMouse(e); var state; processCell(cell); $(g.canvasId).mousemove(function(e) { cell = getCellPointUnderMouse(e); processCell(cell); }); function getCellPointUnderMouse(e) { return new Point((e.pageX - that.offsetLeft) / g.cellSize | 0, ((e.pageY - that.offsetTop) / g.cellSize) | 0); } function processCell(cell) { var x = cell.x; var y = cell.y; if (x > l.xCells - 1 || y > l.yCells - 1) { return; } if (typeof state == 'undefined') { state = !l.prev[x][y]; } l.prev[x][y] = state; drawCell(x, y, state); // TODO: Consider setting next as well } } function paint() { var g = graphics; var l = life; for (var x = 0; x < l.xCells; x++) { for (var y = 0; y < l.yCells; y++) { g.drawCell(x, y, l.prev[x][y]); } } } return { canvas: canvas, ctx: ctx, canvasId: canvasId, cellSize: cellSize, onColour: onColour, offColour: offColour, gridColour: gridColour, initCanvas: initCanvas, drawCell: drawCell, handleMouse: handleMouse, paint: paint, } }(); var life = function() { var yCells; var xCells; var prev = []; // previous generation var next = []; // next generation var _timeout; var _alive = false; var initUniverse = function(canvasId) { var l = life; var g = graphics; g.initCanvas(canvasId); l.xCells = ((g.canvas.width - 1) / g.cellSize) | 0; l.yCells = ((g.canvas.height - 1) / g.cellSize) | 0; g.ctx.fillStyle = g.offColour; g.ctx.fillRect(0, 0, l.xCells * g.cellSize, l.yCells * g.cellSize); g.ctx.fillStyle = g.gridColour; for (var x = 0; x < l.xCells; x++) { l.prev[x] = []; l.next[x] = []; g.ctx.fillRect(x * g.cellSize, 0, 1, l.yCells * g.cellSize); for(var y = 0; y < l.yCells; y++) { l.prev[x][y] = false; } } g.ctx.fillRect(l.xCells * g.cellSize, 0, 1, l.yCells * g.cellSize); for(var y = 0; y < l.yCells; y++) { g.ctx.fillRect(0, y * g.cellSize, l.xCells * g.cellSize, 1); } g.ctx.fillRect(0, l.yCells * g.cellSize, l.xCells * g.cellSize, 1); $(canvasId).mousedown(g.handleMouse); $('body').mouseup(function(e) { $(g.canvasId).unbind('mousemove'); }); } var nextGen = function() { var l = life; var g = graphics; for (var x = 0; x < l.xCells; x++) { for (var y = 0; y < l.yCells; y++) { l.next[x][y] = l.prev[x][y]; } } for (var x = 0; x < l.xCells; x++) { for (var y = 0; y < l.yCells; y++) { count = _neighbourCount(x, y); // Game of Life rules if (prev[x][y]) { if (count < 2 || count > 3) { next[x][y] = false; } } else if (count == 3) { next[x][y] = true; } } } for (var x = 0; x < l.xCells; x++) { for (var y = 0; y < l.yCells; y++) { l.prev[x][y] = l.next[x][y]; } } g.paint(); } var toggleLife = function() { var l = life; if (!l._alive) { l._alive = true; l._timeout = setInterval("life.nextGen()", 100); } else { l._alive = false; clearInterval(l._timeout); } } var clear = function() { var l = life; var g = graphics; for (var x = 0; x < l.xCells; x++) { for (var y = 0; y < l.yCells; y++) { l.prev[x][y] = false; } } g.paint(); } var _neighbourCount = function(x, y) { var l = life; var count = 0; var neighbours = [ l.prev[x][(y - 1 + l.yCells) % l.yCells], l.prev[(x + 1 + l.xCells) % l.xCells][(y - 1 + l.yCells) % l.yCells], l.prev[(x + 1 + l.xCells) % l.xCells][y], l.prev[(x + 1 + l.xCells) % l.xCells][(y + 1 + l.yCells) % l.yCells], l.prev[x][(y + 1 + l.yCells) % l.yCells], l.prev[(x - 1 + l.xCells) % l.xCells][(y + 1 + l.yCells) % l.yCells], l.prev[(x - 1 + l.xCells) % l.xCells][y], l.prev[(x - 1 + l.xCells) % l.xCells][(y - 1 + l.yCells) % l.yCells], ]; for (var i = 0; i < neighbours.length; i++) { if (neighbours[i]) { count++; } } return count; } return { yCells: yCells, xCells: xCells, prev: prev, next: next, initUniverse: initUniverse, nextGen: nextGen, toggleLife: toggleLife, clear: clear, } }();