Текущая версия |
Ваш текст |
Строка 1: |
Строка 1: |
− | Игра "Жизнь" Джона Конвея. | + | Игра "Жизнь" - клеточный автомат, придуманный английским математиком Джоном Конвеем в 1970 году. |
− | | |
− | Выполнено [[Шлычков Никита|Шлычковым Никитой]] на языке программирования JavaScript.
| |
| | | |
| == Правила == | | == Правила == |
Строка 13: |
Строка 11: |
| {{#widget:Iframe | url=http://tm.spbstu.ru/htmlets/js2020/Shlychkov/aaaaaaaaaaaaa.html | width=1000 | height = 1000 | border = 0}} | | {{#widget:Iframe | url=http://tm.spbstu.ru/htmlets/js2020/Shlychkov/aaaaaaaaaaaaa.html | width=1000 | height = 1000 | border = 0}} |
| | | |
− | ==Код программы==
| + | Выполнено [[Шлычков Никита|Шлычковым Никитой]] на языке программирования JavaScript. |
− | | |
− | <div class="mw-collapsible mw-collapsed">
| |
− | '''Код программы на языке JavaScript:''' <div class="mw-collapsible-content">
| |
− | <syntaxhighlight lang="javascript" line start="1" enclose="div">
| |
− | const directions = document.createElement('span');
| |
− | const panel = document.getElementById('panel');
| |
− | const birth = document.createElement('INPUT');
| |
− | const survival = document.createElement('INPUT');
| |
− | const directions2 = document.createElement('SPAN');
| |
− | const submit_button = document.createElement('input');
| |
− | const space = document.createElement('span');
| |
− | const nextbutton = document.createElement('input');
| |
− | const togglebutton = document.createElement('input');
| |
− | const speedslide = document.createElement('input');
| |
− | const button1 = document.createElement('input');
| |
− | const button2 = document.createElement('input');
| |
− | var birt = birth.value;
| |
− | var surv = survival.value;
| |
− | var birt_array = [];
| |
− | var surv_array = [];
| |
− | var meaninglessvariable = 0;
| |
− | var birtl = 0;
| |
− | var survl = 0;
| |
− | const canvas = document.getElementById('canbas');
| |
− | const ctx = canvas.getContext('2d');
| |
− | const h = canvas.height;
| |
− | const w = canvas.width;
| |
− | const gridinterval = 800/40;
| |
− | var cells_array = [];
| |
− | var next_cells_array = [];
| |
− | var mousex = 0;
| |
− | var mousey = 0;
| |
− | var neighbours = [];
| |
− | ctx.fillStyle = 'black';
| |
− | ctx.strokeStyle = 'grey';
| |
− | var cellnum = w*h/Math.pow(gridinterval, 2);
| |
− | var neighbours_alive = 0;
| |
− | var auto = false;
| |
− | | |
− | var Cell = function(x, y, alive){
| |
− | this.x = x;
| |
− | this.y = y;
| |
− | this.alive = alive;
| |
− | }
| |
− | | |
− | var current_cell = new Cell(gridinterval/2, gridinterval/2, false);
| |
− | | |
− | | |
− | window.addEventListener('load', createControlBar1, false);
| |
− | | |
− | | |
− | function createControlBar1(){
| |
− | panel.innerHTML = '';
| |
− | console.log('Creating rules panel', performance.now());
| |
− | panel.appendChild(directions);
| |
− | directions.innerHTML = 'Введите условия рождения и выживания клетки: B';
| |
− | panel.appendChild(birth);
| |
− | birth.setAttribute('size', '5');
| |
− | birth.setAttribute('maxlength', '8');
| |
− | birth.setAttribute('value', '3');
| |
− | panel.appendChild(directions2);
| |
− | directions2.innerHTML = '/S';
| |
− | panel.appendChild(survival);
| |
− | survival.setAttribute('size', '5');
| |
− | survival.setAttribute('maxlength', '8');
| |
− | survival.setAttribute('value', '23');
| |
− | panel.appendChild(space);
| |
− | space.innerHTML = ' ';
| |
− | panel.appendChild(submit_button);
| |
− | submit_button.setAttribute('type', 'button');
| |
− | submit_button.setAttribute('value', 'Подтвердить');
| |
− | submit_button.setAttribute('onclick', 'readRules()');
| |
− | console.log('Rules panel created', performance.now());
| |
− | }
| |
− | | |
− | function readRules() {
| |
− | if (birth.value != '' && survival.value != ''){
| |
− | console.log('Setting rules', performance.now());
| |
− | birtl = birth.value.length;
| |
− | survl = survival.value.length;
| |
− | birt = parseInt(birth.value);
| |
− | surv = parseInt(survival.value);
| |
− | console.log('b', birt, 's', surv);
| |
− | getRules();
| |
− | createCells();
| |
− | createControlBar2();
| |
− | drawgrid();
| |
− | } else {
| |
− | alert('Ты чёрт');
| |
− | }
| |
− | }
| |
− | | |
− | function getRules() {
| |
− | for (i = 0; i<birtl; i++){
| |
− | let meaninglessvariable = birt % 10;
| |
− | if (birt_array.indexOf(meaninglessvariable, 0) == -1){
| |
− | birt_array.push(meaninglessvariable);
| |
− | console.log('Birth condition ', i, ': ', meaninglessvariable);
| |
− | }
| |
− | birt = parseInt((birt - meaninglessvariable)/10);
| |
− | }
| |
− | for (i = 0; i<survl; i++){
| |
− | let meaninglessvariable = surv % 10;
| |
− | if (surv_array.indexOf(meaninglessvariable, 0) == -1){
| |
− | surv_array.push(meaninglessvariable);
| |
− | console.log('Survival condition ', i, ': ', meaninglessvariable);
| |
− | }
| |
− | surv = parseInt((surv - meaninglessvariable)/10);
| |
− | }
| |
− | console.log('Rules set', performance.now());
| |
− | }
| |
− | | |
− | function createControlBar2() {
| |
− | panel.innerHTML = '';
| |
− | canvas.setAttribute('onclick', 'toggleCell()');
| |
− | panel.appendChild(button1);
| |
− | button1.setAttribute('type', 'button');
| |
− | button1.setAttribute('value', 'Restart');
| |
− | button1.setAttribute('onclick', 'restart()');
| |
− | panel.appendChild(button2);
| |
− | button2.setAttribute('type', 'button');
| |
− | button2.setAttribute('value', 'Generate');
| |
− | button2.setAttribute('onclick', 'pregen()');
| |
− | panel.appendChild(nextbutton);
| |
− | nextbutton.setAttribute('type', 'button');
| |
− | nextbutton.setAttribute('value', 'Next');
| |
− | nextbutton.setAttribute('onclick', 'stepp()');
| |
− | panel.appendChild(togglebutton);
| |
− | togglebutton.setAttribute('type', 'button');
| |
− | togglebutton.setAttribute('value', 'Start');
| |
− | togglebutton.setAttribute('onclick', 'autostep()');
| |
− | panel.appendChild(directions);
| |
− | directions.innerHTML = ' Speed';
| |
− | panel.appendChild(speedslide);
| |
− | speedslide.setAttribute('type', 'range');
| |
− | speedslide.setAttribute('min', '10');
| |
− | speedslide.setAttribute('max', '500');
| |
− | speedslide.setAttribute('value', '100');
| |
− |
| |
− | }
| |
− | | |
− | function drawgrid() {
| |
− | for (var i=0; i<w/gridinterval; i++){
| |
− | ctx.beginPath();
| |
− | ctx.moveTo(gridinterval*i, 0);
| |
− | ctx.lineTo(gridinterval*i, h);
| |
− | ctx.stroke();
| |
− | ctx.beginPath();
| |
− | ctx.moveTo(0, gridinterval*i);
| |
− | ctx.lineTo(w, gridinterval*i);
| |
− | ctx.stroke();
| |
− | }
| |
− | }
| |
− | | |
− | function createCells() {
| |
− | cells_array = [];
| |
− | console.log('Filling cells array', performance.now());
| |
− | for (j=0; j<h/gridinterval; j++) {
| |
− | for (i=0; i<w/gridinterval; i++){
| |
− | let cell = new Cell((i+0.5)*gridinterval, (j+0.5)*gridinterval, false);
| |
− | cells_array.push(cell);
| |
− | }
| |
− | }
| |
− | for (j=0; j<h/gridinterval; j++) {
| |
− | for (i=0; i<w/gridinterval; i++){
| |
− | let cell = new Cell((i+0.5)*gridinterval, (j+0.5)*gridinterval, false);
| |
− | next_cells_array.push(cell);
| |
− | }
| |
− | }
| |
− | console.log('Cells array filled', performance.now());
| |
− | }
| |
− | | |
− | function getMouseCoords() {
| |
− | mousex = event.clientX - canvas.getBoundingClientRect().left;
| |
− | mousey = event.clientY - canvas.getBoundingClientRect().top;
| |
− | }
| |
− | | |
− | function toggleCell() {
| |
− | getMouseCoords();
| |
− | let cellx = (mousex - (mousex % gridinterval)) + gridinterval/2;
| |
− | let celly = (mousey - (mousey % gridinterval)) + gridinterval/2;
| |
− | let cell_num = (celly/gridinterval - 0.5)*w/gridinterval + (cellx/gridinterval - 0.5);
| |
− | console.log('x', cellx, '(', mousex, ')', 'y', celly, '(', mousey, ') - ', cell_num);
| |
− | if (cells_array[cell_num].alive) {
| |
− | ctx.clearRect(cellx-gridinterval/2 + gridinterval/20, celly-gridinterval/2 + gridinterval/20, gridinterval - gridinterval/10, gridinterval - gridinterval/10)
| |
− | cells_array[cell_num].alive = false;
| |
− | console.log('Kill');
| |
− | } else {
| |
− | ctx.beginPath();
| |
− | ctx.arc(cellx, celly, gridinterval*0.4, 0, 2*Math.PI);
| |
− | ctx.fill();
| |
− | cells_array[cell_num].alive = true;
| |
− | console.log('Spare');
| |
− | }
| |
− | }
| |
− | | |
− | function life(a) {
| |
− | neighbours = [];
| |
− | neighbours_alive = 0;
| |
− | if (cells_array[a].y == gridinterval/2) { //Верхняя строка
| |
− | if (cells_array[a].x == gridinterval/2) {
| |
− | neighbours.push(cells_array[cellnum-1]);
| |
− | neighbours.push(cells_array[cellnum-w/gridinterval]);
| |
− | neighbours.push(cells_array[cellnum-w/gridinterval+1]);
| |
− | neighbours.push(cells_array[a+1]);
| |
− | neighbours.push(cells_array[w/gridinterval+1]);
| |
− | neighbours.push(cells_array[w/gridinterval]);
| |
− | neighbours.push(cells_array[2*w/gridinterval-1]);
| |
− | neighbours.push(cells_array[w/gridinterval-1]);
| |
− | }
| |
− | if (cells_array[a].x == w - gridinterval/2) {
| |
− | neighbours.push(cells_array[cellnum-2]);
| |
− | neighbours.push(cells_array[cellnum-1]);
| |
− | neighbours.push(cells_array[cellnum-w/gridinterval]);
| |
− | neighbours.push(cells_array[0]);
| |
− | neighbours.push(cells_array[w/gridinterval]);
| |
− | neighbours.push(cells_array[a+w/gridinterval]);
| |
− | neighbours.push(cells_array[a+w/gridinterval-1]);
| |
− | neighbours.push(cells_array[a-1]);
| |
− | } else {
| |
− | neighbours.push(cells_array[cellnum - w/gridinterval + a - 1]);
| |
− | neighbours.push(cells_array[cellnum - w/gridinterval + a]);
| |
− | neighbours.push(cells_array[cellnum - w/gridinterval + a + 1]);
| |
− | neighbours.push(cells_array[a+1]);
| |
− | neighbours.push(cells_array[a+w/gridinterval+1]);
| |
− | neighbours.push(cells_array[a+w/gridinterval]);
| |
− | neighbours.push(cells_array[a+w/gridinterval-1]);
| |
− | neighbours.push(cells_array[a-1]);
| |
− | }
| |
− | }
| |
− | if (cells_array[a].y == h - gridinterval/2) { //Нижняя строка
| |
− | if (cells_array[a].x == gridinterval/2) { //Левый нижний
| |
− | neighbours.push(cells_array[a-1]);
| |
− | neighbours.push(cells_array[a-w/gridinterval]);
| |
− | neighbours.push(cells_array[a-w/gridinterval+1]);
| |
− | neighbours.push(cells_array[a+1]);
| |
− | neighbours.push(cells_array[1]);
| |
− | neighbours.push(cells_array[0]);
| |
− | neighbours.push(cells_array[w/gridinterval-1]);
| |
− | neighbours.push(cells_array[cellnum-1]);
| |
− | }
| |
− | if (cells_array[a].x == w - gridinterval/2) { //Правый нижний
| |
− | neighbours.push(cells_array[a-w/gridinterval-1]);
| |
− | neighbours.push(cells_array[a-w/gridinterval]);
| |
− | neighbours.push(cells_array[a - 2*w/gridinterval + 1]);
| |
− | neighbours.push(cells_array[a-w/gridinterval+1]);
| |
− | neighbours.push(cells_array[0]);
| |
− | neighbours.push(cells_array[w/gridinterval-1]);
| |
− | neighbours.push(cells_array[w/gridinterval-2]);
| |
− | neighbours.push(cells_array[a-1]);
| |
− | } else { //Не угловая клетка
| |
− | neighbours.push(cells_array[a-w/gridinterval-1]);
| |
− | neighbours.push(cells_array[a-w/gridinterval]);
| |
− | neighbours.push(cells_array[a-w/gridinterval+1]);
| |
− | neighbours.push(cells_array[a+1]);
| |
− | neighbours.push(cells_array[w/gridinterval-(cellnum-a)+1]);
| |
− | neighbours.push(cells_array[w/gridinterval-(cellnum-a)]);
| |
− | neighbours.push(cells_array[w/gridinterval-(cellnum-a)-1]);
| |
− | neighbours.push(cells_array[a-1]);
| |
− | }
| |
− | }
| |
− | if (cells_array[a].x == gridinterval/2) { //Левый столбец
| |
− | neighbours.push(cells_array[a-1]);
| |
− | neighbours.push(cells_array[a-w/gridinterval]);
| |
− | neighbours.push(cells_array[a-w/gridinterval+1]);
| |
− | neighbours.push(cells_array[a+1]);
| |
− | neighbours.push(cells_array[a+w/gridinterval+1]);
| |
− | neighbours.push(cells_array[a+w/gridinterval]);
| |
− | neighbours.push(cells_array[a+2*w/gridinterval-1]);
| |
− | neighbours.push(cells_array[a+w/gridinterval-1]);
| |
− | }
| |
− | if (cells_array[a].x == w - gridinterval/2) { //Правый столбец
| |
− | neighbours.push(cells_array[a-w/gridinterval-1]);
| |
− | neighbours.push(cells_array[a-w/gridinterval]);
| |
− | neighbours.push(cells_array[a-2*w/gridinterval+1]);
| |
− | neighbours.push(cells_array[a-w/gridinterval+1]);
| |
− | neighbours.push(cells_array[a+1]);
| |
− | neighbours.push(cells_array[a+w/gridinterval]);
| |
− | neighbours.push(cells_array[a+w/gridinterval-1]);
| |
− | neighbours.push(cells_array[a-1]);
| |
− | } else {
| |
− | neighbours.push(cells_array[a-w/gridinterval-1]);
| |
− | neighbours.push(cells_array[a-w/gridinterval]);
| |
− | neighbours.push(cells_array[a-w/gridinterval+1]);
| |
− | neighbours.push(cells_array[a+1]);
| |
− | neighbours.push(cells_array[a+w/gridinterval+1]);
| |
− | neighbours.push(cells_array[a+w/gridinterval]);
| |
− | neighbours.push(cells_array[a+w/gridinterval-1]);
| |
− | neighbours.push(cells_array[a-1]);
| |
− | }
| |
− |
| |
− | for (it=0; it<8; it++) {
| |
− | if (neighbours[it].alive) { neighbours_alive++ }
| |
− | }
| |
− |
| |
− | if (cells_array[a].alive){
| |
− | if (surv_array.indexOf(neighbours_alive) == -1) {
| |
− | next_cells_array[a].alive = false;
| |
− | } else {
| |
− | next_cells_array[a].alive = true;
| |
− | }
| |
− | }
| |
− | if (cells_array[a].alive == false){
| |
− | if (birt_array.indexOf(neighbours_alive) != -1){ next_cells_array[a].alive = true; }
| |
− | }
| |
− | }
| |
− | | |
− | function devMarkNeigh(a) {
| |
− | life(a);
| |
− | for (i=0; i<8; i++){
| |
− | ctx.beginPath();
| |
− | ctx.arc(neighbours[i].x, neighbours[i].y, 0.2*gridinterval, 0, 2*Math.PI);
| |
− | ctx.fill();
| |
− | }
| |
− | }
| |
− | | |
− | function draw(a) {
| |
− | if (next_cells_array[a].alive) {
| |
− | ctx.beginPath();
| |
− | ctx.arc(next_cells_array[a].x, next_cells_array[a].y, 0.4*gridinterval, 0, 2*Math.PI);
| |
− | ctx.fill();
| |
− | } else {
| |
− | ctx.clearRect(next_cells_array[a].x-gridinterval/2 + gridinterval/20, next_cells_array[a].y-gridinterval/2 + gridinterval/20, gridinterval - gridinterval/10, gridinterval - gridinterval/10);
| |
− | }
| |
− | }
| |
− | | |
− | function change(a) {
| |
− | cells_array[a].alive = next_cells_array[a].alive;
| |
− | }
| |
− | | |
− | function stepp() {
| |
− | for (i=0; i<cellnum; i++){
| |
− | life(i);
| |
− | }
| |
− | for (i=0; i<cellnum; i++){
| |
− | draw(i);
| |
− | }
| |
− | for (i=0; i<cellnum; i++){
| |
− | change(i);
| |
− | }
| |
− | if (auto) {
| |
− | clearInterval(fps);
| |
− | fps = setInterval(stepp, 100*100/speedslide.value)
| |
− | }
| |
− | }
| |
− | | |
− | function autostep() {
| |
− | if (auto) {
| |
− | clearInterval(fps);
| |
− | auto = false;
| |
− | togglebutton.setAttribute('value', 'Start');
| |
− | } else {
| |
− | fps = setInterval(stepp, 100*100/speedslide.value)
| |
− | auto = true;
| |
− | togglebutton.setAttribute('value', 'Stop');
| |
− | }
| |
− | }
| |
− | | |
− | function pregen() {
| |
− | for (i = 0; i<cellnum; i++) {
| |
− | let v = Math.random();
| |
− | if (v < 0.1) {
| |
− | ctx.beginPath();
| |
− | ctx.arc(cells_array[i].x, cells_array[i].y, gridinterval*0.4, 0, 2*Math.PI);
| |
− | ctx.fill();
| |
− | cells_array[i].alive = true;
| |
− | }
| |
− | }
| |
− | }
| |
− | | |
− | function restart() {
| |
− | clearInterval(fps);
| |
− | auto = false;
| |
− | ctx.clearRect(0, 0, w, h);
| |
− | createControlBar1();
| |
− | }
| |
− | | |
− | // Да, "Restart" звучит лучше, чем "Перезапуск", так что я позволил себе посреди программы поменять язык, простите
| |
− | | |
− | </syntaxhighlight>
| |
− | </div>
| |