项目分享:C语言并行实现丨元胞自动机生命游戏

Posted 一起学编程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了项目分享:C语言并行实现丨元胞自动机生命游戏相关的知识,希望对你有一定的参考价值。

简介

细胞自动机(又称元胞自动机),名字虽然很深奥,但是它的行为却是非常美妙的。所有这些怎样实现的呢?我们可以把计算机中的宇宙想象成是一堆方格子构成的封闭空间,尺寸为N的空间就有NN个格子。而每一个格子都可以看成是一个生命体,每个生命都有生和死两种状态,如果该格子生就显示蓝色,死则显示白色。每一个格子旁边都有邻居格子存在,如果我们把33的9个格子构成的正方形看成一个基本单位的话,那么这个正方形中心的格子的邻居就是它旁边的8个格子。

每个格子的生死遵循下面的原则:

1. 如果一个细胞周围有3个细胞为生(一个细胞周围共有8个细胞),则该细胞为生(即该细胞若原先为死,则转为生,若原先为生,则保持不变) 。

2. 如果一个细胞周围有2个细胞为生,则该细胞的生死状态保持不变;

3. 在其它情况下,该细胞为死(即该细胞若原先为生,则转为死,若原先为死,则保持不变)

实现思路

将全局矩阵分解为大小相等的(工作)块,这样我们就可以实现生命的游戏。

初始化:从文件中读取数据:一个包含游戏初始状态的m×n矩阵。

为了与其他处理器通信,我设置了一个局部矩阵和一个全局矩阵。局部矩阵是一种混合状态。对于处理器0,它可以从局部矩阵中获得全局矩阵。

MPI并行实现

#include <stdio.h>
#include <string.h>
#include "mpi.h"
#include <stdlib.h>


static int MAX_M;
static int MAX_N;
static int epoch;
static int DEAD=0;
static int ALIVE=1;

double exe_time;
int size, myid, s, ver, row, col, dir;

int *local_matrix = NULL;
int *tmpmatrix = NULL;
int *global_matrix = NULL;
int *newglobal_matrix = NULL;
MPI_Request requests[4];
MPI_Status status[4];


FILE * matrix;

void display(int *local_matrix)
    int i, j;
    printf("%10c", ' ');
    printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$\\n");
    for (i = 0; i < MAX_M; i++)
        printf("\\n%10c", ' ');
        for (j = 0; j < MAX_N; j++)
            if (local_matrix[i * MAX_N + j] == ALIVE)
                printf("+");
            else
                printf("-");
    
    printf("\\n%10c\\n", ' ');



int adj8(int neighbor, int row, int col)
    int res;
    if(neighbor == 2)
        return local_matrix[row * MAX_N + col];
    else if(neighbor == 3)
        return ALIVE;
    else
        return DEAD;
    



int main(int argc,char *argv[])
    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);
    ver = MAX_M / size;

    epoch= atoi(argv[1]);
    MAX_M= atoi(argv[2]);
    MAX_N= atoi(argv[3]);

    local_matrix = (int*)malloc(sizeof(int) * (ver+2) * MAX_N);
    tmpmatrix = (int*)malloc(sizeof(int) * (ver+2) * MAX_N);
    for (row = 0; row < ver+2; row++) 
        for (col = 0; col < MAX_N; col++) 
            local_matrix[row*MAX_N+col] = DEAD;
            tmpmatrix[row*MAX_N+col] = DEAD;
        
    
    //Initialization
    if (myid == 0) 
        int i;
        global_matrix = (int*)malloc(sizeof(int) * MAX_M * MAX_N);
        newglobal_matrix = (int*)malloc(sizeof(int) * MAX_M * MAX_N);

        if((matrix = fopen("matrix.txt","r"))==NULL)
            printf("the file can not open.");
            return -1;
        

        for(row = 0; row < MAX_M; row++)
            for(col = 0; col < MAX_N; col++)
                fscanf(matrix,"%d ", &global_matrix[row*MAX_N + col]);
            
            fscanf(matrix,"\\n");
        

        memcpy(&local_matrix[MAX_N], &global_matrix[0], ver * MAX_N * sizeof(int));
        for (dir = 1; dir < size; dir++) 
            MPI_Send(&global_matrix[dir*ver*MAX_N], ver * MAX_N, MPI_INT, dir, 1, MPI_COMM_WORLD);
        

        display(global_matrix);
     else 
        //For each processor, there is a local matrix.
        MPI_Recv(&local_matrix[MAX_N], ver * MAX_N, MPI_INT, 0, 1, MPI_COMM_WORLD, status);
    


    exe_time = -MPI_Wtime();


    for (int count=0; count<epoch;count++)
        int req_id = 0;
        if (myid == 0) 
            MPI_Isend(&local_matrix[(ver)*MAX_N], MAX_N, MPI_INT, myid + 1, 1, MPI_COMM_WORLD, &requests[req_id++]);
            MPI_Irecv(&local_matrix[(ver+1)*MAX_N], MAX_N, MPI_INT, myid + 1, 1, MPI_COMM_WORLD, &requests[req_id++]);
            printf("\\n");
            display(local_matrix);
         else 
            MPI_Irecv(local_matrix, MAX_N, MPI_INT, myid - 1, 1, MPI_COMM_WORLD, &requests[req_id++]);
            MPI_Isend(&local_matrix[(ver)*MAX_N], MAX_N, MPI_INT, myid + 1, 1, MPI_COMM_WORLD, &requests[req_id++]);
            MPI_Irecv(&local_matrix[(ver+1)*MAX_N], MAX_N, MPI_INT, myid + 1, 1, MPI_COMM_WORLD, &requests[req_id++]);
            MPI_Isend(&local_matrix[MAX_N], MAX_N, MPI_INT, myid - 1, 1, MPI_COMM_WORLD, &requests[req_id++]);
        
        MPI_Waitall(req_id, requests, status);

        for (row = 1; row < ver+1; row+=1)
            for (col = 0; col < MAX_N; col++)
                int neighbor = 0, c, r;
                for (r = row - 1; r <= row + 1; r++)
                    for (c = col - 1; c <= col + 1; c++)
                        if (c < 0 || c >= MAX_N) continue;
                        if (local_matrix[r * MAX_N + c] == ALIVE) neighbor++;
                    
                if (local_matrix[row * MAX_N + col] == ALIVE)
                    neighbor--;
                tmpmatrix[row * MAX_N + col] = adj8(neighbor, row, col);
            
        

        for (row = 1; row < ver+1; row+=1)
            for (col = 0; col < MAX_N; col++)
                local_matrix[row * MAX_N + col] = tmpmatrix[row * MAX_N + col];
            
        
    
    if (myid == 0) 
        exe_time += MPI_Wtime();
        printf("Time: %lf \\n", exe_time);
        memcpy(global_matrix, &local_matrix[MAX_N], ver * MAX_N * sizeof(int));
        for (dir = 1; dir < size; dir++) 
            MPI_Recv(&global_matrix[dir*ver*MAX_N], ver*MAX_N, MPI_INT, dir, 1, MPI_COMM_WORLD, status);
        
        printf("Last Status:\\n");
        display(global_matrix);
    
    else 
        MPI_Send(&local_matrix[MAX_N], ver * MAX_N, MPI_INT, 0, 1, MPI_COMM_WORLD);
    
    MPI_Finalize();
    return 0;

输出示例

来源:OmegaXYZ丨xyjisaw

写在最后:对于准备学习C/C++编程的小伙伴,如果你想更好的提升你的编程核心能力(内功)不妨从现在开始!

C语言C++编程学习交流圈子,QQ群:739386924点击进入】微信公众号:C语言编程学习基地

整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)

欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!

C语言基础视频分享:

 

以上是关于项目分享:C语言并行实现丨元胞自动机生命游戏的主要内容,如果未能解决你的问题,请参考以下文章

元胞自动机基于matlab元胞自动机生命游戏含Matlab源码 655期

生命游戏的三种玩法

元胞自动机基于matlab元胞自动机双通道交通含Matlab源码 1657期

元胞自动机基于matlab元胞自动机双边教室疏散含Matlab源码 1208期

元胞自动机基于matlab元胞自动机单边教室疏散含Matlab源码 1207期

Python案例:协程实现康威生命游戏,元胞自动机