More or less finished product: added options like speed and density and age color effects

This commit is contained in:
Dan Ballard 2011-06-20 23:54:24 -07:00
parent aa71ad5867
commit cd91b75321
1 changed files with 143 additions and 33 deletions

176
life.html
View File

@ -10,13 +10,15 @@
var width_c; var width_c;
var cells; var cells;
var timer; var timer;
var effects;
// set start/stop button value
function btn_control_set_name(name) { function btn_control_set_name(name) {
var btn = document.getElementById('control-btn'); var btn = document.getElementById('control-btn');
btn.value = name; btn.value = name;
} }
// generate an 2d array of cells based on current geometry
function gen_cells() { function gen_cells() {
var new_cells = new Array(height_c); var new_cells = new Array(height_c);
for(var i = 0; i < height_c; i++) { for(var i = 0; i < height_c; i++) {
@ -24,33 +26,54 @@
} }
for (var y = 0; y < height_c; y++) { for (var y = 0; y < height_c; y++) {
for (var x = 0; x < width_c; x++) { for (var x = 0; x < width_c; x++) {
new_cells[y][x] = false; new_cells[y][x] = 0;
} }
} }
return new_cells; return new_cells;
} }
// init the cells
function init_cells() { function init_cells() {
cells = gen_cells(); cells = gen_cells();
} }
// Generate and populate the geometry variables
// possibly over complicated from my experiment with an elastic resizeable board
function get_demensions() {
var canvas = document.getElementById('board');
size = parseInt( document.getElementById('density').value);
width_px = canvas.offsetWidth - (canvas.offsetWidth%size);
canvas.width = width_px;
width_c = width_px/ size;
height_px = canvas.offsetHeight - (canvas.offsetHeight%size);
canvas.height = height_px;
height_c = height_px/size;
//console.log(width_px + 'x' + height_px + ' => ' + width_c + 'x' +height_c);
}
// init the board
// set vars
// get geometry
// generate cells for 1st time
// draw
function board_init() { function board_init() {
var canvas = document.getElementById('board'); var canvas = document.getElementById('board');
size = 10; document.getElementById('density').value = 10;
width_px = canvas.width; get_demensions();
width_c = width_px/ size;
height_px = canvas.height;
height_c = height_px/size;
btn_control_set_name('Start'); btn_control_set_name('Start');
hertz = 4; document.getElementById('speed').value = 8;
change_speed();
init_cells(); init_cells();
document.getElementById('effects').value=0;
effects=0;
redraw(); redraw();
} }
// Draw the current board: gird, then cells
function redraw() { function redraw() {
console.log('redraw()');
var canvas = document.getElementById('board'); var canvas = document.getElementById('board');
var c = canvas.getContext('2d'); var c = canvas.getContext('2d');
get_demensions();
c.globalCompositeOperation = 'destination-over'; c.globalCompositeOperation = 'destination-over';
@ -58,7 +81,6 @@
c.fillStyle='rgba(0,0,0,0.)'; c.fillStyle='rgba(0,0,0,0.)';
c.strokeStyle= 'rgba(192,192,192,1)'; c.strokeStyle= 'rgba(192,192,192,1)';
c.save();
c.beginPath(); c.beginPath();
@ -66,28 +88,54 @@
c.stroke(); c.stroke();
c.strokeStyle= 'rgba(0,0,0,1)';
c.fillStyle = c.strokeStyle;
c.beginPath();
draw_cells(c); draw_cells(c);
c.stroke();
c.fill();
} }
// Generate a cycling darkening with age rainbow color
// based on math/code from http://www.krazydad.com/makecolors.php
function setStrokeAgeRainbow(l, c) {
var frequency = 0.3;
var center = 200; //128;
var width = 55; //127;
var red = Math.floor( (Math.sin(frequency*l + 0) * width + center) -l) ;
var green = Math.floor( (Math.sin(frequency*l + 2) * width + center) -l);
var blue = Math.floor( (Math.sin(frequency*l + 4) * width + center) -l);
red = Math.max(0, red);
green = Math.max(0, green);
blue = Math.max(0, blue);
c.strokeStyle= 'rgba('+red+','+green+','+blue+','+1+')';
}
// Draw all the cells onto the board inside the grid
function draw_cells(c) { function draw_cells(c) {
for (var y = 0; y < height_c; y++) { for (var y = 0; y < height_c; y++) {
for (var x =0; x < width_c; x ++) { for (var x =0; x < width_c; x ++) {
if (cells[y][x] == true) { if (cells[y][x] != 0) {
if(effects == 0) {
c.strokeStyle = 'rgba(0,0,0,1)';
} else {
setStrokeAgeRainbow(cells[y][x], c);
}
c.fillStyle = c.strokeStyle;
c.beginPath();
c.moveTo(x*size +1, y*size+1); c.moveTo(x*size +1, y*size+1);
c.lineTo(x*size+ size-1, y*size+1); c.lineTo(x*size+ size-1, y*size+1);
c.lineTo(x*size+ size-1, y*size + size-1); c.lineTo(x*size+ size-1, y*size + size-1);
c.lineTo(x*size+1, y*size + size-1); c.lineTo(x*size+1, y*size + size-1);
// auto return home? // auto return home
c.stroke();
c.fill();
} }
} }
} }
} }
// draw the grid and border
function draw_grid(c) { function draw_grid(c) {
// Horizontal lines // Horizontal lines
for (var y = 0; y <= height_px; y += size) { for (var y = 0; y <= height_px; y += size) {
@ -102,20 +150,24 @@
} }
// When we've loaded, run!
window.onload = board_init; window.onload = board_init;
// is a cell alive or dead
// 0 for dead, 1 for alive
// walls count as dead
// used by num_neighbours
function cell_value(x, y) { function cell_value(x, y) {
//console.log('(x:' + x + ',y:' + y + ') w/s:' + (width/size) + ' h/s:' + (height/size) ); //console.log('(x:' + x + ',y:' + y + ') w/s:' + (width/size) + ' h/s:' + (height/size) );
if (x < 0 || x >= width_c || y < 0 || y >= height_c) { if (x < 0 || x >= width_c || y < 0 || y >= height_c) {
return 0; return 0;
} else { } else {
return cells[y][x]; return cells[y][x] == 0 ? 0 : 1;
} }
} }
// return the number of neighbours for a cell
// walls count as dead
function num_neighbours(x, y) { function num_neighbours(x, y) {
var n = 0; var n = 0;
n += cell_value(x-1, y-1); n += cell_value(x-1, y-1);
@ -132,22 +184,24 @@
return n; return n;
} }
// Simulate one generation of cells
// create a new cells 2d array and simulate the next generation
// into it and then replace the current cells with it
function step() { function step() {
var new_cells = gen_cells(); var new_cells = gen_cells();
for(var y=0; y < height_c; y++) { for(var y=0; y < height_c; y++) {
for(var x =0 ; x < width_c; x++) { for(var x =0 ; x < width_c; x++) {
var n = num_neighbours(x, y); var n = num_neighbours(x, y);
if (cells[y][x] == true) { if (cells[y][x] != 0) {
if (n < 2 || n > 3) { if (n < 2 || n > 3) {
new_cells[y][x] = false; new_cells[y][x] = 0;
} else { } else {
console.log('ALIVE'); new_cells[y][x] = cells[y][x] +1;
new_cells[y][x] = true;
} }
} else if (n == 3) { } else if (n == 3) {
new_cells[y][x] = true; new_cells[y][x] = 1;
} else { } else {
new_cells[y][x] = false; new_cells[y][x] = 0;
} }
} }
} }
@ -155,6 +209,7 @@
cells = new_cells; cells = new_cells;
} }
// Stop/Start button press
function control_click() { function control_click() {
var btn = document.getElementById('control-btn'); var btn = document.getElementById('control-btn');
if (btn.value == 'Start') { if (btn.value == 'Start') {
@ -166,28 +221,83 @@
} }
} }
// Function to call on timmer
// simulate on e generation,
// redrawn
// reset timmer
function tick() { function tick() {
step(); step();
redraw(); redraw();
timmer = setTimeout('tick();', 1000/hertz); timmer = setTimeout('tick();', 1000.0/hertz);
} }
// Handler for a click on the board to place/unplace a cell
function board_click(e) { function board_click(e) {
var canvas = document.getElementById('board'); var canvas = document.getElementById('board');
var x = Math.floor((e.pageX-canvas.offsetLeft)/size); var x = Math.floor((e.pageX-canvas.offsetLeft)/size);
var y = Math.floor((e.pageY-canvas.offsetTop)/size); var y = Math.floor((e.pageY-canvas.offsetTop)/size);
console.log(e.pageX + '/' + size + ' = ' + x + ' && ' + e.pageY + '/' + size + ' = ' +y);
cells[y][x] = ! cells[y][x]; cells[y][x] = ! cells[y][x];
redraw(); redraw();
} }
// Change speed handler
function change_speed() {
hertz = parseInt(document.getElementById('speed').value);
}
// Resize board handler (kind of not used)
// Left over from experiment in resiable elastic board
// Abandoned because of problems with lining up mouse clicks on board
// and weird stretcing issues
function resize_cells() {
var new_cells = gen_cells();
var w = Math.min(width_c, cells[0].length);
var h = Math.min(height_c, cells.length);
for(var y = 0; y < h; y++) {
for(x = 0; x < w; x++) {
new_cells[y][x] = cells[y][x];
}
}
cells = new_cells;
}
// What to do on a document resize (more usefull for elastic boards)
function canvas_resize() {
get_demensions();
resize_cells();
redraw();
}
</script> </script>
</head> </head>
<body> <body onResize="canvas_resize();">
<input type="button" id="control-btn" onClick="control_click(); return false;" /> Speed: <select id="speed" onChange="change_speed();">
<option value="1">1 Hz</option>
<option value="2">2 Hz</option>
<option value="4">4 Hz</option>
<option value="8">8 Hz</option>
<option value="16">16 Hz</option>
<option value="32">32 Hz</option>
<option value="64">64 Hz</option>
</select>
Density: <select id="density" onChange="canvas_resize();">
<option value="3">X-Small</option>
<option value="5">Small</option>
<option value="10">Medium</option>
<option value="15">Large</option>
<option value="20">X-Large</option>
</select>
Effects: <select id="effects" onChange="effects=parseInt(this.value); redraw();">
<option value="0">None (black and white)</option>
<option value="1">Color age (Raindbow)</option>
</select>
<input type="button" id="control-btn" onClick="control_click(); return false;" />
<small style="margin-left:20px">Dan Ballard (2011) &lt;<a href="mailto:dan@mindstab.net">dan@mindstab.net</a>&gt;</small>
<input style="left:775px; position: absolute; /* width:100% height: 100%; */" type="button" value="Clear" onClick="cells = gen_cells(); redraw();" />
<br/> <br/>
<canvas width="800" height="400" id="board" onClick="board_click(event);"></canvas> <canvas id="board" onClick="board_click(event);" width="800" height="400"></canvas>
</body> </body>
</html> </html>