项目分享: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语言基础视频分享:

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值