① 请高手用C++编写程序—生命游戏
#include<iostream>
usingnamespacestd;
#include<time.h>
#defineM70
#defineN20
voidmShow(inta[N+2][M+2])
{inti,j;
for(i=0;i<N;i++,cout<<endl)
for(j=0;j<M;j++)
if(a[i+1][j+1])cout<<'*';
elsecout<<'.';
//cout<<(a[i+1][j+1])?('*'):('');
}
intmJge(inta[N+2][M+2])
{inti,j,k,s,*p[9],b[N][M];
for(i=0;i<N;i++)
{
p[0]=p[4]=p[5]=&a[i+1][1];p[4]--;p[5]++;//123
p[1]=p[2]=p[3]=p[0]-M-2;p[1]--;p[3]++;//405
p[6]=p[7]=p[8]=p[0]+M+2;p[6]--;p[8]++;//678
for(j=0;j<M;j++)
{for(k=1,s=0;k<9;k++)s+=(*p[k]);
b[i][j]=*p[0];
if(s>=3)b[i][j]=1;
elseif(s<2)b[i][j]=0;
for(k=0;k<9;k++)p[k]++;
}
}
for(i=0,s=1;i<N;i++)for(j=0;j<M;j++){a[i+1][j+1]=b[i][j];if(b[i][j]==0)s=0;}
returns;
}
voidmain()
{
inta[N+2][M+2],b[N][M],*p[9];
intt,i,j,k;
for(i=0;i<N+2;i++)for(j=0;j<M+2;j++)a[i][j]=0;
srand((unsignedint)time(NULL));
for(i=0;i<N;i++)for(j=0;j<M;j++){k=rand()%100;a[i+1][j+1]=(k>=77)?(1):(0);}
cout<<"--------T=0--------"<<endl;mShow(a);
k=0;t=0;
while(!k)
{k=mJge(a);t++;
cout<<"--------T="<<t<<"--------"<<endl;mShow(a);
}
}
a数组比实际要的数组大一圈,大出来的一圈永恒等于0,作为边界,省得计算8连通数据时数组越界
b数组用于计算本次的结果,计算完成后复制、覆盖a数组中间部分作为结果
主程序做直到所有空间都被活细胞占满情况停止
以下是设置M=10,N=5的测试部分结果
② 求C语言命令行程序的“生命游戏”代码
I don't know的这个答案在网上随处可见,而且并不符合楼主的要求。
这个程序并不复杂,用1个2维数组来保存列表的信息,用2个循环嵌套来遍历数组中的每个元素,然后计算每个元素周围共有多少个'*',并根据规则为这个元素重新赋值。计算每个元素周围'*'的数量我是用2个循环嵌套来实现的,因为不象I don't know给出的程序那样边缘的元素不参与变化,所以需要判断是否会超出范围。
#include <stdio.h>
void input(char [][21],int,int);
void output(char [][21],int);
int trans(char [][21],int,int);
int main()
{
int row,col,ret,i;
char tab[20][21];
for(;;)
{
printf("输入行数和列数(行,列):");
ret=scanf("%d,%d",&row,&col);
if(ret==2 && (9<=row && row<=20) && (9<=col && col<=20))
break;
else
printf("输入错误!请重新输入!\n");
fflush(stdin);
}
input(tab,row,col);
for(i=0;i<10;i++)
{
if(trans(tab,row,col))
output(tab,row);
else
break;
}
return 0;
}
void input(char tab[][21],int row,int col)
{
int i,j,c;
for(c=0;c!=col;)
{
printf("输入列表:\n");
for(i=0;i<row;i++)
{
scanf("%s",tab[i]);
for(c=j=0;tab[i][j];j++)
{
if(tab[i][j]=='*' || tab[i][j]=='.')
c++;
else
break;
}
if(c!=col)
{
printf("输入错误!请重新输入!\n");
break;
}
}
fflush(stdin);
}
}
void output(char tab[][21],int row)
{
int i;
printf("输出列表:\n");
for(i=0;i<row;i++)
printf("%s\n",tab[i]);
}
int trans(char tab[][21],int row,int col)
{
int i,j,x,y,c,change=0;
char t[20][20];
for(i=0;i<row;i++)
{
for(j=0;j<col;j++)
{
for(c=0,x=i-1;x<=i+1;x++)
{
if(x<0 || x>=row)
continue;
for(y=j-1;y<=j+1;y++)
{
if(y<0 || y>=col || (x==i && y==j))
continue;
if(tab[x][y]=='*')
c++;
}
}
t[i][j]=(c==3 || tab[i][j]=='*' && c==2)?'*':'.';
if(tab[i][j]!=t[i][j])
change=1;
}
}
for(i=0;i<row;i++)
for(j=0;j<col;j++)
tab[i][j]=t[i][j];
return change;
}
③ Matlab中生命游戏代码每一行的注释
clc
clearall
closeall
m=30;n=30;p=.7;h=100;
%%
%生成30*30矩阵a,a的值根据随机数是否大于阈值0.7决定为1或0。
forx=1:m
fory=1:n
r=rand(1);%rand产生的是0到1(不包括1)的随机数。
ifr>p
a(x,y)=1;
elsea(x,y)=0;
end
end
end
%%
forx=1:m
fory=1:n
ifa(x,y)==1
fx=[x-1,x-1,x,x];
fy=[y-1,y,y,y-1];
fill(fx,fy,'g');
%fill将点[x1,y1],[x2,y2],[x3,y3],[x4,y4]按序连线,后形成的图像进行填充,参数‘g’表示绿色。
%[x1,y1],[x2,y2],[x3,y3],[x4,y4]对应写成[x1x2x3x4][y1y2y3y4],holdon表示画在一幅图上。
holdon
else
end
end
end
%即如果a(1,1)值为1,就在图像上在(1,1)点左下方画一个单位为1绿色的正方形。
%这一块可以不要,因为画图后被黑底覆盖。
%%
fork=1:h%运行100次
fx=[0,m,m,0];fy=[0,0,n,n];fill(fx,fy,'k'),holdon%画一个30*30黑底
forx=2:m-1
fory=2:n-1
b(x,y)=a(x-1,y-1)+a(x-1,y)+a(x-1,y+1)+a(x,y-1)+a(x,y+1)+a(x+1,y-1)+a(x+1,y)+a(x+1,y+1);
%根据生命游戏规,取矩阵a元素(x,y)周围八个元素值的和,因为最外边一圈元素周围没有八个相邻元素,
%所以不考虑,x、y范围2:m-1、2:n-1。
ifb(x,y)==2,c(x,y)=a(x,y);
%如果(x,y)周围存在2个1,即游戏意义2个活细胞,则这个细胞下一刻生死与原来生死有关。
elseifb(x,y)==3,c(x,y)=1;
%如果(x,y)周围存在3个1,即游戏意义2个活细胞,则这个细胞下一刻必存活(这里我假设1是存活)。
elsec(x,y)=0;
%如果(x,y)周围存在活细胞不是这两个值,即太多或太少,则这个细胞下一刻必死亡(这里我假设0是死亡)。
end
end
end
%%
c(1:m,1)=a(1:m,1);
c(1:m,n)=a(1:m,n);%加上两侧的两列
c(1,1:n)=a(1,1:n);%此处我感觉还应该加上最上最下两行,原程序没有。否则缺少的部分值为零,显示一直为黑。
c(m,1:n)=a(m,1:n);%注意矩阵表示与画图等于进行了矩阵的转置,缺少矩阵上下两行则左右两侧显示为黑。
forx=1:m
fory=1:n
ifc(x,y)==1
fx=[x-1,x-1,x,x];fy=[y-1,y,y,y-1];fill(fx,fy,'g'),holdon
else
end
end
end
%画出c,同上画a
pause(.05)%暂停0.05秒,观察变化过程
a=c;%将c赋值给a,即将此时的c当作前一时刻a,继续循环画图
end
%这个过程就是先生成一个随机30*30矩阵a,对a矩阵中间29*29部分根据生命游戏规则进行运算并显示,循环100次。
%可以发现最外边一圈图形是不变的。
④ 如何用c语言编生命游戏程序
写了这么多,记得追点分啊~~~~~`
这个问题分解为两部分
1、用什么方式表示某时刻有哪些细胞是活的
一种简单的想法是用一个二位数组将某时刻所有的细胞的状态都记录下来,不过这样的内存开销太大,同时又给细胞网格设定了界限,而且效率也并不高
比较好的做法是用一个线形表int list[][2]来记录某时刻的所有的活细胞的坐标,同时用一个整数int n记录当前的活细胞数量
2、如何从某时刻的状态推导出下一时刻有哪些细胞为活的
根据规则,显然,某时刻某个细胞是否活着完全取决于前一时刻周围有多少活着的细胞,以及该时刻该细胞是否活着
因此,推导下一时刻状态时,根据当前list中的活细胞,可以得到该时刻有哪些细胞是与活细胞相临的,进而得知这些细胞在该时刻与多少个活细胞相临,于是可以知道下一时刻有哪些细胞是活的
具体实现时,需要一个能够储存坐标并给每个坐标附带了一个计数器(记录该坐标的细胞与多少个活细胞相临)和一个标志(0或1,表示当前该坐标的细胞是活是死)的容器,假设为T,容器T的功能是检查某个坐标是否在其中,以及向其中添加带有某个标志某个坐标并将该坐标的计数器清零,以及将某个坐标的计数器累进一
比如,假设已经定义了
struct Container
{
...
};//容器类型
void Clear(Container *T);//清空容器T
int Exist(Container *T,int x,int y);//返回坐标(x,y)是否存在于T中
void Insert(Container *T,int x,int y,int flag);//将标志为flag的坐标(x,y)加入T
void Add(Container *T,int x,int y);//将坐标(x,y)的计数器累加
void Promote(Container *T,int *n,int list[][2]);//将容器中所有计数器值为3的坐标以及所有计数器为2并且标志为1的坐标添加到list中,并将其个数记录于n
此外,为了方便找出某个坐标的所有相邻坐标,设置以下方向常量
const int dir[8][2]={{0,1},{0,-1},{1,0},{-1,0},{1,1},{-1,1},{1,-1},{-1,-1}};
那么,从某时刻状态生成下一时刻状态的主要代码如下
...
Container T;
int i,j;
...
Clear(&T);
for (i=0;i<n;i++) Insert(&T,list[i][0],list[i][1],1);
for (i=0;i<n;i++)
for (j=0;j<8;j++)
{
int x,y;
x=list[i][0]+dir[j][0];
y=list[i][1]+dir[j][1];
if (!Exist(&T,x,y)) Insert(&T,x,y,0);
Add(&T,x,y);
}
Promote(&T,&n,list);
...
关于容器T如何实现,一种简单的思路是用线形表并将元素有序记录,不过这样的查找/插入效率难以兼顾
用哈希表的话,最后的Promote很难实现
块状链表可以兼顾查找与插入的效率,但是写起来太恶心,效率也不是特别高
个人认为,最佳的解决方案是用平衡二叉搜索树,常见的AVL树或者红黑树什么的,不过写起来也太麻烦。
这里强烈推荐Size Balanced Tree,由中国一位现在读高二的高中生所发明,原理清晰,效率高,实现简单