Processing:Примеры/Игра жизни Конвея
Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску
Содержание | Среда разработки Processing | Справочник языка Processing | Библиотеки | Примеры | Режимы программирования |
Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.
Описание[1]
Нажмите на пробел, чтобы остановить клеточный автомат, или на кнопку мышки, чтобы изменить значения клеток. Во время паузы на клетки можно нажимать, активируя и деактивируя их. Нажмите на клавишу «R», чтобы случайно сбросить исходное расположение клеток. Нажмите на клавишу «C», чтобы очистить фоновую решетку.
Клеточный автомат «Игра жизни» был придуман Джоном Конвеем в 1970 году.
Пример
// размер клеток:
int cellSize = 5;
// насколько высока вероятность того,
// что клетка будет жива в начале игры (в процентах):
float probabilityOfAliveAtStart = 15;
// переменные для таймера:
int interval = 100;
int lastRecordedTime = 0;
// цвета для активных/неактивных клеток:
color alive = color(0, 200, 0);
color dead = color(0);
// массив клеток:
int[][] cells;
// буфер для записи состояния клеток;
// он также будет использоваться
// для изменения других клеток во время взаимодействий:
int[][] cellsBuffer;
// пауза:
boolean pause = false;
void setup() {
size (640, 360);
// инициализируем массивы:
cells = new int[width/cellSize][height/cellSize];
cellsBuffer = new int[width/cellSize][height/cellSize];
// строка для отрисовки фоновой клеточной решетки:
stroke(48);
noSmooth();
// инициализируем клетки:
for (int x=0; x<width/cellSize; x++) {
for (int y=0; y<height/cellSize; y++) {
float state = random (100);
if (state > probabilityOfAliveAtStart) {
state = 0;
}
else {
state = 1;
}
cells[x][y] = int(state); // сохраняем состояние каждой клетки
}
}
background(0); // закрашиваем фон черным на случай,
// если клетки не заполнят все ячейки решетки
}
void draw() {
// рисуем решетку:
for (int x=0; x<width/cellSize; x++) {
for (int y=0; y<height/cellSize; y++) {
if (cells[x][y]==1) {
fill(alive); // если жива
}
else {
fill(dead); // если мертва
}
rect (x*cellSize, y*cellSize, cellSize, cellSize);
}
}
// итерируем, если таймер дает отсчет:
if (millis()-lastRecordedTime>interval) {
if (!pause) {
iteration();
lastRecordedTime = millis();
}
}
// во время паузы вручную создаем новые клетки:
if (pause && mousePressed) {
// масштабируем друг к другу размер экрана
// и количество ячеек в фоновой решетке;
// также задаем границы для фоновой решетки:
int xCellOver = int(map(mouseX, 0, width, 0, width/cellSize));
xCellOver = constrain(xCellOver, 0, width/cellSize-1);
int yCellOver = int(map(mouseY, 0, height, 0, height/cellSize));
yCellOver = constrain(yCellOver, 0, height/cellSize-1);
// сверяемся с клетками в буфере:
if (cellsBuffer[xCellOver][yCellOver]==1) { // клетка жива
cells[xCellOver][yCellOver]=0; // убита
fill(dead); // заполняем цветом убитой клетки
}
else { // клетка мертва
cells[xCellOver][yCellOver]=1; // оживляем
fill(alive); // заполняем цветом живой клетки
}
}
else if (pause && !mousePressed) { // и сохраняем, когда
// пользователь отпустил мышку
// сохраняем клетки в буфер
// (это дает возможность работать
// с одним массивом, другой оставляя нетронутым):
for (int x=0; x<width/cellSize; x++) {
for (int y=0; y<height/cellSize; y++) {
cellsBuffer[x][y] = cells[x][y];
}
}
}
}
void iteration() { // если счетчик дает отчет
// сохраняем клетки в буфер
// (это дает возможность работать
// с одним массивом, другой оставляя нетронутым):
for (int x=0; x<width/cellSize; x++) {
for (int y=0; y<height/cellSize; y++) {
cellsBuffer[x][y] = cells[x][y];
}
}
// проходим через все клетки:
for (int x=0; x<width/cellSize; x++) {
for (int y=0; y<height/cellSize; y++) {
// проходим через всех соседей каждой клетки:
int neighbours = 0; // считаем соседей
for (int xx=x-1; xx<=x+1;xx++) {
for (int yy=y-1; yy<=y+1;yy++) {
// проверяем, не вышли ли за пределы экрана:
if (((xx>=0)&&(xx<width/cellSize))&&((yy>=0)&&(yy<height/cellSize))) {
if (!((xx==x)&&(yy==y))) { // проверяем клетку
// относительно самой себя
if (cellsBuffer[xx][yy]==1){
neighbours ++; // проверяем живых соседей и считаем их
}
} // заканчиваем цикл if()
} // заканчиваем цикл if()
} // заканчиваем цикл yy
} // заканчиваем цикл xx
// проверили всех соседей: применяем правила!
if (cellsBuffer[x][y]==1) { // клетка жива:
// если нужно, убиваем ее
if (neighbours < 2 || neighbours > 3) {
cells[x][y] = 0; // убиваем, разве что у нее нет 2-3 соседей
}
}
else { // клетка мертва: если нужно, оживляем
if (neighbours == 3 ) {
cells[x][y] = 1; // только если у нее 3 соседа
}
} // заканчиваем цикл if()
} // заканчиваем цикл y
} // заканчиваем цикл x
} // конец функции
void keyPressed() {
if (key=='r' || key == 'R') {
// перезапуск - повторная инициализация клеток:
for (int x=0; x<width/cellSize; x++) {
for (int y=0; y<height/cellSize; y++) {
float state = random (100);
if (state > probabilityOfAliveAtStart) {
state = 0;
}
else {
state = 1;
}
cells[x][y] = int(state); // сохраняем состояние каждой клетки
}
}
}
if (key==' ') { // вкл/выкл для паузы
pause = !pause;
}
if (key=='c' || key == 'C') { // очищаем все
for (int x=0; x<width/cellSize; x++) {
for (int y=0; y<height/cellSize; y++) {
cells[x][y] = 0; // сохраняем все значения как «0»
}
}
}
}
См.также
Внешние ссылки
Примеры на Processing | |
---|---|
Основы |
|
Продвинутые графические эффекты |
|
Примеры из сторонних библиотек |