CelAut v3 — различия между версиями
Материал из Department of Theoretical and Applied Mechanics
Wikiadmin (обсуждение | вклад) м (Замена текста — «<source lang="(.*)" first-line="(.*)">» на «<syntaxhighlight lang="$1" line start="$2" enclose="div">») |
Wikiadmin (обсуждение | вклад) м (Замена текста — «</source>» на «</syntaxhighligh>») |
||
Строка 282: | Строка 282: | ||
this.set_L(0); // после запуска системы, т.к. изменяет переменную L | this.set_L(0); // после запуска системы, т.к. изменяет переменную L | ||
} | } | ||
− | </ | + | </syntaxhighligh> |
Файл '''"CelAut_v3_release.html"''' | Файл '''"CelAut_v3_release.html"''' | ||
<syntaxhighlight lang="html" line start="1" enclose="div"> | <syntaxhighlight lang="html" line start="1" enclose="div"> | ||
Строка 306: | Строка 306: | ||
</body> | </body> | ||
</html> | </html> | ||
− | </ | + | </syntaxhighligh> |
</toggledisplay> | </toggledisplay> | ||
[[Category: Виртуальная лаборатория]] | [[Category: Виртуальная лаборатория]] | ||
[[Category: Программирование]] | [[Category: Программирование]] |
Версия 18:55, 8 марта 2015
Виртуальная лаборатория > Игра "Жизнь" > Клеточный автомат - версии > CelAut v3Справа вы видите легенду геномов, а также можете выбрать, какие клетки вы хотите "рисовать" мышкой.
Скачать программу: CelAut_v3_release.zip Текст программы на языке JavaScript (разработчик Цветков Денис): <toggledisplay status=hide showtext="Показать↓" hidetext="Скрыть↑" linkstyle="font-size:default"> Файл "CelAut_v3_release.js" <syntaxhighlight lang="javascript" line start="1" enclose="div"> function Main_CelAut(canvas) {
// Предварительные установки
var context = canvas.getContext("2d"); // на context происходит рисование canvas.oncontextmenu = function() {return false;}; // блокировка контекстного меню canvas.onselectstart = function() {return false;}; // запрет выделения canvas
// *** Задание физических параметров ***
var mutate_chance = 1 / 50; // шанс клетки мутировать при рождении
// *** Задание вычислительных параметров ***
var fps = 5; // frames per second - число кадров в секунду
// Выполнение программы
var w = canvas.width; // ширина окна var h = canvas.height; // высота окна var N = 50; // количество клеток по горизонтали (желательно, делитель ширины окна) var M = 50; // количество клеток по горизонтали (желательно, делитель высоты окна) var cell_w = w / N; // ширина клетки var cell_h = h / M; // высота клетки
var pause = true; // остановлен ли клеточный автомат var interval_ID; // для управления работой автомата
// "Жизнь" Конвея: [B = 000100000, L = 001100000] var B = "001000000"; // геном рождения var L = "000001100"; // геном выживания
this.set_L = function(n) { // присваеваем нужный геном (n - положение первой единицы в геноме) while (L[0] != '1') L = L.substring(1) + "0"; for (var i = 0; i < n; i++) L = "0" + L.substring(0, L.length - 1); };
// Работа с мышью
canvas.onmousedown = function(e){ // функция при нажатии клавиши мыши var life; if (e.which == 1) life = true; // при нажатии левой клавиши мыши клетка рождается else if (e.which == 3) life = false; // при нажатии правой клавиши мыши клетка умирает else return;
set_cell(e, life, B, L); canvas.onmousemove = function(e) {set_cell(e, life, B, L);}; // функция, выполняющаяся при перемещении курсора мыши };
document.onmouseup = function(e){ // функция при отпускании клавиши мыши canvas.onmousemove = null; // когда клавиша отпущена - функции перемещения нету };
function set_cell(e, is_alive, B, L){ // придать клетке определенное состояние с нажатия клавиши мыши var m = mouse_coords(e); // обновить координаты в переменных mouseX, mouseY if (m.x < 0 || m.x >= w || m.y < 0 || m.y >= h) return; // проверка на ошибочные координаты var i = Math.floor(m.x / cell_w); // получаем ячейку по горизонтали var j = Math.floor(m.y / cell_h); // получаем ячейку по вертикали // везде прибавляем 1 - из за периодических условий массив сдвинут на 1 cells[i + 1][j + 1].alive = is_alive; cells[i + 1][j + 1].B = B; cells[i + 1][j + 1].L = L; draw(); }
function mouse_coords(e) { // функция возвращает экранные координаты курсора мыши var m = []; var rect = canvas.getBoundingClientRect(); m.x = e.clientX - rect.left; m.y = e.clientY - rect.top; return m; }
// Работа с массивом
var cells; // массив клеток var cells_buf = []; // буфер для расчета следующего шага for (var i1 = 0; i1 < N + 2; i1++) { cells_buf[i1] = []; for (var j1 = 0; j1 < M + 2; j1++) { cells_buf[i1][j1] = []; } } function generate_random_field() { // каждая клетка жива с вероятностью 50% cells = []; var i, j; for (i = 0; i < N + 2; i++) { cells[i] = []; for (j = 0; j < M + 2; j++) { if (i != 0 && i != (N + 1) && j != 0 && j != (M + 1)) cells[i][j] = {B:B, L:L, alive:Math.random() >= 0.5}; else cells[i][j] = []; } } }
this.clear = function() { // очистить поле for (var i = 1; i < N + 1; i++) for (var j = 1; j < M + 1; j++) cells[i][j].alive = false; draw(); stop_system(); };
// Управление работой автомата
function step() { tick(); draw(); }
this.change_pause_state = function() { // кнопка паузы if (!pause) stop_system(); else start_system() };
this.next_step = function(){ // кнопка "Следующий шаг" stop_system(); step(); };
function start_system() { pause = false; interval_ID = setInterval(step, 1000/fps); document.getElementById('pause').value = "Остановить"; }
function stop_system() { pause = true; clearInterval(interval_ID); document.getElementById('pause').value = "Запустить"; }
// Расчетная часть программы
function tick() { // то, что происходит каждый шаг времени
// периодичность - копируем боковые клетки for (i = 1; i < N + 1; i++) { cells[i][0].B = cells[i][M].B; cells[i][0].L = cells[i][M].L; cells[i][0].alive = cells[i][M].alive; cells[i][M + 1].B = cells[i][1].B; cells[i][M + 1].L = cells[i][1].L; cells[i][M + 1].alive = cells[i][1].alive; } for (j = 0; j < M + 2; j++) { cells[0][j].B = cells[N][j].B; cells[0][j].L = cells[N][j].L; cells[0][j].alive = cells[N][j].alive; cells[N + 1][j].B = cells[1][j].B; cells[N + 1][j].L = cells[1][j].L; cells[N + 1][j].alive = cells[1][j].alive; }
// цикл по всем клеткам for (var i = 1; i < N + 1; i++) { for (var j = 1; j < M + 1; j++) { // подсчет количества живых клеток вокруг рассматриваемой клетки var near = []; var cell; // сначала содержимое cells[][] присваевается переменной cell // потом проверяется cell.alive, и если оно true - клетка добавляется в список живых клеток if ((cell = cells[i - 1] [j - 1] ).alive) near.push(cell); if ((cell = cells[i - 1] [j] ).alive) near.push(cell); if ((cell = cells[i - 1] [j + 1] ).alive) near.push(cell); if ((cell = cells[i] [j - 1] ).alive) near.push(cell); if ((cell = cells[i] [j + 1] ).alive) near.push(cell); if ((cell = cells[i + 1] [j - 1] ).alive) near.push(cell); if ((cell = cells[i + 1] [j] ).alive) near.push(cell); if ((cell = cells[i + 1] [j + 1] ).alive) near.push(cell);
if (cells[i][j].alive) { // рассматриваемая клетка жива if (cells[i][j].L[near.length] == '1') { // проверка условия выживания по биному L cells_buf[i][j].alive = true; cells_buf[i][j].B = cells[i][j].B; cells_buf[i][j].L = cells[i][j].L; } else { cells_buf[i][j].alive = false; } } else { // рассматриваемая клетка мертва //выясним, сколько видов удовлетворяют условиям рождения новой клетки var good_types = []; for (var k = 0; k < near.length; k++) { if (near[k].B[near.length] != "1") continue; var bad_type = false; for (var gt = 0; gt < good_types.length; gt++) { if (good_types[gt].B == near[k].B && good_types[gt].L == near[k].L) bad_type = true; } if (!bad_type) good_types.push(near[k]); }
if (good_types.length > 0) { // видов, условия которых удовлетворены - больше 0 // если нужных видов больше одного - выбираем случайно var type = good_types[Math.floor(Math.random() * good_types.length)];
// здесь происходит мутация if (Math.random() < mutate_chance) cells_buf[i][j].L = genome_shift(type.L); else cells_buf[i][j].L = type.L; cells_buf[i][j].B = type.B; cells_buf[i][j].alive = true; } else { cells_buf[i][j].alive = false; } } } }
// копирование посчитанных значений следующего шага (cells_buf) в cells for (var i0 = 1; i0 < N + 1; i0++) { for (var j0 = 1; j0 < M + 1; j0++) { cells[i0][j0].B = cells_buf[i0][j0].B; cells[i0][j0].L = cells_buf[i0][j0].L; cells[i0][j0].alive = cells_buf[i0][j0].alive; } } }
// функция сдвига. Принимает строку вида 001110000 (количество единиц любое), и случайно сдвигает единицы влево/вправо // Пример_1: 01100 -> 00110 или 01100 -> 11000 // Пример_2: 00001 -> 00010 (в другую сторону сдвига быть не может) function genome_shift(genome) { var new_genome = genome; // если первый или последний элемент генома - единичка, сдвиг может быть произведен только в одну сторону с шансом 50% if (Math.random() >= 0.5) { if (genome[0] != '1') new_genome = genome.substring(1) + "0"; } else { if (genome[genome.length - 1] != '1') new_genome = "0" + genome.substring(0, genome.length - 1) } return new_genome; }
// Рисование
var colors = ["#ff0000", "#ffaa00", "#ffff00", "#00ff00", "#00ffff", "#0000ff", "#7f00ff", "#ff40ff", "#7f0000"];
function draw(){ context.fillStyle = "#000000"; // цвет клетки context.fillRect(0, 0, w, h); // очистить экран for (var i = 1; i < N + 1; i++) { for (var j = 1; j < M + 1; j++) { if (cells[i][j].alive) { context.fillStyle = colors[cells[i][j].L.indexOf("1")]; // цвет клетки context.beginPath(); context.rect((i - 1) * cell_w, (j - 1) * cell_h, cell_w, cell_h); context.closePath(); context.fill(); } } } }
// Интерфейс
// запишем все возможные состояния генома L (все возможные мутации) var L_test = L; while (L_test[0] != '1') L_test = L_test.substring(1) + "0"; // сдвинем единицы в геноме максимально влево var variants = [L_test]; while (L_test[L_test.length - 1] != '1') { // теперь сдвигаем единицы вправо и запоминаем вариант L_test = "0" + L_test.substring(0, L_test.length - 1); variants.push(L_test); }
// нарисуем таблицу геномов for (var i0 = 0; i0 < variants.length; i0++) { var tr = document.createElement('tr'); tr.innerHTML = "<td><input type='radio' id='radio_" + i0 +"' name='colorTable' onclick='app.set_L(" + i0 + ")'/></td>" + "<td style='width:30px; height:30px; background-color:" + colors[i0] + "; border: 1px solid black;'></td>" + "<td>" + variants[i0] + "</td>"; document.getElementById("type_table").appendChild(tr); }
// Запуск системы
generate_random_field(); // сгенероровать поле start_system();
document.getElementById("radio_0").checked = true; this.set_L(0); // после запуска системы, т.к. изменяет переменную L
} </syntaxhighligh> Файл "CelAut_v3_release.html" <syntaxhighlight lang="html" line start="1" enclose="div"> <!DOCTYPE html> <html> <head>
<title>Cellular automaton</title> <script src="CelAut_v3_release.js"></script>
</head> <body>
<canvas id="canvas_CelAut" width="600" height="600" style="border:1px solid #000000;"></canvas> | |
<input id="pause" type="button" name="" style="width: 100px" onclick="app.change_pause_state();return false;"/>
<input type="button" name="" onclick="app.next_step();return false;" value="Следующий шаг"/><input type="button" name="" onclick="app.clear();return false;" value="Очистить поле"/> |
<script type="text/javascript">var app = new Main_CelAut(document.getElementById('canvas_CelAut'));</script>
</body> </html> </syntaxhighligh> </toggledisplay>