|
| gliba 31.12.2006 20:32 Игра 'Жизнь' придумана британским математиком John Conway в 1970 году. Удачно имитирует поведение колоний клеток.
Использует всего 3 правила, но генерирует интересные орнаменты.
Правило 1. Мертвая клетка становится живой, если она граничит ровно с тремя живыми.
Правило 2. Живая продолжает жить, если граничит с двумя или тремя живыми.
Правило 3. Во всех остальных случаях клетка является мертвой.
Живая умирает от нехватки пищи (слишком много соседей) или потери тепла (слишком мало соседей).
Так и люди, в одиночку гибнут, в толпе нивелируются.
Переход на игру.
Код
<script>
//colors
var arrCol = new Array( "#000066", "#9999ff" );
//create table with cells
function createCells( arr, m, n, widthCell, border )
{
var i, j, k, val, col;
if( "" + widthCell == "undefined" ) widthCell = 10;
if( "" + border == "undefined" ) border = 1;
document.writeln( "<table style='color:#ffff00; table-layout:fixed;' cellpadding='0' cellspacing='0' border='" + border + "'>" );
k = 0;
for( i = 0; i < m; i++ )
{
document.writeln( "<tr height='" + widthCell + "'>" );
for( j = 0; j < n; j++ )
{
val = arr[ k++ ];
col = ( val ? arrCol[ 1 ] : arrCol[ 0 ] );
document.writeln( "<td width='" + widthCell + " height='" + widthCell + "' id='c" + i + "_" + j + "'" +
" style='background-color:" + col + ";'><img src='point.png' width='0' height='0'></td>" );
}
document.writeln( "</tr>" );
}
document.writeln( "</table>" );
}
//randomly init cells and update table
function Init( bUpdate )
{
var i;
for( i = 0; i < sz; i++ ) arr[ i ] = 0;
for( i = 0; i < nInit; i++ )
{
arr[ Math.floor( sz * Math.random() ) ] = 1;
}
if( bUpdate ) updateCells();
}
//add one more alive cell
function addLive()
{
var k = Math.floor( sz * Math.random() );
var i = Math.floor( k / n ); //VI
var j = k % n;
var s = "c" + i + "_" + j;
var obj = document.getElementById( s );
if( obj )
{
obj.style.backgroundColor = arrCol[ 1 ];
arr[ k ] = 1;
}
return false;
}
//update
function updateCells()
{
var k;
for( k = 0; k < sz; k++ )
{
if( arrObj[ k ] )
{
arrObj[ k ].style.backgroundColor = arr[ k ] ? arrCol[ 1 ] : arrCol[ 0 ];
if( iDebug ) arrObj[ k ].innerText = arrNeighb[ k ];
}
}
return false;
}
//new iteration
function Iterate()
{
var i;
//calculate neighboors
for( i = 0; i < sz; i++ ) arrNeighb[ i ] = 0;
for( i = 0; i < sz; i++ )
{ //check all 8 neighboors
if( i % n == 0 )
{ //left border
}
else
{ //not left
if( arr[ i - 1 ] == 1 ) arrNeighb[ i ]++;
if( i - 1 - n >= 0 && arr[ i - 1 - n ] == 1 ) arrNeighb[ i ]++;
if( i - 1 + n < sz && arr[ i - 1 + n ] == 1 ) arrNeighb[ i ]++;
}
if( i % n == n - 1 )
{ //right border
}
else
{ //not right
if( arr[ i + 1 ] == 1 ) arrNeighb[ i ]++;
if( i + 1 - n >= 0 && arr[ i + 1 - n ] == 1 ) arrNeighb[ i ]++;
if( i + 1 + n < sz && arr[ i + 1 + n ] == 1 ) arrNeighb[ i ]++;
}
//top
if( i - n >= 0 && arr[ i - n ] == 1 ) arrNeighb[ i ]++;
//bottom
if( i + n >= 0 && arr[ i + n ] == 1 ) arrNeighb[ i ]++;
}
//new generation
for( i = 0; i < sz; i++ )
{
if( arr[ i ] == 0 && arrNeighb[ i ] == 3 )
{ //new alive
arr[ i ] = 1;
}
else if( arr[ i ] == 1 && ( arrNeighb[ i ] == 2 || arrNeighb[ i ] == 3 ) )
{ //keep alive
}
else
{ //die
arr[ i ] = 0;
}
}
//update table
updateCells();
return false;
}
//start loop
function Start()
{
cycle = 1;
Next();
return false;
}
function Next()
{
if( cycle == 1 )
{
Iterate();
window.setTimeout( "Next()", 50 );
}
return false;
}
//stop loop
function Stop()
{
cycle = 0;
return false;
}
var i, j, k, s;
var m = 40; //rows
var n = 50; //columns
var widthCell = 10; //cell width
var border = 0; //border width
var nInit = 500; //initially alive
var sz = m * n; //table size
var arr = new Array( sz ); //cell state
var arrNeighb = new Array( sz ); //number of neighboors
var arrObj = new Array( sz ); //reference by ID
var cycle = 0; //loop
var iDebug = 0;
Init( false );
createCells( arr, m, n, widthCell, border );
//assign objects
i = 0;
j = 0;
for( k = 0; k < sz; k++ )
{
s = "c" + i + "_" + j;
j++;
if( j == n )
{ //next row
j = 0;
i = i + 1;
}
obj = document.getElementById( s );
arrObj[ k ] = obj;
}
</script>
<input type="button" value="Инициализация" onclick="Init( true )">
<input type="button" value="Добавить клетку" onclick="addLive()">
<input type="button" value="1 итерация" onclick="Iterate()">
<input type="button" value="Запустить" onclick="Start()">
<input type="button" value="Остановить" onclick="Stop()">
Комментарии.
Элемент стиля таблицы table-layout:fixed; очень важен. Он нужен, чтобы получались маленькие ячейки.
Посмотрите, что будет, если убрать его. <img src='point.png' width='0' height='0'> нужен для маленьких таблиц в FireFox.
point.png - прозрачная картинка.
При создании таблицы каждая ячейка получает ID. Это позволит в дальнейшем менять стиль элементов таблицы.
С помощью
obj.style.backgroundColor = arrCol[ 1 ];
меняем цвет фона.
Массив arrObj нужен для ускорения вычислений
Приведенный код можно улучшить. Например, выводить номер итерации и число "живых" клеток.
Использовать различные оттенки для указания количества соседей.
Большая часть клеток не меняет своего состояния. Изменять их атрибуты не нужно.
За счет этого можно ускорить перерисовку.
"Полировку" будем считать домашним заданием. |