天天看点

生命游戏背景要求代码在线体验

文章目录

  • 背景
  • 要求
  • 代码
    • 顺序代码
    • 并行代码
  • 在线体验

背景

生命游戏中,对于任意细胞,规则如下:

  1. 每个细胞有两种状态-存活或死亡,每个细胞与以自身为中心的周围八个细胞产生互动。
  2. 当前细胞为存活状态时,当周围低于2个(不包含2个)存活细胞时, 该细胞变成死亡状态。(模拟生命数量稀少)
  3. 当前细胞为存活状态时,当周围有2个或3个存活细胞时, 该细胞保持原样。
  4. 当前细胞为存活状态时,当周围有3个以上的存活细胞时,该细胞变成死亡状态。(模拟生命数量过多)
  5. 当前细胞为死亡状态时,当周围有3个存活细胞时,该细胞变成存活状态。 (模拟繁殖)

本实验中,需要在一个平面上使用细胞自动机模型实现生命游戏模拟。可以把最初的细胞结构定义为种子,当所有在种子中的细胞同时被以上规则处理后, 可以得到第一代细胞图。按规则继续处理当前的细胞图,可以得到下一代的细胞图,周而复始。

要求

  1. 设定平面大小至少为2020(WidthHeight),具体数值可以自行设定。
  2. 实现顺序代码后,使用MPI实现一个简单的并行情况代码。

代码

顺序代码

#include <stdio.h>  
#include <stdlib.h>  
#include <time.h>  
  
#define N 42  
#define M 72  
//平面大小40×70,周围一圈作为边界
char cell = '@';  //细胞形状
  
void init(char cells[N][M]);  
void show(char cells[N][M]);  
void evolve(char cells[N][M]);  
int around(char cells[N][M], int x, int y);  
  
int main(int argc, char *argv[])  
{  
    if(argc != 2)  
    {  //用户输入代数
        printf("Usage:%s number\n", argv[0]);   
        return 1;  
    }  
      
    char cells[N][M];  
    int i = 0, G=atoi(argv[1]);  
    init(cells);   
    show(cells);  
    while(i++ < G) {  
        sleep(1);  
        evolve(cells);  
        show(cells);  
        printf("\ngeneration %d\n",i);  
    }  
  
    return 0;  
}  
void init(char cells[N][M])  
{  //随机初始化培养皿
    int i,j;  
    srand(time(0));  
  
    for(i=0;i<N;i++)  
        for(j=0;j<M;j++)  
            if(rand()%2 || 0==i || 0==j   
                || N-1 == i || M-1 == j)  
                cells[i][j]=' ';  
            else  
                cells[i][j]=cell;  
}  
  
void show(char cells[N][M])  
{  
    int i,j;  
  
    system("clear");  
    for(i=0;i<N;i++) {  
        for(j=0;j<M;j++)  
            putchar(cells[i][j]);  
        putchar('\n');  
    }  
}  
void evolve(char cells[N][M])  
{  //细胞进化,实际平面要大一圈,作为培养皿壁,方便统一
    int i,j, lives;  
    char tmp[N][M];  
  
    for(i=1;i<N-1;i++) {  
        for(j=1;j<M-1;j++) {  
            lives = around(cells, i, j);  
            if(cell == cells[i][j]){  
                lives--;  
                if(lives < 2 || lives > 3)  
                    tmp[i][j]=' ';  
                else  
                    tmp[i][j]=cell;  
            }else if(lives == 3)  
                    tmp[i][j]=cell;  
                else  
                    tmp[i][j]=' ';  
        }  
    }  
    for(i=1;i<N-1;i++)   
        for(j=1;j<M-1;j++)   
            cells[i][j]=tmp[i][j];  
}  
int around(char cells[N][M], int x, int y)  
{  //一个细胞周围细胞个数
    int i,j,count=0;  
      
    for(i=x-1;i<x+2;i++)  
        for(j=y-1;j<y+2;j++)  
            if(cells[i][j]==cell)  
                count++;  
          
    return count;  
}  
           
生命游戏背景要求代码在线体验

并行代码

#include <stdio.h>  
#include <stdlib.h>  
#include "mpi.h"  
#include <time.h>  
  
#define N 42  
#define M 72  
#define G 30  
//代数为30
char cell = '@';  
  
void init(char cells[N][M]);  
void show(char cells[N][M]);  
void liner(char array[][M], char *line, int len, int check);  
void matrix(char array[][M], char *line, int len);  
void evolve(char cells[N][M], int n);  
int around(char cells[N][M], int x, int y);  
  
int main(int argc, char *argv[])  
{  
    MPI_Init(&argc, &argv);  
    MPI_Status status;  
    int rank, size;  
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);  
    MPI_Comm_size(MPI_COMM_WORLD, &size);  
    int i,g=0, step=(N-2)/(size-1), flag = (N-2)%(size-1);  
    char line[(step+2)*M];  
      
    if(!rank){  //主进程
        int from, length;  
        char cells[N][M];  
        if(flag){  
            from = size*step;  
            length = N-from;  
        }  
  
        init(cells);   
        show(cells);  
        while(g++ < G) {  
            sleep(1);  
            for(i=1;i<size;i++){  
                liner(&cells[(i-1)*step], line, step+2, 0);  
                MPI_Send(line, (step+2)*M, MPI_CHAR,   
                        i, 0, MPI_COMM_WORLD);  
            }  
            for(i=1; i<size; i++){  
                MPI_Recv(line, step*M, MPI_CHAR,   
                        i, 0, MPI_COMM_WORLD, &status);  
                matrix(&cells[(i-1)*step+1], line, step);  
            }  
            if(flag){  
                evolve(&cells[from], length);  
            }  
            show(cells);  
            printf("\ngeneration %d\n",g);  
        }  
    }else {  //子进程
        char buf[step+2][M];  
        while(g++ < G) {  
            sleep(1);  
            MPI_Recv(line, (step+2)*M, MPI_CHAR,   
                    0, 0, MPI_COMM_WORLD, &status);  
            matrix(buf, line, step+2);  
            evolve(buf, step+2);  
            liner(buf, line, step+2, 1);  
            MPI_Send(line, step*M, MPI_CHAR,   
                    0, 0, MPI_COMM_WORLD);  
        }  
    }  
  
    MPI_Finalize();  
    return 0;  
}  
void init(char cells[N][M])  
{  
    int i,j;  
    srand(time(0));  
  
    for(i=0;i<N;i++)  
        for(j=0;j<M;j++)  
            if(rand()%2 || 0==i || 0==j   
                || N-1 == i || M-1 == j)  
                cells[i][j]=' ';  
            else  
                cells[i][j]=cell;  
}  
  
void show(char cells[N][M])  
{  
    int i,j;  
  
    system("clear");  
    for(i=0;i<N;i++) {  
        printf("%d ",i);  
        for(j=0;j<M;j++)  
            putchar(cells[i][j]);  
        putchar('\n');  
    }  
}  
	void liner(char array[][M], char *line, int len, int check)  
	{  //将二维数组转换成一维数组
	    int i,j;  
	    for(i=0+check;i<len-check;i++){  
	        for(j=0;j<M;j++){  
	            *line++=array[i][j];  
	        }  
	    }  
	}  
	void matrix(char array[][M], char *line, int len)  
	{  //将一维数组转换成二维数组
	    int i,j;  
	    for(i=0;i<len;i++){  
	        for(j=0;j<M;j++){  
	            array[i][j]=*line++;  
	        }  
	    }  
	}  
	void evolve(char cells[N][M], int n)  
	{  
	    int i,j, lives;  
	    char tmp[n][M];  
	  
	    for(i=1;i<n-1;i++) {  
	        for(j=1;j<M-1;j++) {  
	            lives = around(cells, i, j);  
	            if(cell == cells[i][j]){  
	                lives--;  
	                if(lives < 2 || lives > 3)  
	                    tmp[i][j]=' ';  
	                else  
	                    tmp[i][j]=cell;  
	            }else if(lives == 3)  
	                    tmp[i][j]=cell;  
	                else  
	                    tmp[i][j]=' ';  
	        }  
	    }  
	    for(i=1;i<n-1;i++)   
	        for(j=1;j<M-1;j++)   
	            cells[i][j]=tmp[i][j];  
	}  
	int around(char cells[N][M], int x, int y)  
	{  
	    int i,j,count=0;  
	      
	    for(i=x-1;i<x+2;i++)  
	        for(j=y-1;j<y+2;j++)  
	            if(cells[i][j]==cell)  
	                count++;  
	          
	    return count;  
}  
           

数据划分方法如下:

生命游戏背景要求代码在线体验

上图以p=4为例,主进程将数组按行分为3部分,每一部分与相邻的部分有两行重叠,分发给子进程,子进程对数据处理的时候空出最外面的一圈,只计算里面的数据。处理完之后只将处理之后的里面的数据发送给主进程。

在线体验

John Conway’s Game of Life是一个牛批的国外网站,可以在线感受一下生命游戏。