文章目錄
- 背景
- 要求
- 代碼
-
- 順序代碼
- 并行代碼
- 線上體驗
背景
生命遊戲中,對于任意細胞,規則如下:
- 每個細胞有兩種狀态-存活或死亡,每個細胞與以自身為中心的周圍八個細胞産生互動。
- 目前細胞為存活狀态時,當周圍低于2個(不包含2個)存活細胞時, 該細胞變成死亡狀态。(模拟生命數量稀少)
- 目前細胞為存活狀态時,當周圍有2個或3個存活細胞時, 該細胞保持原樣。
- 目前細胞為存活狀态時,當周圍有3個以上的存活細胞時,該細胞變成死亡狀态。(模拟生命數量過多)
- 目前細胞為死亡狀态時,當周圍有3個存活細胞時,該細胞變成存活狀态。 (模拟繁殖)
本實驗中,需要在一個平面上使用細胞自動機模型實作生命遊戲模拟。可以把最初的細胞結構定義為種子,當所有在種子中的細胞同時被以上規則處理後, 可以得到第一代細胞圖。按規則繼續處理目前的細胞圖,可以得到下一代的細胞圖,周而複始。
要求
- 設定平面大小至少為2020(WidthHeight),具體數值可以自行設定。
- 實作順序代碼後,使用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是一個牛批的國外網站,可以線上感受一下生命遊戲。