⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sharkfish.cpp

📁 使用VC。NET2005并行实现著名的细胞自动机程序:生命游戏
💻 CPP
字号:
#include "SharkFish.h"
#include <malloc.h>

void SeaInit(Cell &matrix,int rows,int cols)   //随机初始化海域生物
{
	srand( (unsigned)time( NULL ) );   //设置随机种子
    system("cls");  //清空屏幕
	for(int i=0;i<rows;i++)
	{
		for(int j=0;j<cols;j++)
		{
            int RAND_SPAN=rand()%10;  //获得随机数
			if((RAND_SPAN>=0)&&(RAND_SPAN<5))  //如果随机数在范围一中
                (&matrix+(i*cols+j))->SetType(FISH_TYPE);  //设置细胞为小鱼类型
			else if((RAND_SPAN>=5)&&(RAND_SPAN<7))  //如果随机数在范围二中
                (&matrix+(i*cols+j))->SetType(SHARK_TYPE); //设置细胞为鲨鱼类型
			else                               //其余情况
                (&matrix+(i*cols+j))->SetType(EMPTY);   //设置细胞为空白区域
		}
	}
}

int RandEatDiretion(Cell &matrix,int rows,int cols,int i,int j)  //鲨鱼随机选择一条鱼吃
{
	int EatAble[4]={0,0,0,0}; //存储可能的所有方向
    int k=0;   //可以吃的鱼的数量
	srand( (unsigned)time( NULL ) );  //产生随机种子   
    if((&matrix+(i*cols+(j+1)%COLUMN))->GetType()==FISH_TYPE)  //右侧有鱼吃
	{
        EatAble[k]=RIGHT;  //存储方向
		k++; //可选择的鱼数量加一
	}
	if((&matrix+((i+1)%ROW*cols+j))->GetType()==FISH_TYPE)  //下侧有鱼吃
	{
        EatAble[k]=DOWN;
		k++;
	}
    if((&matrix+(i*cols+(j-1+COLUMN)%COLUMN))->GetType()==FISH_TYPE)  //左侧有鱼吃
	{
        EatAble[k]=LEFT;
		k++;
	}
    if((&matrix+((i-1+ROW)%ROW*cols+j))->GetType()==FISH_TYPE)  //上侧有鱼吃
	{
        EatAble[k]=UP;
		k++;
	}
	if(k!=0)  //有鱼可以选择吃
	{
		return EatAble[rand()%k];  //随机选择一条鱼吃
	}
	return NOTHING_TO_EAT;  //没有鱼吃
}

int RandMoveDiretion(Cell &matrix,int rows,int cols,int i,int j)  //随机选择一个方向移动
{
	int MoveAble[4]={0,0,0,0};  //存储可以移动的方向
    int k=0;  //可以选择的方向数量
	srand( (unsigned)time( NULL ) );   //产生随机种子   
    if((&matrix+(i*cols+(j+1)%COLUMN))->GetType()==EMPTY)   //右侧可以移动
	{
        MoveAble[k]=RIGHT;  //存储可移动的方向
		k++;  //可选择的数量加一
	}
	if((&matrix+((i+1)%ROW*cols+j))->GetType()==EMPTY)     //下侧可以 移动
	{
        MoveAble[k]=DOWN;
		k++;
	}
    if((&matrix+(i*cols+(j-1+COLUMN)%COLUMN))->GetType()==EMPTY)  //左侧可以移动
	{
        MoveAble[k]=LEFT;
		k++;
	}
    if((&matrix+((i-1+ROW)%ROW*cols+j))->GetType()==EMPTY)   //上侧可以移动
	{
        MoveAble[k]=UP;
		k++;
	}
	if(k!=0)   //有方向可以选择移动
	{
		return MoveAble[rand()%k];  //在可选择的范围内随机移动
	}
	return NOWHERE_TO_MOVE;  //没有空间可以移动
}

void EatFish(Cell &matrix,int rows,int cols,int i,int j,int EatDirection)  //鲨鱼吃小鱼
{
    if(EatDirection!=NOTHING_TO_EAT)   //有鱼可以选择吃
	{
        (&matrix+(i*cols+j))->ClearStarve();  //将鲨鱼的饥饿时间清空
		switch(EatDirection)  //查看所选择的小鱼在哪个方向
		{
		case RIGHT: //右侧
			*(&matrix+(i*cols+(j+1)%COLUMN))=*(&matrix+(i*cols+j));  //复制细胞数据到右侧的空间
			(&matrix+(i*cols+j))->Clear();  //清空原来鲨鱼的空间
			break;
		case DOWN:  //下侧
			*(&matrix+((i+1)%ROW*cols+j))=*(&matrix+(i*cols+j));
			(&matrix+(i*cols+j))->Clear();
			break; 
		case LEFT:  //左侧
			*(&matrix+(i*cols+(j-1+COLUMN)%COLUMN))=*(&matrix+(i*cols+j));
			(&matrix+(i*cols+j))->Clear();
			break;
		case UP:    //上侧
			*(&matrix+((i-1+ROW)%ROW*cols+j))=*(&matrix+(i*cols+j));
			(&matrix+(i*cols+j))->Clear();
			break;
		}
	}
	else   //鲨鱼没有鱼吃
	{
		(&matrix+(i*cols+j))->Starve();  //饥饿时间增加一
		if((&matrix+(i*cols+j))->GetStarvationTime()==SHARK_STARVE_SPAN)  //如果鲨鱼的饥饿时间到达生命极限
            (&matrix+(i*cols+j))->Clear();  //鲨鱼由于没有食物而被饿死
	}
}

void Move(Cell &matrix,int rows,int cols,int i,int j,int MoveDirection)  //细胞进行移动
{
    if(MoveDirection!=NOWHERE_TO_MOVE)  //有方向可以移动
	{
		switch(MoveDirection)  //查找所选的移动方向
		{
		case RIGHT:   //向右移动
			*(&matrix+(i*cols+(j+1)%COLUMN))=*(&matrix+(i*cols+j));  //把细胞数据复制到新位置
			break;
		case DOWN:    //向下移动
			*(&matrix+((i+1)%ROW*cols+j))=*(&matrix+(i*cols+j));
			break;
		case LEFT:    //向左移动
			*(&matrix+(i*cols+(j-1+COLUMN)%COLUMN))=*(&matrix+(i*cols+j));
			break;
		case UP:      //向上移动
			*(&matrix+((i-1+ROW)%ROW*cols+j))=*(&matrix+(i*cols+j));
			break;
		}
        if((&matrix+(i*cols+j))->GetType()==SHARK_TYPE)   //移动的是一条鲨鱼
		{
			if(((&matrix+(i*cols+j))->GetAge()!=0)&&(((&matrix+(i*cols+j))->GetAge()%SHARK_BORN_AGE)==0))
			{    //鲨鱼到了生育年龄
                (&matrix+(i*cols+j))->Clear();  //清空原来空间
                (&matrix+(i*cols+j))->SetType(SHARK_TYPE); //设置新的鲨鱼属性
			}
			else
			{    //如果没有到达生育年龄
				(&matrix+(i*cols+j))->Clear();  //清空原来的空间  
			}
		}
		else if((&matrix+(i*cols+j))->GetType()==FISH_TYPE)  //移动的是一条小鱼
		{
			if(((&matrix+(i*cols+j))->GetAge()!=0)&&(((&matrix+(i*cols+j))->GetAge()%FISH_BORN_AGE)==0))
			{    //小鱼到达生育年龄
                (&matrix+(i*cols+j))->Clear(); //清空原来的空间
                (&matrix+(i*cols+j))->SetType(FISH_TYPE);   //设置新的小鱼属性
			}
			else
			{    //如果没有到达生育年龄
				(&matrix+(i*cols+j))->Clear();  //清空原来的空间
			}
		}

	}
}


void OutPutSea(Cell &matrix,int rows,int cols)   //输出海域的状态
{
    /*	  //输出细胞状态
    for(int i=0;i<rows;i++)
	{
		for(int j=0;j<cols;j++)
		{
			(&matrix+(i*cols+j))->PrintCell();
		}
		cout<<endl;
	}
	*/
    
	for(int i=0;i<rows;i++)   //图形输出鲨鱼和小鱼的状态
	{
		for(int j=0;j<cols;j++)
		{
			if((&matrix+(i*cols+j))->GetType()==SHARK_TYPE)  //用 ■ 表示鲨鱼
			    cout<<"■";
			else if((&matrix+(i*cols+j))->GetType()==FISH_TYPE)  //用 ⊙ 表示小鱼
			    cout<<"⊙";
			else
				cout<<"  ";  //用空格表示空白区域
		}
		cout<<endl;
	}
}
int GetCellListLen(struct CellNode *ListHead)  //获得细胞链表的长度
{
	struct CellNode *p=ListHead;  //获得链表头
	int lenth=0;  //初始化长度
	while(p!=NULL)  //指针非空进行循环
	{   
		lenth++;    //长度加一
		p=p->next;  //链表指针向后移动
	}
	return lenth;   //返回链表长度
}

struct CellNode *InsertCellList(struct CellNode *ListHead,Cell* CellElem,int x,int y)  //将细胞随机插入链表
{
	struct CellNode *p=ListHead;  //获得链表头
	struct CellNode *s=NULL;      //定义TEMP节点指针
	int j=0;  //定义位置循环变量
	srand( (unsigned)time( NULL ) );  //设置随机种子   
	int index=rand()%GetCellListLen(ListHead);  //产生随机插入位置

	while(p&&j<index-1){p=p->next;++j;}  //查找随机插入位置

       s=(struct CellNode *)malloc(sizeof(CellNode));  //为TEMP节点分配空间
	   s->NodeElem=CellElem;   //为TEMP节点附值
	   s->x=x;
	   s->y=y;
	   s->next=p->next;  //将TEMP节点插入指定位置
	   p->next=s;

	return ListHead;  //返回细胞链表头
}

struct CellNode *CreatCellList(struct CellNode *ListHead,Cell &matrix,int rows,int cols,int TYPE)
{   //创建细胞链表
	ListHead=(struct CellNode *)malloc(sizeof(CellNode)); //产生表头节点空间
	ListHead->next=NULL;  

	for(int i=0;i<rows;i++)   //在海域内进行查找
	{
		for(int j=0;j<cols;j++)
		{
           if((&matrix+(i*cols+j))->GetType()==TYPE)  //在海域内查找指定细胞类型
		   {  
              ListHead=InsertCellList(ListHead,(&matrix+(i*cols+j)),i,j);  //将指定的类型细胞插入相应链表
		   }
		}
	}

	return ListHead;  //返回链表头
}

void PrintList(struct CellNode *ListHead)  //输出细胞链表的元素信息
{
	struct CellNode *p=ListHead->next;  //定义节点指针
	while(p!=NULL)  //顺链表循环
	{   //输出节点信息
		cout<<"{"<<p->NodeElem->GetType()<<","<<p->NodeElem->GetAge()<<","<<p->x<<","<<p->y<<"}"<<endl;
		p=p->next;  //向链表后步进
	}
}

struct CellNode *GetCell(struct CellNode *ListHead)  //获得链表头节点并在表中删除此节点
{
	struct CellNode *p=ListHead->next;  //定义节点指针

	if(p==NULL)  //如果指针空,则返回空指针
	{
		return NULL;
	}
	else     //若不空
	{
		ListHead->next=p->next;  //在节点中删除此节点
		return p;  //返回细胞节点
	}
}

void Action(struct CellNode* List,Cell &matrix,int rows,int cols,int TYPE)  //海洋生物的行动
{
	if(TYPE==SHARK_TYPE)  //如果是鲨鱼类型
	{
		struct CellNode* SharkNode=GetCell(List);  //获得第一个鲨鱼节点
	    while(SharkNode)  //当节点非空则进行循环
		{
			int i=SharkNode->x; //获得鲨鱼节点位置信息
			int j=SharkNode->y;
		    SharkNode->NodeElem->Grow();  //鲨鱼年龄增长一个时间单位
			if(SharkNode->NodeElem->GetAge()==SHARK_LIFE_SPAN)  //如果鲨鱼到达生命极限
               SharkNode->NodeElem->Clear();  //鲨鱼死亡
		    int EatDirection=RandEatDiretion(matrix,rows,cols,i,j);  //获得可以吃的鱼
            EatFish(matrix,rows,cols,i,j,EatDirection);  //吃所选择的鱼
            if(EatDirection==NOTHING_TO_EAT)  //如果没有鱼可以吃
			{
				int MoveDirection=RandMoveDiretion(matrix,rows,cols,i,j); //选择可以移动的方向
				if(NOWHERE_TO_MOVE!=MoveDirection)  //如果有空间进行移动
					Move(matrix,rows,cols,i,j,MoveDirection);  //鲨鱼按照所选方向移动
				else   //没有空间移动
				   SharkNode->NodeElem->Clear();  //鲨鱼由于密度太大而死
			}
			SharkNode=GetCell(List); //获得下一个细胞节点
		}
	}
	else if(TYPE==FISH_TYPE)  //如果是小鱼类型
	{
        struct CellNode* FishNode=GetCell(List);  //获得第一个小鱼节点信息
	    while(FishNode)    //当节点非空则进行循环
		{
			if(FishNode->NodeElem->GetType()==FISH_TYPE)  //《注意》原来存储的小鱼节点可能已经
			{                                 //被鲨鱼吃掉而换成了鲨鱼类型,这里处理没有改变的节点
				int i=FishNode->x;  //获得节点位置信息
				int j=FishNode->y;
				FishNode->NodeElem->Grow();  //小鱼年龄增加一个时间单位
				if(FishNode->NodeElem->GetAge()==FISH_LIFE_SPAN)  //如果小鱼到达生命极限
				   FishNode->NodeElem->Clear();  //小鱼死亡
				int MoveDirection=RandMoveDiretion(matrix,rows,cols,i,j);  //随机选择移动的方向
				if(NOWHERE_TO_MOVE!=MoveDirection)  //如果有空间可以移动
					Move(matrix,rows,cols,i,j,MoveDirection);  //移动到新的位置
				else   //没有空间移动
					FishNode->NodeElem->Clear();  //小鱼由于密度太大而死亡
			}
			FishNode=GetCell(List);  //获得下一个细胞节点
		}
	}

}

void main()
{
	Cell Sea[ROW][COLUMN];  //定义海域矩阵
    time_t   start, finish; //定义起止时间
    double   elapsed_time;  //定义时间差
	
	time( &start );         //获得开始时间
	srand( (unsigned)time( NULL ) );    //设置随机种子

    SeaInit(Sea[0][0],ROW,COLUMN);   //初始化海域生物信息

	for(int Time=0;Time<TIMELOOP;Time++)  //在迭代次数内循环
	{   
    	system("cls");         //清除屏幕
        struct CellNode* SharkList=NULL;  //定义鲨鱼链表
        struct CellNode* FishList=NULL;   //定义小鱼链表

        SharkList=CreatCellList(SharkList,Sea[0][0],ROW,COLUMN,SHARK_TYPE);  //创建鲨鱼链表
        FishList=CreatCellList(FishList,Sea[0][0],ROW,COLUMN,FISH_TYPE);     //创建小鱼链表
        
        Action(SharkList,Sea[0][0],ROW,COLUMN,SHARK_TYPE);   //鲨鱼的动作
        Action(FishList,Sea[0][0],ROW,COLUMN,FISH_TYPE);     //小鱼的动作

		OutPutSea(Sea[0][0],ROW,COLUMN);  //输出迭代一次后的海域情况
   //     getchar();

	}
    time( &finish );  //获得结束时间
    elapsed_time = difftime( finish, start );  //计算程序运行时间
	cout<<"程序运行时间:"<<elapsed_time<<"秒"<<endl;
    cout<<"自动机程序运行完毕,请按任意键退出";
	getchar();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -