The Game Of Life(生命游戏,又称为细胞自动机)几乎是所有数据结构与算法导论教程前言的一个很经典的程序了。这是一个零玩家游戏,发生在一个平面网格里。每个格子的细胞都有死亡和存活两种状态,在代与代之间有两种状态,如果每一个细胞周围少于或等于1个细胞或多于4个细胞时,他会在下一代死亡;如果一个格子周围恰好有3个细胞,他将会重新活过来。

例如,当一种特别的状态被初始化后,会形成下列状态。

周期为4的轻量级飞船

也会有循环或者稳定的状态:

周期为3的脉冲星
周期为3的Cross

更有甚者发现的「滑行者枪」,可以源源不断地向外发射滑行者。

滑行者枪
 

接下来是一个用C++和控制台实现生命游戏的尝试。本可以很短小的,但上周闲下来的时候东增西补地加了许多东西,也算是当作初学面向对象的一个习题了吧,实现了一个可以自动运行,随机初始化和自定义规则的黑框框生命游戏。

运行效果

Source Code:

 #include "pch.h"
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <windows.h>
constexpr int FIRST_INTRODUCTION = ;
constexpr int MANIPUNATE_INSTRUCTION = ;
constexpr int WITH_GENERATION_INFO = ;
constexpr int NO_GENERATION_INFO = ;
//Define rules;
int BOTTOM_LIMIT = ;
int UPPER_LIMIT = ;
int REBIRTH_NUM = ;
//define characters to print
const char LIVEC = '#';
const char DIEC = '.';
const int MAXL = ;
using namespace std;
class LifeMap {
public:
int width;
int height;
int matrix[MAXL][MAXL] = { };
int surround[MAXL][MAXL] = { };
int generation = ;
void instructor(int type) {
switch (type) {
case FIRST_INTRODUCTION:
cout << "Welcome to the Game of Life!" << endl << endl <<
"生命游戏是一个零玩家游戏,它包括一个二维矩形世界,这个世界中的每个方格居住着一个活着的或死了的细胞。一个细胞在下一个时刻生死取决于相邻八个方格中活着的或死了的细胞的数量。如果相邻方格活着的细胞数量过多,这个细胞会因为资源匮乏而在下一个时刻死去;相反,如果周围活细胞过少,这个细胞会因太孤单而死去。"
<< endl << "实际中,你可以设定周围活细胞的数目怎样时才适宜该细胞的生存。如果这个数目设定过低,世界中的大部分细胞会因为找不到太多的活的邻居而死去,直到整个世界都没有生命;如果这个数目设定过高,世界中又会被生命充满而没有什么变化。所以我们把这个数目选取为2或者3;这样整个生命世界才不至于太过荒凉或拥挤,而是一种动态的平衡。"
<< endl << "这样的话,游戏的规则就是:当一个方格周围有2或3个活细胞时,方格中的活细胞在下一个时刻继续存活;即使这个时刻方格中没有活细胞,在下一个时刻也会“诞生”活细胞。在这个游戏中,还可以设定一些更加复杂的规则,例如当前方格的状况不仅由父一代决定,而且还考虑祖父一代的情况。"
<< endl << "你作为这个世界的上帝,随意设定某个方格细胞的死活,以观察对世界的影响。在游戏的进行中,杂乱无序的细胞会逐渐演化出各种精致、有形的结构;这些结构往往有很好的对称性,而且每一代都在变化形状。一些形状已经锁定,不会逐代变化。有时,一些已经成形的结构会因为一些无序细胞的“入侵”而被破坏。但是形状和秩序经常能从杂乱中产生出来。"
<< endl << endl << " Please insert the width AND the height of the grid:" << endl << "(Max Length is " << MAXL - << ")" << endl;
break;
case MANIPUNATE_INSTRUCTION:
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,"
<< endl << "insert \"D X Y\" to set a cell to die. insert \"P\" to print the current status."
<< endl << "\"N\" for simply jump tp the next generation.\nN (optional)GENERATIONS (optional)INTERVAL_TIME for evolve multiple generation at a time."
<< endl << "Insert \"R\" to reset your gird and \"Q\" to quit." << endl
<< "Inset X to define rules."
<< "Most interstingly, you can radomlize every cell by insert \"!\"" << endl << "You can set multiple cells' status in one line." << endl;
break;
} }
void initialize(int W, int H) {
int i, j;
for (i = ; i < MAXL; i++) {
for (j = ; j < MAXL; j++) {
matrix[i][j] = ;
surround[i][j] = ;
}
}
width = W;
height = H;
generation = ;
}
void printer(int gen) {
//gen = 1 for printing with generation info.
if (gen == ) {
cout << "\n Generation No." << generation << ":" << endl;
}
cout << endl;
int i, j;
cout << " ";
for (i = ; i < width; i++) {
printf("%2d ", i + );
}
cout << endl;
for (i = ; i < height; i++) {
printf("%2d ", i + );
for (j = ; j < width; j++) {
if (matrix[i + ][j + ] == ) printf("%c ", DIEC);
else if (matrix[i + ][j + ] == ) printf("%c ", LIVEC);
}
cout << endl;
}
cout << endl;
//print ratio
if (gen == ) {
int liveCells = ;
for (i = ; i < height; i++) {
for (j = ; j < width; j++) {
if (matrix[i + ][j + ] == ) liveCells++;
}
}
cout << " Live cell ratio: " << (double)liveCells / (double)(width*height) * 100.0
<< "% (" << liveCells << "/" << width * height << ")" << endl << endl;
}
}
void SetLiving(int W, int H) {
if (W <= || W > width || H <= || H > height)
cout << "Unvalid input, please try again.\n";
else {
matrix[W][H] = ;
cout << "Cell (" << W << " ," << H << ") came alive." << endl;
} }
void SetDying(int W, int H) {
if (W <= || W > width || H <= || H > height)
cout << "Unvalid input, please try again.\n";
else {
matrix[W][H] = ;
cout << "Cell (" << W << " ," << H << ") has been dead." << endl;
} }
void Radomlize() {
int i, j;
cout << "Randomlizing cell status..." << endl;
for (i = ; i < height; i++) {
for (j = ; j < width; j++) {
//srand(time(NULL));
if ((rand() % ) == ) matrix[i + ][j + ] = ;
else {
matrix[i + ][j + ] = ;
cout << "Cell (" << i + << " ," << j + << ") came alive." << endl;
}
}
}
}
void Next() {
int i, j;
//Initialize the surround matrix.
for (i = ; i < MAXL; i++) {
for (j = ; j < MAXL; j++) {
surround[i][j] = ;
}
}
//Calculate the surrounded live cells
for (i = ; i < height; i++) {
for (j = ; j < width; j++) {
if (matrix[i][j] == ) surround[i + ][j + ]++;
if (matrix[i][j + ] == ) surround[i + ][j + ]++;
if (matrix[i][j + ] == ) surround[i + ][j + ]++;
if (matrix[i + ][j] == ) surround[i + ][j + ]++;
if (matrix[i + ][j + ] == ) surround[i + ][j + ]++;
if (matrix[i + ][j] == ) surround[i + ][j + ]++;
if (matrix[i + ][j + ] == ) surround[i + ][j + ]++;
if (matrix[i + ][j + ] == ) surround[i + ][j + ]++;
}
}
//Rules
for (i = ; i < height; i++) {
for (j = ; j < width; j++) {
if (surround[i + ][j + ] >= UPPER_LIMIT) matrix[i + ][j + ] = ;
if (surround[i + ][j + ] <= BOTTOM_LIMIT) matrix[i + ][j + ] = ;
if (surround[i + ][j + ] == REBIRTH_NUM) matrix[i + ][j + ] = ;
}
}
generation++;
}
void Definer() {
int i, j, k;
cout << "Please insert three value to define the rules: (Defaul Configuration:1 4 3)" << endl
<< "BOTTOM_LIMIT UPPER_LIMIT REBIRTH_NUM" << endl;
inputrule: cout << ">> "; cin >> i >> j >> k;
if (cin.fail() || i >= || j >= || k >= || i < || j < || k < ) {
cout << "Invalid input, please input three positive integers smaller than 8." << endl;
cin.clear();
while (cin.get() != '\n');
goto inputrule;
}
else {
BOTTOM_LIMIT = i;
UPPER_LIMIT = j;
REBIRTH_NUM = k;
printf("Rules have been defined to %d %d %d.\n", i, j, k);
}
}
};
int main()
{
LifeMap Map;
//These variables are used for manipunating.
int X, Y;
//these two labels are used for jumping for input that's too large and the reset command.
start: Map.instructor(FIRST_INTRODUCTION);
input: cin >> X >> Y;
while (cin.fail()) {
cout << "Unvalid input, please try again. Pleas type two integers." << endl;
cin.clear();
while (cin.get() != '\n') continue;
cin >> X >> Y;
}
while (X >= || Y >= ) {
cout << "Too long." << endl;
cin.clear();
goto input;
}
Map.instructor(MANIPUNATE_INSTRUCTION);
cout << "This is all the cells you have." << endl;
Map.initialize(X, Y);
Map.printer(NO_GENERATION_INFO);
cin.clear();
while (cin.get() != '\n') continue; // Clear datas in the cache.
char command;
while ((command = toupper(cin.get())) != 'Q') {
switch (command) {
case 'L':
cin >> X >> Y;
if (cin.fail()) {
cout << "Unvalid input, please try again." << endl;
cin.clear();
while (cin.get() != '\n') continue;
}
else
Map.SetLiving(X, Y);
break;
case 'D':
cin >> X >> Y;
if (cin.fail()) {
cout << "Unvalid input, please try again." << endl;
cin.clear();
while (cin.get() != '\n') continue;
}
else
Map.SetDying(X, Y);
break;
case 'P':
Map.printer(WITH_GENERATION_INFO);
break;
case 'N':
//gens mens the number of generations to evolve
//interval means the interval times between two evolutions
int i, gens, interval;
if (cin.get() != '\n') {
cin >> gens;
if (cin.get() == '\n') interval = ;
else cin >> interval;
if (gens <= || interval < ) {
cout << "Unvalid input, please enter positive integers." << endl;
cin.clear();
while (cin.get() != '\n') continue;
}
else {
for (i = ; i < gens; i++) {
system("cls");
Map.instructor(MANIPUNATE_INSTRUCTION);
Map.Next();
Map.printer(WITH_GENERATION_INFO);
Sleep(interval);
}
}
}
else {
system("cls");
Map.instructor(MANIPUNATE_INSTRUCTION);
Map.Next();
Map.printer(WITH_GENERATION_INFO);
}
break;
case 'R':
system("cls");
goto start;
break;
case '!':
Map.Radomlize();
cout << "OK, now it's just chaos." << endl;
Map.printer(WITH_GENERATION_INFO);
break;
case 'X':
Map.Definer();
case '\n': break;
case ' ': break;
default:
cout << "Unknown Command:(" << endl;
//while (cin.get() != '\n') continue;
}
}
cout << "See you:)\n\n";
system("pause");
return ;
}

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/

最新文章

  1. SQL Server 2008中的代码安全&lt;转&gt;
  2. 合并多个工作薄workbooks到一个工作薄workbook
  3. [转载]Matlab之静态文本多行输出
  4. mysql的source命令
  5. javascript实现非递归--归并排序
  6. Android Broadcast Receiver
  7. C - The Hardest Problem Ever
  8. c++数组操作
  9. python自学笔记(一)简单了解python
  10. 使用javaDate类代数据仓库维度表
  11. 从Visual Studio看微软20年技术变迁
  12. 201521123062《Java程序设计》第7周学习总结
  13. Python程序练习4--模拟员工信息数据库操作
  14. sigsuspend()阻塞:异步信号SIGIO为什么会被截胡?
  15. Windows 10中设置自动登录
  16. Ubuntu 16.04 源添加
  17. SQLServer2008 导出数据库表结构和数据
  18. 1.2OpenCV如何扫描图像,利用查找表和计时
  19. 【LeetCode】203. Remove Linked List Elements
  20. nfs只能挂载为nobody的解决方法

热门文章

  1. NDK开发之&lt;cpu-features.h模块功能&gt;
  2. PHP 错误与异常的日志记录
  3. 奇异值分解SVD
  4. 实战:CentOS 7.2 / Zabbix3.4安装graphtrees
  5. 在 mac osx 上安装OpenOffice并以服务的方式启动
  6. DBCP + C3P0 连接池
  7. 初识JS之数据类型
  8. Android--MediaPlayer(实现列表选歌,上一首,下一首,清空播放列表,搜索本地音乐文件)
  9. mysqldump免密备份方法
  10. PHP RabbitMQ 教程(三)