Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- #############################
- Код написан студентом группы КИУКИ-18-6 Зайцевым Дмитрием
- #############################
- */
- #include <iostream> //Библиотека потока ввода/вывода
- #include <conio.h> //Из библиотеки взята только функция getch();
- #include <Windows.h> //Из библиотеки используется только задержка Sleep();
- #include <ctime> //Используется для рандомизации в зависимости от времени
- #include <string>
- using namespace std;
- int Neighbors(char *mas[],int i,int j,int sizeY,int sizeX) { //Функция для определения количества соседей
- int result = 0; //Результат, который функция вернёт при выполнении
- for (int k = -1; k < 2; k++)
- {
- for (int l = -1; l < 2; l++)
- {
- int neighVarX = 0; int neighVarY = 0; //Координаты по Ох и по Оу окрестности точки, которая проверяется
- /* Проверка на границы поля */
- if ((i == 0 && k == -1) || (i == sizeY - 1 && k == 1)) //Если проверяется точка выше верхней границы ИЛИ ниже нижней, то берется первая координата противоположной стороны
- {
- neighVarY += (-k * sizeY);
- }
- if ((j == 0 && l == -1) || (j == sizeX - 1 && l == 1)) //Если проверяется точка левее левой границы ИЛИ правее правой, то берется первая координата противоположной стороны
- {
- neighVarX += (-l * sizeX);
- }
- if (mas[i + k + neighVarY][j + l + neighVarX] == '@' && !(k == 0 && l == 0)) //Проверка на наличие жизни в клетке
- {
- result += 1; //Результат увеличивается на +1 если клетка-сосед живая
- }
- }
- }
- return result;
- }
- int gens, step = 0;
- void Nextgen(char **mas,int sizeY, int sizeX) { //Функция для определения следующего поколения
- char**masCopy = new char*[sizeY]; /* Создание временного массива */
- for (int i = 0; i < sizeY; i++)
- masCopy[i] = new char[sizeX];
- for (int i = 0; i < sizeY; i++) /*перебор всех клеток поля*/
- {
- for (int j = 0; j < sizeX; j++)
- {
- /* Проверка правил игры Жизнь */
- if (Neighbors(mas, i, j, sizeY, sizeX) == 2) { masCopy[i][j] = mas[i][j]; } //Если у клетки 2 соседа, то состояние клетки не меняется
- else if (Neighbors(mas, i, j, sizeY, sizeX) == 3) { masCopy[i][j] = '@'; } //Иначе если у клетки 3 соседа, то там зарождается жизнь
- else { masCopy[i][j] = ' '; } //Иначе клетка погибает
- }
- }
- for (int i = 0; i < sizeY; i++) /* Перепись временного массива в основной */
- {
- for (int j = 0; j < sizeX; j++)
- {
- mas[i][j] = masCopy[i][j];
- }
- }
- step++; //Счётчик генерации +1
- }
- void fillSpace(char **mas, int sizeY, int sizeX) { /* Функция очистки поля */
- for (int i = 0; i < sizeY; i++) //Перебор элементов поля
- {
- for (int j = 0; j < sizeX; j++)
- {
- mas[i][j] = ' '; //Присвоение элементу ' '
- }
- }
- }
- void printArray(char *mas[], int sizeY, int sizeX) { /* Функция вывода поля на экран */
- for (int i = 0; i < sizeY; i++) //Перебор элементов поля
- {
- for (int j = 0; j < sizeX; j++)
- {
- cout << mas[i][j]; //Вывод элемента
- }
- cout << "\n";
- }
- cout << "Generation: " << step << "\n"; //Счётчик генераций
- }
- void fillManually(char **mas,int sizeY,int sizeX) { /* Функция ручного ввода клеток в поле */
- fillSpace(mas, sizeY, sizeX); //Предварительная очистка
- int tempX=0, tempY=0,key=0; //Координаты текущего положения метки; Ключ, который хранит значение нажатой клавиши
- while (1) {
- system("cls"); //Очистка экрана перед изменением выводимого поля
- if (tempX == -1) { tempX = sizeX - 1; } //Если положение метки стремится за левую границу, то метка перемещается на правую
- if (tempX == sizeX) { tempX = 0; } //Если положение метки стремится за правую границу, то метка перемещается на левую
- if (tempY == -1) { tempY = sizeY - 1; } //Если положение метки стремится за верхнюю границу, то метка перемещается на нижнюю
- if (tempY == sizeY) { tempY = 0; } //Если положение метки стремится за нижнюю границу, то метка перемещается на верхнюю
- if (mas[tempY][tempX]!='@') { //Если метка на неживой клетке, то метка принимает вид "х"
- mas[tempY][tempX] = 'x';
- }
- else if(mas[tempY][tempX]=='@'){ mas[tempY][tempX] = 'X'; } //Иначе если метка уже на живой клетке, то она принимает значение "Х"
- printArray(mas, sizeY, sizeX); //Вывод поля вместе с меткой
- cout << "\'W\'-Up\t\'A\'-Left\t\'S\'-Down\t\'D\'-Right\t\'Space\'-Set\/Delete mark\t \'Enter\'-Exit"; //Вывод клавиш, необходимых для управления меткой
- key = _getch(); //Получение индивидуального кода нажатой клавиши
- char prevChar = mas[tempY][tempX]; //Сохранение текущего положения метки
- if (prevChar == 'X')mas[tempY][tempX] = '@'; //Если метка имеет вид "Х", то там будет жизнь
- switch (key) {
- case 119: if (prevChar!='@'&&prevChar!='X') mas[tempY][tempX] = ' '; tempY -= 1; break; //При нажатии клавиши "W" метка перемещается на 1 вверх. Если она была в положении "х", то она очищается
- case 97: if (prevChar != '@'&&prevChar != 'X') mas[tempY][tempX] = ' '; tempX -= 1; break; //При нажатии клавиши "A" метка перемещается на 1 влево. Если она была в положении "х", то она очищается
- case 115: if (prevChar != '@'&&prevChar != 'X') mas[tempY][tempX] = ' '; tempY += 1; break; //При нажатии клавиши "S" метка перемещается на 1 вниз. Если она была в положении "х", то она очищается
- case 100: if (prevChar != '@'&&prevChar != 'X') mas[tempY][tempX] = ' '; tempX += 1; break; //При нажатии клавиши "D" метка перемещается на 1 вправо. Если она была в положении "х", то она очищается
- case 32: if (prevChar != 'X')mas[tempY][tempX] = '@'; else { mas[tempY][tempX] = 'x'; } break; //При нажатии клавиши "Space": если метка была в состоянии "х", то там зарождется жизнь, иначе метка принимает значение "x"
- case 13: if (prevChar != '@'&&prevChar != 'X') mas[tempY][tempX] = ' '; return; //При нажатии клавиши "Enter" производится выход в меню
- }
- }
- }
- void fillRandom(char **mas, int sizeY, int sizeX) { /* Функция рандомного заполнения поля */
- fillSpace(mas, sizeY, sizeX); //Предварительная очистка поля
- int density; //Плотность заполнения поля
- string temp_density; //Временная переменная, в которую мы записываем значение плотности в строковом виде
- bool error=0; //Переменная-флаг, которая хранит наличие ошибки
- while (1) { //Цикл для исключения ошибок при вводе плотности
- cout << "\nInput density (1-10): "; cin >> temp_density; //Выбор плотности заполнения от 1 до 10
- for (int i = 0; i < size(temp_density); i++) { if (!(temp_density[i] >= '0'&&temp_density[i] <= '9')) error = 1; } //Проверка введённой плотности на цифры
- if (error) { error = 0; system("cls"); cout << "Only numbers!\n"; continue; } //Если флаг ошибки == 1, то он обнуляется, и после очистки поля выводится сообщение об ошибке, предлагается повторный ввод
- density = stoi(temp_density); //Если всё хорошо, значение плотности переводится в целочисленный тип
- if (density < 1 || density>10) { cout << "Input again!\n"; continue; } //Проверка на границы плотности, просьба ввести ещё раз при выходе за границы
- else { break; } //Выход из цикла при правильном вводе
- }
- for (int i = 0; i < sizeY; i++) //Перебор всех клеток поля
- {
- for (int j = 0; j < sizeX; j++)
- {
- int temp = rand() % (11-density); //Определение состояния клетки
- if (temp != 1) { mas[i][j] = ' '; } //Присвоение элементу пробела с шансом ((11-density)/10)
- else { mas[i][j] = '@'; }
- }
- }
- }
- void fillArray(char **mas,int sizeY,int sizeX) { /* Функция заполнения поля (общая) */
- do {
- cout << "How do you want to fill array?\n1-Manually\n2-Random\n0-Exit\nYour choose: "; //Выбор режима заполнения ручной/автоматический(рандомный) либо выход
- int t_choose; t_choose = _getch();
- if (t_choose != 48 && t_choose != 49 && t_choose != 50) { system("cls"); cout << "Make another choose!\n"; continue; } //Если выбор не совпадает ни с одним из вариантов выбора, то новая иттерация
- else {
- switch (t_choose) {
- case 48: exit(0); //Выход из программы
- case 49: fillManually(mas, sizeY, sizeX); break; //Вызов функции ручного заполнения
- case 50: fillRandom(mas, sizeY, sizeX); break; //Вызов функции рандомного заполнения
- }
- system("cls"); return; //Очистка консоли после заполнения поля
- }
- } while (1);
- }
- void eatline() { while (cin.get() != '\n'); } //Функция, которая принимает на себя поток ввода, очищает его
- bool compare_arr(char **mas1, char**mas2, int sizeY, int sizeX) { //Функция сравнения массивов
- for(int i=0;i<sizeY;i++) //Перебор элементов массива
- for(int j=0;j<sizeX;j++)
- if (mas1[i][j] != mas2[i][j]) { //Если есть несовпадение, выход из функции с кодом 0
- return 0;
- }
- return 1;
- }
- int main()
- {
- bool error; //Переменная флаг, хранит информацию об ошибке
- int sizeY,sizeX;
- bool exitCode = 0;
- int counter = 0;
- do { //Определение высоты поля
- string temp_sizeY;
- error = 0; //Обнуление флага-ошибки
- cout << "Input height (min 10 \/ max 25): "; cin >> temp_sizeY; eatline(); //Запись высоты в переменную строкового типа, очистка потока ввода после первого пробела
- for (int i = 0; i < size(temp_sizeY); i++) { if (!(temp_sizeY[i] >= '0'&&temp_sizeY[i] <= '9')) error = 1; } //Проверка на наличие не цифр в о введённой строке
- if (error) { error = 0; system("cls"); cout << "Only numbers!\n"; continue; } //Если есть ошибка, просьба ввести повторно
- if (size(temp_sizeY) > 4) { system("cls"); cout << "Too long, change height\n"; continue; } //Если введённая цифра очень длинная, просьба ввести повторно
- else { sizeY = stoi(temp_sizeY); } //Если всё хорошо, запись высоты в переменную целочисленного типа
- if (sizeY < 10 || sizeY>25) { cout << "Change height\n"; } //Если введённая цифра не попадает в диапазон, просьба ввести повторно
- else break; //Если всё хорошо, выход из цикла ввода высоты
- } while (1);
- do { //Определение высоты поля
- string temp_sizeX;
- error = 0;//Обнуление флага-ошибки
- cout << "Input width (min 10 \/ max 40): "; cin >> temp_sizeX; eatline();//Запись ширины в переменную строкового типа, очистка потока ввода после первого пробела
- for (int i = 0; i < size(temp_sizeX); i++) { if (!(temp_sizeX[i] >= '0'&&temp_sizeX[i] <= '9')) error = 1; } //Проверка на наличие не цифр в о введённой строке
- if (error) { error = 0; system("cls"); cout << "Only numbers!\n"; continue; } //Если есть ошибка, просьба ввести повторно
- if (size(temp_sizeX) > 4) { system("cls"); cout << "Too long, change width\n"; continue; } //Если введённая цифра очень длинная, просьба ввести повторно
- else { sizeX = stoi(temp_sizeX); } //Если всё хорошо, запись высоты в переменную целочисленного типа
- if (sizeX < 10 || sizeX>40) { cout << "Change width\n"; } //Если введённая цифра не попадает в диапазон, просьба ввести повторно
- else break; //Если всё хорошо, выход из цикла ввода ширины
- } while (1);
- char** mas = new char*[sizeY]; //Создание поля
- for (int i = 0; i < sizeY; i++)
- mas[i] = new char[sizeX];
- char **temp_mas = new char*[sizeY]; //Создание поля, которое хранит состояние основного поля на 2 поколения назад
- for (int i = 0; i < sizeY; i++)
- temp_mas[i] = new char[sizeX] {' '};
- fillSpace(mas,sizeY,sizeX); //Заполнение поля пробелами
- fillArray(mas, sizeY, sizeX); //Вызов функции для заполнения поля
- do
- {
- int choose; //Переменная выбора
- cout << "0-Exit\n1-Print some gens\n2-Fill again\nChoose your destiny: "; //Вывод меню
- choose=_getch();
- switch (choose) {
- case 48:return 0; //Выход из программы
- case 49:int delay; //Переменная задержки между выводами поколений
- do {
- error = 0; //Обнуления флага-ошибки
- string temp_delay;
- cout << "\nWhat's delay? (ms) (0-1000): "; eatline(); cin >> temp_delay; //Ввод задержки между выводами поколений
- for (int i = 0; i < size(temp_delay); i++) { if (!(temp_delay[i] >= '0'&&temp_delay[i] <= '9')) error = 1; } //Проверка на наличие букв
- if (error) { error = 0; system("cls"); cout << "Only numbers!\n"; continue; } //Если есть не числа, просьба ввести повторно
- if (size(temp_delay) > 4) { system("cls"); cout << "Too long, please change\n"; continue; } //Если размер числа очень большой, просьба ввести повторно
- else { delay = stoi(temp_delay); } //Запись задержки в переменную целочисленного типа
- if (delay < 0 || delay>1000) { cout << "From 0 to 1000 ms!\n"; } //Проверка на попадание в рамки
- else break; //Если всё хорошо, выход из цикла ввода задержки
- } while (1);
- system("cls");
- while(!_kbhit()&&exitCode!=1){ //Цикл для вывода поколений, пока не нажата клавиша, либо не зациклена генерация поколений
- if (counter == 0){for (int i = 0; i < sizeY; i++) //Если это первое поколение, запись его во временный массив
- for (int j = 0; j < sizeX; j++)
- temp_mas[i][j] = mas[i][j]; }
- Nextgen(mas, sizeY, sizeX); //генерация следующего поколения
- if (counter % 2 == 0&&counter!=0) { //Проверка на несоседнее поколение, и что оно не первое
- if (compare_arr(mas, temp_mas, sizeY, sizeX)) {
- exitCode = 1; //Если предпоследнее поколение совпадает с текущим, флаг для выхода устанавливается в 1
- }
- else {
- for (int i = 0; i < sizeY; i++) //Если не совпадает, запись его во временный массив
- for (int j = 0; j < sizeX; j++)
- temp_mas[i][j] = mas[i][j];
- }
- }
- printArray(mas, sizeY, sizeX); //Вывод только что сгенерированного поколения
- cout << "Press \'Any key\' to exit\n"; //Вывод комбинации для закрытия программы во время вывода
- Sleep(delay); //Задержка перед следующим выводом
- system("cls");
- counter++; //Увеличение счётчика поколений на +1
- }
- if (exitCode == 1) { cout << "All cells died or looped\n"; exitCode = 0; counter = 0; }
- cout << "Press any button\n"; _getch(); system("cls"); break; //Ожидание нажатия клавиши для продолжения после вывода последнего поколения
- case 50: system("cls"); fillArray(mas, sizeY, sizeX); step = 0; break; //Вызов функции для заполнения поля
- default: system("cls"); cout << "Change your choose\n"; continue; //Просьба изменить выбор, если выбран несуществующий пункт меню
- }
- } while (1);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement