The Game Of Life – 数据结构与算法的敲门砖
The Game Of Life(生命游戏,又称为细胞自动机)几乎是所有数据结构与算法导论教程前言的一个很经典的程序了。这是一个零玩家游戏,发生在一个平面网格里。每个格子的细胞都有死亡和存活两种状态,在代与代之间有两种状态,如果每一个细胞周围少于或等于1个细胞或多于4个细胞时,他会在下一代死亡;如果一个格子周围恰好有3个细胞,他将会重新活过来。
例如,当一种特别的状态被初始化后,会形成下列状态。
也会有循环或者稳定的状态:
更有甚者发现的「滑行者枪」,可以源源不断地向外发射滑行者。
接下来是一个用C++和控制台实现生命游戏的尝试。本可以很短小的,但上周闲下来的时候东增西补地加了许多东西,也算是当作初学面向对象的一个习题了吧,实现了一个可以自动运行,随机初始化和自定义规则的黑框框生命游戏。
运行效果
Source Code:
1 #include "pch.h" 2 #include <iostream> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <windows.h> 6 constexpr int FIRST_INTRODUCTION = 0; 7 constexpr int MANIPUNATE_INSTRUCTION = 1; 8 constexpr int WITH_GENERATION_INFO = 1; 9 constexpr int NO_GENERATION_INFO = 0; 10 //Define rules; 11 int BOTTOM_LIMIT = 1; 12 int UPPER_LIMIT = 4; 13 int REBIRTH_NUM = 3; 14 //define characters to print 15 const char LIVEC = '#'; 16 const char DIEC = '.'; 17 const int MAXL = 101; 18 using namespace std; 19 class LifeMap { 20 public: 21 int width; 22 int height; 23 int matrix[MAXL][MAXL] = { 0 }; 24 int surround[MAXL][MAXL] = { 0 }; 25 int generation = 0; 26 void instructor(int type) { 27 switch (type) { 28 case FIRST_INTRODUCTION: 29 cout << "Welcome to the Game of Life!" << endl << endl << 30 "生命游戏是一个零玩家游戏,它包括一个二维矩形世界,这个世界中的每个方格居住着一个活着的或死了的细胞。一个细胞在下一个时刻生死取决于相邻八个方格中活着的或死了的细胞的数量。如果相邻方格活着的细胞数量过多,这个细胞会因为资源匮乏而在下一个时刻死去;相反,如果周围活细胞过少,这个细胞会因太孤单而死去。" 31 << endl << "实际中,你可以设定周围活细胞的数目怎样时才适宜该细胞的生存。如果这个数目设定过低,世界中的大部分细胞会因为找不到太多的活的邻居而死去,直到整个世界都没有生命;如果这个数目设定过高,世界中又会被生命充满而没有什么变化。所以我们把这个数目选取为2或者3;这样整个生命世界才不至于太过荒凉或拥挤,而是一种动态的平衡。" 32 << endl << "这样的话,游戏的规则就是:当一个方格周围有2或3个活细胞时,方格中的活细胞在下一个时刻继续存活;即使这个时刻方格中没有活细胞,在下一个时刻也会“诞生”活细胞。在这个游戏中,还可以设定一些更加复杂的规则,例如当前方格的状况不仅由父一代决定,而且还考虑祖父一代的情况。" 33 << endl << "你作为这个世界的上帝,随意设定某个方格细胞的死活,以观察对世界的影响。在游戏的进行中,杂乱无序的细胞会逐渐演化出各种精致、有形的结构;这些结构往往有很好的对称性,而且每一代都在变化形状。一些形状已经锁定,不会逐代变化。有时,一些已经成形的结构会因为一些无序细胞的“入侵”而被破坏。但是形状和秩序经常能从杂乱中产生出来。" 34 << endl << endl << " Please insert the width AND the height of the grid:" << endl << "(Max Length is " << MAXL - 2 << ")" << endl; 35 break; 36 case MANIPUNATE_INSTRUCTION: 37 cout << endl << "Now you can insert \"L X Y\" (eg. L 2 3 or l 2 3 to set the cell located in the 2nd row, 3rd column) to set a cell to live," 38 << endl << "insert \"D X Y\" to set a cell to die. insert \"P\" to print the current status." 39 << endl << "\"N\" for simply jump tp the next generation.\nN (optional)GENERATIONS (optional)INTERVAL_TIME for evolve multiple generation at a time." 40 << endl << "Insert \"R\" to reset your gird and \"Q\" to quit." << endl 41 << "Inset X to define rules." 42 << "Most interstingly, you can radomlize every cell by insert \"!\"" << endl << "You can set multiple cells' status in one line." << endl; 43 break; 44 } 45 46 } 47 void initialize(int W, int H) { 48 int i, j; 49 for (i = 0; i < MAXL; i++) { 50 for (j = 0; j < MAXL; j++) { 51 matrix[i][j] = 0; 52 surround[i][j] = 0; 53 } 54 } 55 width = W; 56 height = H; 57 generation = 0; 58 } 59 void printer(int gen) { 60 //gen = 1 for printing with generation info. 61 if (gen == 1) { 62 cout << "\n Generation No." << generation << ":" << endl; 63 } 64 cout << endl; 65 int i, j; 66 cout << " "; 67 for (i = 0; i < width; i++) { 68 printf("%2d ", i + 1); 69 } 70 cout << endl; 71 for (i = 0; i < height; i++) { 72 printf("%2d ", i + 1); 73 for (j = 0; j < width; j++) { 74 if (matrix[i + 1][j + 1] == 0) printf("%c ", DIEC); 75 else if (matrix[i + 1][j + 1] == 1) printf("%c ", LIVEC); 76 } 77 cout << endl; 78 } 79 cout << endl; 80 //print ratio 81 if (gen == 1) { 82 int liveCells = 0; 83 for (i = 0; i < height; i++) { 84 for (j = 0; j < width; j++) { 85 if (matrix[i + 1][j + 1] == 1) liveCells++; 86 } 87 } 88 cout << " Live cell ratio: " << (double)liveCells / (double)(width*height) * 100.0 89 << "% (" << liveCells << "/" << width * height << ")" << endl << endl; 90 } 91 } 92 void SetLiving(int W, int H) { 93 if (W <= 0 || W > width || H <= 0 || H > height) 94 cout << "Unvalid input, please try again.\n"; 95 else { 96 matrix[W][H] = 1; 97 cout << "Cell (" << W << " ," << H << ") came alive." << endl; 98 } 99 100 } 101 void SetDying(int W, int H) { 102 if (W <= 0 || W > width || H <= 0 || H > height) 103 cout << "Unvalid input, please try again.\n"; 104 else { 105 matrix[W][H] = 0; 106 cout << "Cell (" << W << " ," << H << ") has been dead." << endl; 107 } 108 109 } 110 void Radomlize() { 111 int i, j; 112 cout << "Randomlizing cell status..." << endl; 113 for (i = 0; i < height; i++) { 114 for (j = 0; j < width; j++) { 115 //srand(time(NULL)); 116 if ((rand() % 2) == 1) matrix[i + 1][j + 1] = 0; 117 else { 118 matrix[i + 1][j + 1] = 1; 119 cout << "Cell (" << i + 1 << " ," << j + 1 << ") came alive." << endl; 120 } 121 } 122 } 123 } 124 void Next() { 125 int i, j; 126 //Initialize the surround matrix. 127 for (i = 0; i < MAXL; i++) { 128 for (j = 0; j < MAXL; j++) { 129 surround[i][j] = 0; 130 } 131 } 132 //Calculate the surrounded live cells 133 for (i = 0; i < height; i++) { 134 for (j = 0; j < width; j++) { 135 if (matrix[i][j] == 1) surround[i + 1][j + 1]++; 136 if (matrix[i][j + 1] == 1) surround[i + 1][j + 1]++; 137 if (matrix[i][j + 2] == 1) surround[i + 1][j + 1]++; 138 if (matrix[i + 1][j] == 1) surround[i + 1][j + 1]++; 139 if (matrix[i + 1][j + 2] == 1) surround[i + 1][j + 1]++; 140 if (matrix[i + 2][j] == 1) surround[i + 1][j + 1]++; 141 if (matrix[i + 2][j + 1] == 1) surround[i + 1][j + 1]++; 142 if (matrix[i + 2][j + 2] == 1) surround[i + 1][j + 1]++; 143 } 144 } 145 //Rules 146 for (i = 0; i < height; i++) { 147 for (j = 0; j < width; j++) { 148 if (surround[i + 1][j + 1] >= UPPER_LIMIT) matrix[i + 1][j + 1] = 0; 149 if (surround[i + 1][j + 1] <= BOTTOM_LIMIT) matrix[i + 1][j + 1] = 0; 150 if (surround[i + 1][j + 1] == REBIRTH_NUM) matrix[i + 1][j + 1] = 1; 151 } 152 } 153 generation++; 154 } 155 void Definer() { 156 int i, j, k; 157 cout << "Please insert three value to define the rules: (Defaul Configuration:1 4 3)" << endl 158 << "BOTTOM_LIMIT UPPER_LIMIT REBIRTH_NUM" << endl; 159 inputrule: cout << ">> "; cin >> i >> j >> k; 160 if (cin.fail() || i >= 8 || j >= 8 || k >= 8 || i < 0 || j < 0 || k < 0) { 161 cout << "Invalid input, please input three positive integers smaller than 8." << endl; 162 cin.clear(); 163 while (cin.get() != '\n'); 164 goto inputrule; 165 } 166 else { 167 BOTTOM_LIMIT = i; 168 UPPER_LIMIT = j; 169 REBIRTH_NUM = k; 170 printf("Rules have been defined to %d %d %d.\n", i, j, k); 171 } 172 } 173 }; 174 int main() 175 { 176 LifeMap Map; 177 //These variables are used for manipunating. 178 int X, Y; 179 //these two labels are used for jumping for input that's too large and the reset command. 180 start: Map.instructor(FIRST_INTRODUCTION); 181 input: cin >> X >> Y; 182 while (cin.fail()) { 183 cout << "Unvalid input, please try again. Pleas type two integers." << endl; 184 cin.clear(); 185 while (cin.get() != '\n') continue; 186 cin >> X >> Y; 187 } 188 while (X >= 100 || Y >= 100) { 189 cout << "Too long." << endl; 190 cin.clear(); 191 goto input; 192 } 193 Map.instructor(MANIPUNATE_INSTRUCTION); 194 cout << "This is all the cells you have." << endl; 195 Map.initialize(X, Y); 196 Map.printer(NO_GENERATION_INFO); 197 cin.clear(); 198 while (cin.get() != '\n') continue; // Clear datas in the cache. 199 char command; 200 while ((command = toupper(cin.get())) != 'Q') { 201 switch (command) { 202 case 'L': 203 cin >> X >> Y; 204 if (cin.fail()) { 205 cout << "Unvalid input, please try again." << endl; 206 cin.clear(); 207 while (cin.get() != '\n') continue; 208 } 209 else 210 Map.SetLiving(X, Y); 211 break; 212 case 'D': 213 cin >> X >> Y; 214 if (cin.fail()) { 215 cout << "Unvalid input, please try again." << endl; 216 cin.clear(); 217 while (cin.get() != '\n') continue; 218 } 219 else 220 Map.SetDying(X, Y); 221 break; 222 case 'P': 223 Map.printer(WITH_GENERATION_INFO); 224 break; 225 case 'N': 226 //gens mens the number of generations to evolve 227 //interval means the interval times between two evolutions 228 int i, gens, interval; 229 if (cin.get() != '\n') { 230 cin >> gens; 231 if (cin.get() == '\n') interval = 0; 232 else cin >> interval; 233 if (gens <= 0 || interval < 0) { 234 cout << "Unvalid input, please enter positive integers." << endl; 235 cin.clear(); 236 while (cin.get() != '\n') continue; 237 } 238 else { 239 for (i = 0; i < gens; i++) { 240 system("cls"); 241 Map.instructor(MANIPUNATE_INSTRUCTION); 242 Map.Next(); 243 Map.printer(WITH_GENERATION_INFO); 244 Sleep(interval); 245 } 246 } 247 } 248 else { 249 system("cls"); 250 Map.instructor(MANIPUNATE_INSTRUCTION); 251 Map.Next(); 252 Map.printer(WITH_GENERATION_INFO); 253 } 254 break; 255 case 'R': 256 system("cls"); 257 goto start; 258 break; 259 case '!': 260 Map.Radomlize(); 261 cout << "OK, now it's just chaos." << endl; 262 Map.printer(WITH_GENERATION_INFO); 263 break; 264 case 'X': 265 Map.Definer(); 266 case '\n': break; 267 case ' ': break; 268 default: 269 cout << "Unknown Command:(" << endl; 270 //while (cin.get() != '\n') continue; 271 } 272 } 273 cout << "See you:)\n\n"; 274 system("pause"); 275 return 0; 276 } 277
GitHub:https://github.com/BillChen2000/LearnigRepo/blob/master/Course/数据结构与算法/LifeGame/
图源:https://www.guokr.com/article/439770/
另外这里还有一个LifeWiki有详细的整理和介绍:http://www.conwaylife.com/wiki/
来源:https://billc.io/2019/02/the-game-of-life/
转载于:https://www.cnblogs.com/BillChen2000/p/the-game-of-life.html
The Game Of Life – 数据结构与算法的敲门砖相关推荐
- Python3-Cookbook总结 - 第一章:数据结构和算法
第一章:数据结构和算法 Python 提供了大量的内置数据结构,包括列表,集合以及字典.大多数情况下使用这些数据结构是很简单的. 但是,我们也会经常碰到到诸如查询,排序和过滤等等这些普遍存在的问题. ...
- 推荐一个关于.NET平台数据结构和算法的好项目
http://www.codeplex.com/NGenerics 这是一个类库,它提供了标准的.NET框架没有实现的通用的数据结构和算法.值得大家研究. 转载于:https://www.cnblog ...
- 数据结构和算法:(3)3.1线性表的顺序存储结构
-----------------------1.线性表基础操作------------------------ 线性表:(List)由零个或多个数据元素组成的有限序列. 首先他是一个序列,元素之间是 ...
- weiss数据结构和算法书的使用说明
<数据结构与算法分析 C语言描述>Mark Allen Weiss著,冯舜玺译,机械工业出版社.Weiss教授的经典教材三部曲之一,其中的C语言描述版本,也就是本书,被称为20世纪最重要的 ...
- 数据结构和算法 -- 学习导图
数据结构和算法 是作为程序员写出高效代码的基础,为了今后的两年在高效代码之路上持续精进,将按照此学习导图进行 算法和数据结构的刻意练习,同时也希望为同样有高效代码追求的伙伴们提供一条学习路径,共同进步 ...
- Java数据结构与算法(第四章栈和队列)
2019独角兽企业重金招聘Python工程师标准>>> 本章涉及的三种数据存储类型:栈.队列和优先级队列. 不同类型的结构 程序员的工具 数组是已经介绍过的数据存储结构,和其他结构( ...
- python数据结构与算法总结
python常用的数据结构与算法就分享到此处,本月涉及数据结构与算法的内容有如下文章: <数据结构和算法对python意味着什么?> <顺序表数据结构在python中的应用> ...
- 学习JavaScript数据结构与算法(一):栈与队列
本系列的第一篇文章: 学习JavaScript数据结构与算法(一),栈与队列 第二篇文章:学习JavaScript数据结构与算法(二):链表 第三篇文章:学习JavaScript数据结构与算法(三): ...
- MySQL索引背后的数据结构及算法原理【转】
http://blog.codinglabs.org/articles/theory-of-mysql-index.html MySQL索引背后的数据结构及算法原理[转] 摘要 本文以MySQL数据库 ...
- 数据结构与算法:22 精选练习50
精选练习50 马上就要期末考试或者考研了.为了大家复习的方便,我精选了有关数据结构与算法的50道选择题,大家可以抽空练习一下.公众号后台回复"答案"可以获取该50道题目的答案. 0 ...
最新文章
- 线阵相机和面阵相机的区别及应用
- 如何实现动态加载删除android,关于android:融云IMKit-动态删除或添加plugin-的实现...
- python歌星大奖赛_在歌星大奖赛中,有10个评委为参赛选手打分,分数为1到100分。...
- hdu5693 D gamehdu 5712 D++ game
- 最近30分钟合约市场爆仓702万美元 BTC爆仓281万美元
- opencl编程简单的入门知识
- 小红伞杀毒软件|小红伞杀毒软件下载
- Luarocks的使用
- 全网最全Linux命令总结!!(史上最全,建议收藏)
- 关于Ubuntu下firefox无法观看视频的解决
- Simulink 快速入门(二)--创建简单模型
- Java抓取网页图片
- oracle box怎么全屏,Oracle VM VirtualBox 虚拟机设置全屏与共享
- PHY--PDCCH
- LNMP架构动态网页
- js vue 获取 (昨天、今天、明天) 时间
- android homme2016款,#攻势来袭#Android Homme 2016 x DEAL线下预定全面开启
- echarts 双y轴设置
- 从零开始学java(二十六)--多维数组,多维数组存储表格数据
- 前端开发——Ionic 3.0【爱创课堂专业前端培训】