康威生命游戏
康威生命游戏(Game of Life)是由剑桥大学约翰·何顿·康威设计的计算机程序,图灵完备(Turing Completeness),是细胞自动机的先驱。
康威生命游戏规则
游戏开始时,每个细胞随机地设定为“生”或“死”之一的某个状态。然后,根据某种规则,计算出下一代每个细胞的状态,画出下一代细胞的生死分布图。
应该规定什么样的迭代规则呢?需要一个简单的,但又反映生命之间既协同又竞争的生存定律。为简单起见,最基本的考虑是假设每一个细胞都遵循完全一样的生存定律;再进一步,把细胞之间的相互影响只限制在最靠近该细胞的8个邻居中。
也就是说,每个细胞迭代后的状态由该细胞及周围8个细胞状态所决定。作了这些限制后,仍然还有很多方法来规定“生存定律”的具体细节。例如,在康威的生命游戏中,规定了如下生存定律。
(1)当前细胞为死亡状态时,当周围有3个存活细胞时,则迭代后该细胞变成存活状态(模拟繁殖);若原先为生,则保持不变。
(2)当前细胞为存活状态时,当周围的邻居细胞低于两个(不包含两个)存活时,该细胞变成死亡状态(模拟生命数量稀少)。
(3)当前细胞为存活状态时,当周围有两个或3个存活细胞时,该细胞保持原样。
(4)当前细胞为存活状态时,当周围有3个以上的存活细胞时,该细胞变成死亡状态(模拟生命数量过多)。
可以把最初的细胞结构定义为种子,当所有种子细胞按以上规则处理后,可以得到第1代细胞图。按规则继续处理当前的细胞图,可以得到下一代的细胞图,周而复始。
上面的生存定律当然可以任意改动,发明出不同的“生命游戏”。
C++实现
/*
代码由 优快云 千鱼干原创,转载请注明出处
*/
#include <iostream>
#include <windows.h>
#include <cstring>
#include <string.h>
#include <ctime>
using namespace std;
/*
注意:h (高)和 w (宽)需要根据控制台设置
使得生命状态图边界不超过控制台长宽。否则显示会出问题
*/
const int h = 55;
const int w = 95;
const string live = " ■";
/*
存活生命用实心方块表示,注意:
本程序运行于 Windows 11 的 Windows Terminal下
故方块前加了个空格以使显示效果整齐
*/
const string die = " "; // 死亡状态
// 设置当前生命状态图 surface 和下一新生命状态图 new_surface
int surface[h][w], new_surface[h][w];
// 设置生命状态图填充内容
void putVal(int val){
for(int i = 0; i < h; i++){
for(int j = 0; j < w; j++){
surface[i][j] = val;
new_surface[h][w] = val;
}
}
}
// 清空生命状态图
void clearSurface(){
putVal(0);
}
// 填满生命状态图
void fullSurface(){
putVal(1);
}
// 设置输出游标,只针对被修改的地方 (x, y) 输出
void updatePos(int x, int y) {
COORD pos = {y * 2, x};
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOut, pos);
printf("%s", (surface[x][y] != 0) ? live.c_str() : die.c_str());
}
// 展示生命状态图
void showSurface(){
for(int i = 0; i < h; i++){
for(int j = 0; j < w; j++){
printf("%s", (surface[i][j] != 0) ? live.c_str() : die.c_str());
}
printf("\n");
}
}
// 随机生成生命状态图,p 为初始存活概率
void randomSeed(int p){
clearSurface();
// 设置随机数种子
srand((unsigned int)time(NULL));
for(int i = 0; i < h; i++){
for(int j = 0; j < w; j++){
if((rand() % 100) <= p){
surface[i][j] = 1;
new_surface[h][w] = 1;
}
}
}
}
// 判断 (x, y) 附近的生命数量
int pdAround(int x, int y){
int x_sub = (x + h - 1) % h;
int y_sub = (y + w - 1) % w;
int x_plus = (x + 1) % h;
int y_plus = (y + 1) % w;
int lifes = (
(surface[x_sub][y_sub] == 1)
+ (surface[x_sub][y] == 1)
+ (surface[x_sub][y_plus] == 1)
+ (surface[x][y_plus] == 1)
+ (surface[x_plus][y_plus] == 1)
+ (surface[x_plus][y] == 1)
+ (surface[x_plus][y_sub] == 1)
+ (surface[x][y_sub] == 1)
);
return lifes;
}
// 设置位于 (x, y) 处生命的状态
void setState(int x, int y){
// 如果无生命
if(surface[x][y] == 0){
// 当周围生命数量为 3 时产生新生命(模拟繁殖)
if(pdAround(x, y) == 3){
new_surface[x][y] = 1;
return;
}
}else{
// 如果已存在生命,当周围生命数量低于 2 或大于 3 死亡,分别模拟生命数量稀少和生命数量过多
if((pdAround(x, y) < 2) || (pdAround(x, y) > 3)){
new_surface[x][y] = 0;
return;
}
}
}
// 刷新当前生命状态图为新生命状态图
void refreshSurface(){
for(int i = 0; i < h; i++){
for(int j = 0; j < w; j++){
if(surface[i][j] != new_surface[i][j]){
surface[i][j] = new_surface[i][j];
updatePos(i, j);
}
}
}
}
// 一次生命状态图模拟
void fun(){
for(int i = 0; i < h; i++){
for(int j = 0; j < w; j++){
setState(i, j);
}
}
refreshSurface();
}
int main() {
int p = 80;
cout << "输入初始存活概率(0~100,建议不要过高):___\b\b\b";
cin >> p;
system("cls");
system("color f0");
clearSurface(); // 清空生命状态图
randomSeed(p); // 随机产生生命状态图
showSurface(); // 输出初始生命状态图
Sleep(1000);
int j = 100;
while(true){
fun(); // 一次生命状态图模拟
}
return 0;
}
实现效果