天天看點

生命遊戲背景要求代碼線上體驗

文章目錄

  • 背景
  • 要求
  • 代碼
    • 順序代碼
    • 并行代碼
  • 線上體驗

背景

生命遊戲中,對于任意細胞,規則如下:

  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是一個牛批的國外網站,可以線上感受一下生命遊戲。