Advertisement
Guest User

Untitled

a guest
May 19th, 2019
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.70 KB | None | 0 0
  1. /*
  2. #############################
  3. Код написан студентом группы КИУКИ-18-6 Зайцевым Дмитрием
  4. #############################
  5. */
  6.  
  7. #include <iostream> //Библиотека потока ввода/вывода
  8. #include <conio.h> //Из библиотеки взята только функция getch();
  9. #include <Windows.h> //Из библиотеки используется только задержка Sleep();
  10. #include <ctime> //Используется для рандомизации в зависимости от времени
  11. #include <string>
  12. using namespace std;
  13.  
  14. int Neighbors(char *mas[],int i,int j,int sizeY,int sizeX) { //Функция для определения количества соседей
  15. int result = 0; //Результат, который функция вернёт при выполнении
  16. for (int k = -1; k < 2; k++)
  17. {
  18. for (int l = -1; l < 2; l++)
  19. {
  20. int neighVarX = 0; int neighVarY = 0; //Координаты по Ох и по Оу окрестности точки, которая проверяется
  21.  
  22. /* Проверка на границы поля */
  23. if ((i == 0 && k == -1) || (i == sizeY - 1 && k == 1)) //Если проверяется точка выше верхней границы ИЛИ ниже нижней, то берется первая координата противоположной стороны
  24. {
  25. neighVarY += (-k * sizeY);
  26. }
  27. if ((j == 0 && l == -1) || (j == sizeX - 1 && l == 1)) //Если проверяется точка левее левой границы ИЛИ правее правой, то берется первая координата противоположной стороны
  28. {
  29. neighVarX += (-l * sizeX);
  30. }
  31. if (mas[i + k + neighVarY][j + l + neighVarX] == '@' && !(k == 0 && l == 0)) //Проверка на наличие жизни в клетке
  32. {
  33. result += 1; //Результат увеличивается на +1 если клетка-сосед живая
  34. }
  35. }
  36. }
  37. return result;
  38. }
  39.  
  40. int gens, step = 0;
  41. void Nextgen(char **mas,int sizeY, int sizeX) { //Функция для определения следующего поколения
  42. char**masCopy = new char*[sizeY]; /* Создание временного массива */
  43. for (int i = 0; i < sizeY; i++)
  44. masCopy[i] = new char[sizeX];
  45.  
  46. for (int i = 0; i < sizeY; i++) /*перебор всех клеток поля*/
  47. {
  48. for (int j = 0; j < sizeX; j++)
  49. {
  50. /* Проверка правил игры Жизнь */
  51. if (Neighbors(mas, i, j, sizeY, sizeX) == 2) { masCopy[i][j] = mas[i][j]; } //Если у клетки 2 соседа, то состояние клетки не меняется
  52. else if (Neighbors(mas, i, j, sizeY, sizeX) == 3) { masCopy[i][j] = '@'; } //Иначе если у клетки 3 соседа, то там зарождается жизнь
  53. else { masCopy[i][j] = ' '; } //Иначе клетка погибает
  54. }
  55. }
  56.  
  57. for (int i = 0; i < sizeY; i++) /* Перепись временного массива в основной */
  58. {
  59. for (int j = 0; j < sizeX; j++)
  60. {
  61. mas[i][j] = masCopy[i][j];
  62. }
  63. }
  64. step++; //Счётчик генерации +1
  65. }
  66.  
  67. void fillSpace(char **mas, int sizeY, int sizeX) { /* Функция очистки поля */
  68. for (int i = 0; i < sizeY; i++) //Перебор элементов поля
  69. {
  70. for (int j = 0; j < sizeX; j++)
  71. {
  72. mas[i][j] = ' '; //Присвоение элементу ' '
  73. }
  74. }
  75. }
  76.  
  77. void printArray(char *mas[], int sizeY, int sizeX) { /* Функция вывода поля на экран */
  78. for (int i = 0; i < sizeY; i++) //Перебор элементов поля
  79. {
  80. for (int j = 0; j < sizeX; j++)
  81. {
  82. cout << mas[i][j]; //Вывод элемента
  83. }
  84. cout << "\n";
  85. }
  86. cout << "Generation: " << step << "\n"; //Счётчик генераций
  87. }
  88.  
  89. void fillManually(char **mas,int sizeY,int sizeX) { /* Функция ручного ввода клеток в поле */
  90. fillSpace(mas, sizeY, sizeX); //Предварительная очистка
  91. int tempX=0, tempY=0,key=0; //Координаты текущего положения метки; Ключ, который хранит значение нажатой клавиши
  92. while (1) {
  93. system("cls"); //Очистка экрана перед изменением выводимого поля
  94. if (tempX == -1) { tempX = sizeX - 1; } //Если положение метки стремится за левую границу, то метка перемещается на правую
  95. if (tempX == sizeX) { tempX = 0; } //Если положение метки стремится за правую границу, то метка перемещается на левую
  96. if (tempY == -1) { tempY = sizeY - 1; } //Если положение метки стремится за верхнюю границу, то метка перемещается на нижнюю
  97. if (tempY == sizeY) { tempY = 0; } //Если положение метки стремится за нижнюю границу, то метка перемещается на верхнюю
  98. if (mas[tempY][tempX]!='@') { //Если метка на неживой клетке, то метка принимает вид "х"
  99. mas[tempY][tempX] = 'x';
  100.  
  101. }
  102. else if(mas[tempY][tempX]=='@'){ mas[tempY][tempX] = 'X'; } //Иначе если метка уже на живой клетке, то она принимает значение "Х"
  103. printArray(mas, sizeY, sizeX); //Вывод поля вместе с меткой
  104. cout << "\'W\'-Up\t\'A\'-Left\t\'S\'-Down\t\'D\'-Right\t\'Space\'-Set\/Delete mark\t \'Enter\'-Exit"; //Вывод клавиш, необходимых для управления меткой
  105. key = _getch(); //Получение индивидуального кода нажатой клавиши
  106. char prevChar = mas[tempY][tempX]; //Сохранение текущего положения метки
  107. if (prevChar == 'X')mas[tempY][tempX] = '@'; //Если метка имеет вид "Х", то там будет жизнь
  108. switch (key) {
  109. case 119: if (prevChar!='@'&&prevChar!='X') mas[tempY][tempX] = ' '; tempY -= 1; break; //При нажатии клавиши "W" метка перемещается на 1 вверх. Если она была в положении "х", то она очищается
  110. case 97: if (prevChar != '@'&&prevChar != 'X') mas[tempY][tempX] = ' '; tempX -= 1; break; //При нажатии клавиши "A" метка перемещается на 1 влево. Если она была в положении "х", то она очищается
  111. case 115: if (prevChar != '@'&&prevChar != 'X') mas[tempY][tempX] = ' '; tempY += 1; break; //При нажатии клавиши "S" метка перемещается на 1 вниз. Если она была в положении "х", то она очищается
  112. case 100: if (prevChar != '@'&&prevChar != 'X') mas[tempY][tempX] = ' '; tempX += 1; break; //При нажатии клавиши "D" метка перемещается на 1 вправо. Если она была в положении "х", то она очищается
  113. case 32: if (prevChar != 'X')mas[tempY][tempX] = '@'; else { mas[tempY][tempX] = 'x'; } break; //При нажатии клавиши "Space": если метка была в состоянии "х", то там зарождется жизнь, иначе метка принимает значение "x"
  114. case 13: if (prevChar != '@'&&prevChar != 'X') mas[tempY][tempX] = ' '; return; //При нажатии клавиши "Enter" производится выход в меню
  115. }
  116. }
  117. }
  118.  
  119. void fillRandom(char **mas, int sizeY, int sizeX) { /* Функция рандомного заполнения поля */
  120. fillSpace(mas, sizeY, sizeX); //Предварительная очистка поля
  121. int density; //Плотность заполнения поля
  122. string temp_density; //Временная переменная, в которую мы записываем значение плотности в строковом виде
  123. bool error=0; //Переменная-флаг, которая хранит наличие ошибки
  124. while (1) { //Цикл для исключения ошибок при вводе плотности
  125. cout << "\nInput density (1-10): "; cin >> temp_density; //Выбор плотности заполнения от 1 до 10
  126.  
  127. for (int i = 0; i < size(temp_density); i++) { if (!(temp_density[i] >= '0'&&temp_density[i] <= '9')) error = 1; } //Проверка введённой плотности на цифры
  128. if (error) { error = 0; system("cls"); cout << "Only numbers!\n"; continue; } //Если флаг ошибки == 1, то он обнуляется, и после очистки поля выводится сообщение об ошибке, предлагается повторный ввод
  129. density = stoi(temp_density); //Если всё хорошо, значение плотности переводится в целочисленный тип
  130.  
  131. if (density < 1 || density>10) { cout << "Input again!\n"; continue; } //Проверка на границы плотности, просьба ввести ещё раз при выходе за границы
  132. else { break; } //Выход из цикла при правильном вводе
  133. }
  134. for (int i = 0; i < sizeY; i++) //Перебор всех клеток поля
  135. {
  136. for (int j = 0; j < sizeX; j++)
  137. {
  138. int temp = rand() % (11-density); //Определение состояния клетки
  139. if (temp != 1) { mas[i][j] = ' '; } //Присвоение элементу пробела с шансом ((11-density)/10)
  140. else { mas[i][j] = '@'; }
  141. }
  142. }
  143. }
  144.  
  145. void fillArray(char **mas,int sizeY,int sizeX) { /* Функция заполнения поля (общая) */
  146.  
  147. do {
  148. cout << "How do you want to fill array?\n1-Manually\n2-Random\n0-Exit\nYour choose: "; //Выбор режима заполнения ручной/автоматический(рандомный) либо выход
  149. int t_choose; t_choose = _getch();
  150. if (t_choose != 48 && t_choose != 49 && t_choose != 50) { system("cls"); cout << "Make another choose!\n"; continue; } //Если выбор не совпадает ни с одним из вариантов выбора, то новая иттерация
  151. else {
  152. switch (t_choose) {
  153. case 48: exit(0); //Выход из программы
  154. case 49: fillManually(mas, sizeY, sizeX); break; //Вызов функции ручного заполнения
  155. case 50: fillRandom(mas, sizeY, sizeX); break; //Вызов функции рандомного заполнения
  156. }
  157. system("cls"); return; //Очистка консоли после заполнения поля
  158. }
  159. } while (1);
  160. }
  161.  
  162. void eatline() { while (cin.get() != '\n'); } //Функция, которая принимает на себя поток ввода, очищает его
  163.  
  164. bool compare_arr(char **mas1, char**mas2, int sizeY, int sizeX) { //Функция сравнения массивов
  165. for(int i=0;i<sizeY;i++) //Перебор элементов массива
  166. for(int j=0;j<sizeX;j++)
  167. if (mas1[i][j] != mas2[i][j]) { //Если есть несовпадение, выход из функции с кодом 0
  168. return 0;
  169. }
  170. return 1;
  171. }
  172.  
  173. int main()
  174. {
  175. bool error; //Переменная флаг, хранит информацию об ошибке
  176. int sizeY,sizeX;
  177. bool exitCode = 0;
  178. int counter = 0;
  179. do { //Определение высоты поля
  180. string temp_sizeY;
  181. error = 0; //Обнуление флага-ошибки
  182. cout << "Input height (min 10 \/ max 25): "; cin >> temp_sizeY; eatline(); //Запись высоты в переменную строкового типа, очистка потока ввода после первого пробела
  183.  
  184. for (int i = 0; i < size(temp_sizeY); i++) { if (!(temp_sizeY[i] >= '0'&&temp_sizeY[i] <= '9')) error = 1; } //Проверка на наличие не цифр в о введённой строке
  185. if (error) { error = 0; system("cls"); cout << "Only numbers!\n"; continue; } //Если есть ошибка, просьба ввести повторно
  186.  
  187. if (size(temp_sizeY) > 4) { system("cls"); cout << "Too long, change height\n"; continue; } //Если введённая цифра очень длинная, просьба ввести повторно
  188. else { sizeY = stoi(temp_sizeY); } //Если всё хорошо, запись высоты в переменную целочисленного типа
  189.  
  190. if (sizeY < 10 || sizeY>25) { cout << "Change height\n"; } //Если введённая цифра не попадает в диапазон, просьба ввести повторно
  191. else break; //Если всё хорошо, выход из цикла ввода высоты
  192. } while (1);
  193.  
  194. do { //Определение высоты поля
  195. string temp_sizeX;
  196. error = 0;//Обнуление флага-ошибки
  197. cout << "Input width (min 10 \/ max 40): "; cin >> temp_sizeX; eatline();//Запись ширины в переменную строкового типа, очистка потока ввода после первого пробела
  198.  
  199. for (int i = 0; i < size(temp_sizeX); i++) { if (!(temp_sizeX[i] >= '0'&&temp_sizeX[i] <= '9')) error = 1; } //Проверка на наличие не цифр в о введённой строке
  200. if (error) { error = 0; system("cls"); cout << "Only numbers!\n"; continue; } //Если есть ошибка, просьба ввести повторно
  201.  
  202. if (size(temp_sizeX) > 4) { system("cls"); cout << "Too long, change width\n"; continue; } //Если введённая цифра очень длинная, просьба ввести повторно
  203. else { sizeX = stoi(temp_sizeX); } //Если всё хорошо, запись высоты в переменную целочисленного типа
  204.  
  205. if (sizeX < 10 || sizeX>40) { cout << "Change width\n"; } //Если введённая цифра не попадает в диапазон, просьба ввести повторно
  206. else break; //Если всё хорошо, выход из цикла ввода ширины
  207. } while (1);
  208.  
  209. char** mas = new char*[sizeY]; //Создание поля
  210. for (int i = 0; i < sizeY; i++)
  211. mas[i] = new char[sizeX];
  212.  
  213. char **temp_mas = new char*[sizeY]; //Создание поля, которое хранит состояние основного поля на 2 поколения назад
  214. for (int i = 0; i < sizeY; i++)
  215. temp_mas[i] = new char[sizeX] {' '};
  216.  
  217. fillSpace(mas,sizeY,sizeX); //Заполнение поля пробелами
  218. fillArray(mas, sizeY, sizeX); //Вызов функции для заполнения поля
  219.  
  220.  
  221. do
  222. {
  223. int choose; //Переменная выбора
  224. cout << "0-Exit\n1-Print some gens\n2-Fill again\nChoose your destiny: "; //Вывод меню
  225. choose=_getch();
  226. switch (choose) {
  227. case 48:return 0; //Выход из программы
  228. case 49:int delay; //Переменная задержки между выводами поколений
  229.  
  230. do {
  231. error = 0; //Обнуления флага-ошибки
  232. string temp_delay;
  233. cout << "\nWhat's delay? (ms) (0-1000): "; eatline(); cin >> temp_delay; //Ввод задержки между выводами поколений
  234.  
  235. for (int i = 0; i < size(temp_delay); i++) { if (!(temp_delay[i] >= '0'&&temp_delay[i] <= '9')) error = 1; } //Проверка на наличие букв
  236. if (error) { error = 0; system("cls"); cout << "Only numbers!\n"; continue; } //Если есть не числа, просьба ввести повторно
  237.  
  238. if (size(temp_delay) > 4) { system("cls"); cout << "Too long, please change\n"; continue; } //Если размер числа очень большой, просьба ввести повторно
  239. else { delay = stoi(temp_delay); } //Запись задержки в переменную целочисленного типа
  240.  
  241. if (delay < 0 || delay>1000) { cout << "From 0 to 1000 ms!\n"; } //Проверка на попадание в рамки
  242. else break; //Если всё хорошо, выход из цикла ввода задержки
  243. } while (1);
  244.  
  245. system("cls");
  246.  
  247. while(!_kbhit()&&exitCode!=1){ //Цикл для вывода поколений, пока не нажата клавиша, либо не зациклена генерация поколений
  248.  
  249. if (counter == 0){for (int i = 0; i < sizeY; i++) //Если это первое поколение, запись его во временный массив
  250. for (int j = 0; j < sizeX; j++)
  251. temp_mas[i][j] = mas[i][j]; }
  252.  
  253. Nextgen(mas, sizeY, sizeX); //генерация следующего поколения
  254. if (counter % 2 == 0&&counter!=0) { //Проверка на несоседнее поколение, и что оно не первое
  255. if (compare_arr(mas, temp_mas, sizeY, sizeX)) {
  256. exitCode = 1; //Если предпоследнее поколение совпадает с текущим, флаг для выхода устанавливается в 1
  257. }
  258. else {
  259. for (int i = 0; i < sizeY; i++) //Если не совпадает, запись его во временный массив
  260. for (int j = 0; j < sizeX; j++)
  261. temp_mas[i][j] = mas[i][j];
  262. }
  263. }
  264.  
  265. printArray(mas, sizeY, sizeX); //Вывод только что сгенерированного поколения
  266. cout << "Press \'Any key\' to exit\n"; //Вывод комбинации для закрытия программы во время вывода
  267. Sleep(delay); //Задержка перед следующим выводом
  268. system("cls");
  269. counter++; //Увеличение счётчика поколений на +1
  270. }
  271. if (exitCode == 1) { cout << "All cells died or looped\n"; exitCode = 0; counter = 0; }
  272. cout << "Press any button\n"; _getch(); system("cls"); break; //Ожидание нажатия клавиши для продолжения после вывода последнего поколения
  273. case 50: system("cls"); fillArray(mas, sizeY, sizeX); step = 0; break; //Вызов функции для заполнения поля
  274. default: system("cls"); cout << "Change your choose\n"; continue; //Просьба изменить выбор, если выбран несуществующий пункт меню
  275. }
  276.  
  277. } while (1);
  278. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement