细胞自动机(又称元胞自动机),名字虽然很深奥,但是它的行为却是非常美妙的。所有这些怎样实现的呢?我们可以把计算机中的宇宙想象成是一堆方格子构成的封闭空间,尺寸为N的空间就有N*N个格子。而每一个格子都可以看成是一个生命体,每个生命都有生和死两种状态,如果该格子生就显示蓝色,死则显示白色。每一个格子旁边都有邻居格子存在,如果我们把3*3的9个格子构成的正方形看成一个基本单位的话,那么这个正方形中心的格子的邻居就是它旁边的8个格子。
每个格子的生死遵循下面的原则:
1. 如果一个细胞周围有3个细胞为生(一个细胞周围共有8个细胞),则该细胞为生(即该细胞若原先为死,则转为生,若原先为生,则保持不变) 。
2. 如果一个细胞周围有2个细胞为生,则该细胞的生死状态保持不变;
3. 在其它情况下,该细胞为死(即该细胞若原先为生,则转为死,若原先为死,则保持不变)
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
const int MAX_ROW = 15;
const int MAX_COL = 20;
struct Unit
{
bool alive;
int neighbor;
};
class Life
{
public:
Life();
void execute();
void initialize();
private:
Unit unit[MAX_ROW+2][MAX_COL+2];
int generation;
void inputFromStrings();
void inputFromKeyboard();
void inputFromFile();
int choose();
void show();
void live();
void countNeighbor();
void empty();
void append(bool append = true);
void output();
};
Life::Life()
{
generation = 1;
empty();
}
void Life::append(bool append)
{
int i, j;
if (append)
cout << "请输入增加活单元的坐标:";
else
cout << "请输入减少活单元的坐标:";
while (!(cin >> i >> j) || i < 1 || j < 1 || i > MAX_ROW || j > MAX_COL)
{
cout << "输入有误,请重新输入:";
cin.clear();
cin.ignore(100, '\n');
}
unit[i][j].alive = append;
}
void Life::empty()
{
for (int i = 0; i < MAX_ROW + 2; i++)
{
for (int j = 0; j < MAX_COL + 2; j++)
{
unit[i][j].alive = false;
unit[i][j].neighbor = 0;
}
}
}
void Life::inputFromKeyboard()
{
int i, j;
bool valid;
cout << "请依次输入活单元坐标:(输入-1 -1表示结束)";
while (1)
{
valid = bool(cin >> i >> j);
if (valid && i == -1 && j == -1)
break;
else if (!valid || i < 1 || j < 1 || i > MAX_ROW || j > MAX_ROW)
{
cout << "您的输入有误,请重新输入:";
cin.clear();
cin.ignore(100, '\n');
}
else
{
unit[i][j].alive = true;
cout << "(" << i << "," << j << ")变为活细胞!" << endl;
}
}
}
void Life::inputFromStrings()
{
string line;
cout << "请输入若干行字符串,空格和x分别代表死单元和活单元(直接按回车结束):" << endl;
cin.ignore(100, '\n');
int i = 1, size;
do
{
cout << "请输入第" << i << "行:" << endl;
getline(cin, line);
size = line.size();
if (size > 0)
{
for (int j = 0; j < size; j++)
{
if ((line[j] != ' ' && line[j] != 'x') || j+1 > MAX_COL)
{
cout << "您的输入有误,请重新输入:" << endl;
i--;
break;
}
else
{
unit[i][j].alive = line[j] == 'x';
}
}
i++;
}
} while (size > 0 && i <= MAX_ROW);
}
void Life::inputFromFile()
{
string line;
char fileName[20];
int i;
bool valid;
ifstream fileIn;
cout << "请输入文件名:";
cin.ignore(100, '\n');
do
{
cin.getline(fileName, 20);
fileIn.open(fileName);
if (fileIn.fail())
{
cout << "文件打开失败!请重新输入文件名:";
valid = false;
}
else
{
i = 1;
empty();
valid = true;
while (i <= MAX_ROW && getline(fileIn, line))
{
for (int j = 0; j < line.size(); j++)
{
if (j+1 > MAX_COL || (line[j] != ' ' && line[j] != 'x'))
{
valid = false;
break;
}
else
unit[i][j+1].alive = line[j] == 'x';
if (!valid) break;
}
if (!valid) break;
i++;
}
if (!valid)
cout << "文件内容不正确,请重新输入文件名:";
fileIn.close();
}
} while (!valid);
}
void Life::show()
{
system("cls");
cout << "第" << generation << "代:" << endl << endl;
for (int i = 1; i <= MAX_ROW; i++)
{
for (int j = 1; j <= MAX_COL; j++)
{
if (unit[i][j].alive)
cout << "x";
else
cout << " ";
}
cout << endl;
}
}
void Life::initialize()
{
int choice;
cout << "请选择读入数据的方式:" << endl;
cout << "<1> 从键盘输入活单元坐标,以-1,-1结束" << endl;
cout << "<2> 从键盘读入若干行字符串,空格和x分别代表死单元和活单元" << endl;
cout << "<3> 从文件读入若干行字符串,空格和x分别代表死单元和活单元" << endl << endl;
cout << "请选择:";
while (!(cin >> choice) || choice < 1 || choice > 3)
{
cout << "您的输入有误,请重新输入:";
cin.clear();
cin.ignore(100, '\n');
}
switch (choice)
{
case 1:
inputFromKeyboard();
break;
case 2:
inputFromStrings();
break;
case 3:
inputFromFile();
break;
}
show();
}
void Life::execute()
{
bool end = false;
do
{
show();
switch (choose())
{
case 1:
live();
break;
case 2:
output();
break;
case 3:
append();
break;
case 4:
append(false);
break;
case 5:
end = true;
break;
}
}
while (!end);
}
int Life::choose()
{
cout << "请选择一项:" << endl;
cout << "<1> 查看下一代" << endl;
cout << "<2> 将当前代保存到文件" << endl;
cout << "<3> 增加一个活单元" << endl;
cout << "<4> 减少一个活单元" << endl;
cout << "<5> 结束" << endl << endl;
cout << "请选择:";
int choice;
while (!(cin >> choice) || choice < 1 || choice > 5)
{
cout << "您的输入有误!请重新输入:";
cin.clear();
cin.ignore(100, '\n');
}
return choice;
}
void Life::live()
{
countNeighbor();
bool alive;
int neighbor;
generation++;
for (int i = 1; i <= MAX_ROW; i++)
for (int j = 1; j <= MAX_COL; j++)
{
neighbor = unit[i][j].neighbor;
alive = unit[i][j].alive;
if (alive && (neighbor == 0 || neighbor == 1 || neighbor >= 4))
unit[i][j].alive = false;
else if (!alive && neighbor == 3)
unit[i][j].alive = true;
}
}
void Life::countNeighbor()
{
int sum;
for (int i = 1; i <= MAX_ROW; i++)
for (int j = 1; j <= MAX_COL; j++)
{
sum = -unit[i][j].alive;
for (int ii = i - 1; ii <= i + 1; ii++)
for (int jj = j - 1; jj <= j + 1; jj++)
sum += unit[ii][jj].alive;
unit[i][j].neighbor = sum;
}
}
void Life::output()
{
cout << "请输入文件名,文件内原始内容会被清空:";
char fileName[20];
ofstream fileOut;
cin.ignore(100, '\n');
while (1)
{
cin.getline(fileName, 20);
fileOut.open(fileName, ios_base::trunc);
if (fileOut.fail())
{
cout << "文件打开失败!请重新输入文件名:";
}
else
{
for (int i = 1; i <= MAX_ROW; i++)
{
for (int j = 1; j <= MAX_COL; j++)
{
if (unit[i][j].alive)
fileOut << "x";
else
fileOut << " ";
}
fileOut << endl;
}
fileOut.close();
break;
}
}
}
int main()
{
Life life;
life.initialize();
life.execute();
return 0;
}