Arduino:Примеры/life
Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску
Содержание | Знакомство с Arduino | Продукты | Основы | Справочник языка Arduino | Примеры | Библиотеки | Хакинг | Изменения | Сравнение языков Arduino и Processing |
Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.
Игра «Жизнь»[1]
Этот пример показывает при помощи Arduino и библиотеки GLCD воспроизвести на GLCD-панели клеточный автомат Джона Конуэя (John Conway) под названием «Игра “Жизнь”».
Код
/*
* Игра «Жизнь»
*
* Игра «Жизнь» – клеточный автомат, придуманный Джоном Конуэем
* (John Conway) и адаптированный под Arduino GLCD.
*
*/
#include <glcd.h>
#include "fonts/SystemFont5x7.h" // системный шрифт
/********* пользовательские настройки ************/
#define CELL_SIZE 4 // высота и ширина каждой клетки
#define DELAY 50 // задержка (в миллисекундах) между показом поколений
/******* обработка пользовательских настроек ********/
#define ROWS (DISPLAY_HEIGHT / CELL_SIZE)
#define COLUMNS (DISPLAY_WIDTH / CELL_SIZE)
#define BYTES_PER_COLUMN ((COLUMNS + 7)/ 8) // это количество байт, необходимых для хранения столбца
#define MAX_ITERATIONS 500 // при достижении этого числа проходы обнуляются
#define STABLE_GENERATIONS 4 // должно быть как минимум «2», это количество старых поколений, которые проверяются для стабильности
#define MIN_OBJECTS 2 // минимальное количество объектов, которые будут посеяны случайным генератором
#define MAX_OBJECTS 4 // максимальное количество объектов, которые будут посеяны случайным генератором
#define MARGIN 4 // минимальная дистанция от края экрана для случайно посеянных объектов
#define BITVAL(_pos) (1<< (7-(_pos % 8))) // макрос для получения значения «bitfield»
#define ALIVE true
#define DEAD false
/* ======== Объекты, участвующие в «Игре жизни» ========
* Это объекты, которые будут участвовать в «Игре жизни»
* (или, другими словами, которые могут быть отображаться на дисплее).
* Чтобы добавить свой объект, создайте и инициализируйте структуру,
* следуя примерам ниже.
* Добавьте в таблицу объектов обращение к своей структуре,
* а также назовите свою структуру, добавив ее в список «enum».
*/
// шаблон структуры для живых объектов:
typedef struct {
byte height ;
byte width ;
byte bitfield[];
} object_t, *object_ptr_t;
// ниже создаются и инициализируются все объекты, которые будут
// участвовать в «Игре жизни»:
struct {
byte height ;
byte width ;
byte bitfield[2];
} table = {2,4, { 0b10010000 , // * *
0b11110000 } }; // ****
struct {
byte height ;
byte width ;
byte bitfield[3];
} glider = {3,3, { 0b00100000 , // *
0b10100000 , // * *
0b01100000 }}; // **
struct {
byte height ;
byte width ;
byte bitfield[3];
} glider2 = {3,3, { 0b10100000 , // * *
0b11000000 , // **
0b11110000 }}; // ****
struct {
byte height ;
byte width ;
byte bitfield[4];
} loaf = {4,4, { 0b01100000 , // **
0b10010000 , // * *
0b01010000 , // * *
0b00100000 }}; // *
struct {
byte height ;
byte width ;
byte bitfield[3];
} ship = {3,3, { 0b11000000 , // **
0b10100000 , // * *
0b01100000 }}; // **
struct {
byte height ;
byte width ;
byte bitfield[4];
} behive = {4,3, { 0b01000000 , // *
0b10100000 , // * *
0b10100000 , // * *
0b01000000}}; // *
struct {
byte height ;
byte width ;
byte bitfield[1];
} blinker = {1,3, { 0b11100000 }}; // ***
struct {
byte height ;
byte width ;
byte bitfield[2];
} block = {2,2, { 0b11000000 , // **
0b11000000}}; // **
// помещаем все эти объекты в таблицу объектов:
object_ptr_t objectTable[] = {
(object_ptr_t)&table,
(object_ptr_t)&glider,
(object_ptr_t)&loaf,
(object_ptr_t)&ship,
(object_ptr_t)&behive,
(object_ptr_t)&blinker,
(object_ptr_t)&block
};
#define OBJECT_COUNT (sizeof( objectTable/ sizeof(object_ptr_t)))
// Составляем список объектов. Новые объекты добавляем в конец списка.
// Код «Игры жизни» будет обращаться к объектам через названия в этом списке.
enum {Table,Glider,Loaf,Ship,Behive,Blinker,Block};
byte generations[STABLE_GENERATIONS][ROWS][BYTES_PER_COLUMN]; // массив, используемый для вычисления, рисования и проверки, изменилось ли количество проходов
void setup(){
GLCD.Init(); // инициализируем библиотеку в режиме рисования
GLCD.SelectFont(System5x7);
seed(0);
}
void loop (void){
GLCD.ClearScreen();
unsigned int i = generate();
GLCD.CursorTo(0,0);
GLCD.print(i);
GLCD.print(" iterations");
delay(1500);
seed(1); // используем случайное семя
}
unsigned int generate(){
unsigned int iteration = 0;
byte thisGeneration,nextGeneration, previousGeneration;
thisGeneration = nextGeneration = 0;
// показываем начальный массив:
for(int row = 0; row < ROWS; row++)
{
for(int column = 0; column < COLUMNS; column++)
{
if(isAlive(thisGeneration,row,column))
GLCD.DrawRoundRect(column * CELL_SIZE, row * CELL_SIZE, CELL_SIZE-1, CELL_SIZE-1, CELL_SIZE/2, BLACK) ;
else
GLCD.DrawRoundRect(column * CELL_SIZE, row * CELL_SIZE, CELL_SIZE-1, CELL_SIZE-1, CELL_SIZE/2, WHITE) ;
}
}
delay(1500); // задержка для показа условий посева
do{
thisGeneration = iteration % STABLE_GENERATIONS;
nextGeneration = (thisGeneration+1) % STABLE_GENERATIONS;
previousGeneration = (thisGeneration-1) % STABLE_GENERATIONS;
delay(DELAY);
memset(generations[nextGeneration],0,sizeof(generations[0])); // очищаем массив для следующего поколения
// смотрим, кто жив, а кто умер:
for(int row = 0; row < ROWS; row++){
for(int column = 0; column < COLUMNS; column++){
boolean cell = isAlive(thisGeneration,row,column);
byte n = getNeighborCount(thisGeneration,row,column);
if(cell == DEAD){
if(n==3) {
setLife(nextGeneration,row,column,ALIVE); // рождение
GLCD.DrawRoundRect(column * CELL_SIZE, row * CELL_SIZE, CELL_SIZE-1, CELL_SIZE-1, CELL_SIZE/2, BLACK) ;
}
}
else{
if(n==2 || n==3) {
setLife(nextGeneration,row,column,ALIVE); // выживание
// рисовать клетку не нужно, поскольку она уже есть:
} else {
setLife(nextGeneration,row,column,DEAD); // смерть
GLCD.DrawRoundRect(column * CELL_SIZE, row * CELL_SIZE, CELL_SIZE-1, CELL_SIZE-1, CELL_SIZE/2, WHITE) ;
}
}
}
}
}
while(isStable(thisGeneration) == false && ++iteration < MAX_ITERATIONS ) ;
return iteration;
}
void seed(int seedValue){
// если seedvalue равно «0», делаем запрограммированный посев; во всех остальных случаях делаем случайный посев
memset(generations,0,sizeof(generations)); // очищаем все массивы для поколений
if(seedValue == 0){
// размещаем объекты по умолчанию; аргумента – это смещение от центра
loadObject(Table,2,-9); // размещаем объект «table» в двух рядах ниже и девяти столбцах левее центра
loadObject(Glider, -5,-9); // размещаем объект «glider» в пяти рядах выше и в девяти столбцах левее центра
}
else{
// загружаем несколько случайных объектов и размещаем в случайных позициях:
byte nbrObjects = random(MIN_OBJECTS,MAX_OBJECTS+1); // создаем случайное количество объектов
for(byte i=0; i < nbrObjects;i++){
byte obj = random(7); // OBJECT_COUNT);
int column = random(MARGIN - (COLUMNS/2), (COLUMNS/2) - MARGIN);
int row = random(MARGIN - (ROWS/2) , (ROWS/2) - MARGIN);
loadObject(obj,row,column);
}
}
}
void loadObject(void * object, char y, char x){
// object_ptr – это загружаемый объект;
// X и Y – это координаты смещения от центра дисплея:
object_ptr_t object_ptr = (object_ptr_t)object;
byte row = (ROWS/2) + y;
byte column = (COLUMNS/2) + x;
for(byte ys = 0; ys < object_ptr->height; ys++ ){
for(byte xs=0; xs < object_ptr->width; xs++ ){
if( (row +ys < ROWS) && (column +xs < COLUMNS)){
// этот код работает, только если в «width» содержится до 8 бит:
boolean value = object_ptr->bitfield[ys] & BITVAL(xs) ;
setLife(0, row+ys, column+xs, value) ; // объекты всегда загружаются в первый массив
}
}
}
}
void loadObject(int object, char y, char x){
loadObject(objectTable[object], y, x );
}
boolean isStable(byte thisGeneration){
// возвращает «true», если два зарегистрированных поколения – одинаковые:
for(byte i=0; i < STABLE_GENERATIONS; i++)
if(i != thisGeneration)
if(memcmp(generations[thisGeneration], generations[i], sizeof(generations[0])) == 0)
return true;
return false;
}
boolean isAlive( byte generation, byte row, byte column){
byte b = generations[generation][row][column /8];
return b & BITVAL(column) ;
}
void setLife( byte generation, byte row, byte column, boolean state){
byte elem = column /8;
byte b = generations[generation][row][elem];
if(state != DEAD){
b = b | BITVAL(column);
}
else{
b &= ~(BITVAL(column)) ;
}
generations[generation][row][elem] = b;
}
byte getNeighborCount( byte generation, byte row, byte column){
byte count = 0;
for(byte d = 0;d < 8; d++)
if(isNeighborAlive(generation,row,column,d) != 0)
count++;
return count;
}
boolean isNeighborAlive( byte generation , byte row, byte column, byte dir){
byte nrow=row;
byte ncol=column;
if(dir == 7 || dir == 0 || dir == 1)
nrow--;
if(dir == 3 || dir == 4 || dir == 5)
nrow++;
if(dir == 5 || dir == 6 || dir == 7)
ncol--;
if(dir == 1 || dir == 2 || dir == 3)
ncol++;
if(ncol==255) ncol = COLUMNS - 1;
if(ncol==COLUMNS) ncol = 0;
if(nrow==255) nrow = ROWS - 1;
if(nrow==ROWS) nrow = 0;
return isAlive(generation,nrow,ncol);
}
См.также
Внешние ссылки
Arduino продукты | |
---|---|
Начальный уровень | Arduino Uno • Arduino Leonardo • Arduino 101 • Arduino Robot • Arduino Esplora • Arduino Micro • Arduino Nano • Arduino Mini • Arduino Starter Kit • Arduino Basic Kit • MKR2UNO • TFT-дисплей Arduino |
Продвинутые функции | Arduino Mega 2560 • Arduino Zero • Arduino Due • Arduino Mega ADK • Arduino Pro • Arduino Motor Shield • Arduino USB Host Shield • Arduino Proto Shield • MKR Proto Shield • MKR Proto Large Shield • Arduino ISP • Arduino USB 2 Serial Micro • Arduino Mini USB Serial Adapter |
Интернет вещей | Arduino Yun • Arduino Ethernet • Arduino MKR1000 • Arduino WiFi 101 Shield • Arduino GSM Shield V2 • Arduino WiFi Shield • Arduino Wireless SD Shield • Arduino Wireless Proto Shield • Arduino Ethernet Shield V2 • Arduino Yun Shield • Arduino MKR1000 Bundle |
Носимые устройства | Arduino Gemma • Lilypad Arduino Simple • Lilypad Arduino Main Board • Lilypad Arduino USB • LilyPad Arduino SimpleSnap |
3D-печать | Arduino Materia 101 |
Устаревшие устройства | - |
Примеры Arduino | |
---|---|
Стандартные функции | |
Основы |
|
Цифровой сигнал |
|
Аналоговый сигнал |
|
Связь |
|
Управляющие структуры |
|
Датчики |
|
Дисплей |
Примеры, объясняющие основы управления дисплеем:
|
Строки |
|
USB (для Leonardo, Micro и Due плат) |
В этой секции имеют место примеры, которые демонстрируют использование библиотек, уникальных для плат Leonardo, Micro и Due.
|
Клавиатура |
|
Мышь |
|
Разное |
Категории:
- Страницы, использующие повторяющиеся аргументы в вызовах шаблонов
- Справочник языка Arduino
- Arduino
- Перевод от Сubewriter
- Проверка:myagkij
- Оформление:myagkij
- Редактирование:myagkij
- Страницы, где используется шаблон "Навигационная таблица/Телепорт"
- Страницы с телепортом
- Пример
- Примеры
- Пример программирования Arduino
- Примеры программирования Arduino