实验四:有限状态机实验
一、实验目的
通过蚂蚁世界实验掌握游戏中追有限状态机算法
二、实验仪器
Win10下的Visualstudio
三、实验原理及过程
//描述有限状态机的算法原理
//描述程序实现时的思路包括对每个函数模块进行详细说明
有限状态机(FSM)是表示有限个状态及在这些状态之间的转移和动作等行为的数学模型,在计算机领域有着广泛的应用。通常FSM包含几个要素:状态的管理、状态的监控、状态的触发、状态触发后引发的动作。有限状态机是由寄存器组和组合逻辑构成的硬件时序电路。有限状态机的状态(即由寄存器组的1和0的组合状态所构成的有限个状态)只可能在同一时钟跳变沿的情况下才能从一个状态转向另一个状态。
有限状态机的下一个状态不但取决于各个输入值,还取决于当前所在状态。这里指的是米里Mealy型有限状态机,而莫尔Moore型有限状态机的下一个状态只决于当前状态。
- 制作菜单
编辑
设置参数:点击会弹出对话框,设置一些参数,红、黑蚂蚁的家会在地图上标记出来
运行:设置好参数后点击运行,毒药、食物、水会在地图上随机显示
下一步:2只红蚂蚁和2只黑蚂蚁会随机出现在地图上,窗口右方还会出现红、黑蚂
蚁当前数量的统计
不断按下一步,有限状态机就会不断运行,使蚁群产生变化
2)添加加速键
资源视图中
下方编辑
编辑
选择ID和键值
编辑
四、实验结果
编辑
编辑
编辑
编辑
编辑
编辑
五、实验心得(需包括有何不足如何改进)
//你认为你目前实现的程序有什么不足之处,如何改进
通过有限状态机实现蚂蚁的繁殖的一个实验,代码还是有点复杂,程序还有很多需要改进的地方。代码规范还需要进一步规范,使之将代码简洁明了。
六、主要代码
#include "stdafx.h"
#include "MAYI.h"
#include "MAYIDoc.h"
#include "MAYIView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
//房子初始位置
int kBlackHomeRow=3;
int kBlackHomeCol=3;
int kRedHomeRow=1;
int kRedHomeCol=1;
//地图参数
#define kMaxRows 20
#define kMaxCols 20
#define LENGTH 20 //每格的宽度
int terrain[kMaxRows][kMaxCols];
//设置水,食物,毒药的数量,系统会随机分配位置
int kMaxWater=3;
int kMaxPoison=3;
int kMaxFood=6;
//蚂蚁的状态
#define kForage 1
#define kGoHome 2
#define kThirsty 3
#define kDead 4
//计数初始化
int RedNum=2;
int BlackNum=2;
//蚂蚁组别
#define kRedAnt 1
#define kBlackAnt 2
//地形值
#define kGround 1
#define kWater 2
#define kBlackHome 3
#define kRedHome 4
#define kPoison 5
#define kFood 6
#define RedHomeRow 5;
#define RedHomeCol 5;
#define BlackHomeRow 1;
#define BlackHomeCol 1;
//随机函数
int Rnd(int min, int max)
{
int result;
do{
result=rand()%max;
}while(result<=min);
return result;
}
//蚂蚁类
class ai_Entity{
public:
int type;
int state;
int row;
int col;
ai_Entity();
~ai_Entity() {}
void New (int theType,int theState,int theRow,int theCol);
void Forage();
void GoHome();
void Thirsty();
void Dead();
};
ai_Entity::ai_Entity()
{
type=0;
state=0;
row=0;
col=0;
}
void ai_Entity::New(int theType, int theState,int theRow,int theCol)
{
type=theType;
row=theRow;
col=theCol;
state=theState;
}
#define kMaxEntities 200
ai_Entity entityList[kMaxEntities];
//标志位
bool FLAG=false;
//寻找食物的状态
void ai_Entity::Forage()
{
int rowMove;
int colMove;
int newRow;
int newCol;
int foodRow;
int foodCol;
int poisonRow;
int poisonCol;
rowMove=Rnd(-1,3)-1; //通过随机函数设定行方向要移动的距离
colMove=Rnd(-1,3)-1; //通过随机函数设定列方向要移动的距离
newRow=row+rowMove; //新的行的位置
newCol=col+colMove; //新的列的位置
if(newRow<0)
return;
if(newCol<0)
return;
if(newRow>=kMaxRows)
return;
if(newCol>=kMaxCols)
return;
//如果下一个位置是地面或者水,不改变蚂蚁的状态,直接赋予新的位置
if((terrain[newRow][newCol]==kGround)||(terrain[newRow][newCol]==kWater))
{
row=newRow;
col=newCol;
}
//如果下一个位置是食物,在更新位置之后还要去掉食物,改变蚂蚁的状态
if(terrain[newRow][newCol]==kFood)
{
row=newRow;
col=newCol;
terrain[row][col]=kGround;
state=kGoHome; //状态变为回家的状态
do{
foodRow=Rnd(-1,kMaxRows);
foodCol=Rnd(-1,kMaxCols);
}while(terrain[foodRow][foodCol]!=kGround);
terrain[foodRow][foodCol]=kFood; //设置新的食物位置
}
if(terrain[newRow][newCol]==kPoison)
{
row=newRow;
col=newCol;
terrain[row][col]=kGround;
state=kDead; //如果遇到毒药,状态变为死
do{
poisonRow=Rnd(-1,kMaxRows);
poisonCol=Rnd(-1,kMaxCols);
}while(terrain[poisonRow][poisonCol]!=kGround);
terrain[poisonRow][poisonCol]=kPoison; //设置新的毒药位置
}
}
void ai_Entity::GoHome()
{
int rowMove;
int colMove;
int newRow;
int newCol;
int homeRow;
int homeCol;
int poisonRow;
int poisonCol;
int i;
if(type==kRedAnt)
{
homeRow=RedHomeRow;
homeCol=RedHomeCol;
}
else
{
homeRow=BlackHomeRow;
homeCol=BlackHomeCol;
}
//渐渐逼近家里
if(row<homeRow)
rowMove=1;
else if(row>homeRow)
rowMove=-1;
else
rowMove=0;
if(col<homeCol)
colMove=1;
else if(col>homeCol)
colMove=-1;
else
colMove=0;
newRow=row+rowMove;
newCol=col+colMove;
if(newRow<0)
return;
if(newCol<0)
return;
if(newRow>=kMaxRows)
return;
if(newCol>=kMaxCols)
return;
if(terrain[newRow][newCol]!=kPoison)
{
row=newRow;
col=newCol;
}
else
{
row=newRow;
col=newCol;
terrain[row][col]=kGround;
state=kDead;
do{
poisonRow=Rnd(-1,kMaxRows);
poisonCol=Rnd(-1,kMaxCols);
}while(terrain[poisonRow][poisonCol]!=kGround);
terrain[poisonRow][poisonCol]=kPoison; //回家的过程碰到毒药还是死
}
if((newRow==homeRow)&&(newCol==homeCol))
{
row=newRow;
col=newCol;
state=kThirsty;//回家后状态变为饥渴
for(i=0;i<kMaxEntities;i++)
if(entityList[i].type==0)
{
entityList[i].New(type,kForage,homeRow,homeCol);//产生新的蚂蚁
if(type==kRedAnt) //如果是红蚂蚁则新蚂蚁也是红的
RedNum++;
if(type==kBlackAnt) //如果是黑蚂蚁则新蚂蚁也是黑的
BlackNum++;
break;
}
}
}
void ai_Entity::Thirsty()
{
int rowMove;
int colMove;
int newRow;
int newCol;
int foodRow;
int foodCol;
int poisonRow;
int poisonCol;
rowMove=Rnd(-1,3)-1;
colMove=Rnd(-1,3)-1;
newRow=row+rowMove;
newCol=col+colMove;
if(newRow<0)
return;
if(newCol<0)
return;
if(newRow>=kMaxRows)
return;
if(newCol>=kMaxCols)
return;
if((terrain[newRow][newCol]==kGround)||(terrain[newRow][newCol]==kFood))
{
row=newRow;
col=newCol;
}
if(terrain[newRow][newCol]==kWater)
{
row=newRow;
col=newCol;
terrain[row][col]=kGround;
state=kForage; //找到水后状态变为寻找
do{
foodRow=Rnd(-1,kMaxRows);
foodCol=Rnd(-1,kMaxCols);
}while(terrain[foodRow][foodCol]!=kGround);
terrain[foodRow][foodCol]=kWater;
}
if(terrain[newRow][newCol]==kPoison)
{
row=newRow;
col=newCol;
terrain[row][col]=kGround;
state=kDead;
do{
poisonRow=Rnd(-1,kMaxRows);
poisonCol=Rnd(-1,kMaxCols);
}while(terrain[poisonRow][poisonCol]!=kGround);
terrain[poisonRow][poisonCol]=kPoison;
}
}
//蚂蚁死后计数减少
void ai_Entity::Dead()
{
if(type==kRedAnt)
RedNum--;
if(type==kBlackAnt)
BlackNum--;
type=0;
}
// CMAYIView
IMPLEMENT_DYNCREATE(CMAYIView, CView)
BEGIN_MESSAGE_MAP(CMAYIView, CView)
// 标准打印命令
ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
ON_COMMAND(ID_START, &CMAYIView::OnStart)
ON_COMMAND(ID_SET, &CMAYIView::OnSet)
END_MESSAGE_MAP()
// CMAYIView 构造/析构
CMAYIView::CMAYIView()
{
// TODO: 在此处添加构造代码
}
CMAYIView::~CMAYIView()
{
}
BOOL CMAYIView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
return CView::PreCreateWindow(cs);
}
// CMAYIView 绘制
void CMAYIView::OnDraw(CDC* pDC)
{
CMAYIDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
int i,j;
//绘制网格
for(i=0;i<=LENGTH*kMaxRows;i+=LENGTH)
{
//画横线
pDC->MoveTo(0,i);
pDC->LineTo(LENGTH*kMaxCols,i);
}
for(i=0;i<=LENGTH*kMaxCols;i+=LENGTH)
{
//画竖线
pDC->MoveTo(i,0);
pDC->LineTo(i,LENGTH*kMaxRows);
}
if(FLAG)
{
//初始化房子
pDC->SetTextColor(RGB(0,0,0));
pDC->TextOutW(kBlackHomeCol*LENGTH+3,kBlackHomeRow*LENGTH+3,L"H");
pDC->SetTextColor(RGB(255,0,0));
pDC->TextOutW(kRedHomeCol*LENGTH+3,kRedHomeRow*LENGTH+3,L"H");
}
//在地图上更新水(W),毒药(P),食物(F)
for(i=0;i<kMaxRows;i++)
{
for(j=0;j<kMaxCols;j++)
{
if(terrain[i][j]==kWater)
{
pDC->SetTextColor(RGB(0,192,255));
pDC->TextOutW(i*LENGTH+3,j*LENGTH+3,L"W");
}
else if(terrain[i][j]==kPoison)
{
pDC->SetTextColor(RGB(160,0,120));
pDC->TextOutW(i*LENGTH+3,j*LENGTH+3,L"P");
}
else if(terrain[i][j]==kFood)
{
pDC->SetTextColor(RGB(255,216,0));
pDC->TextOutW(i*LENGTH+3,j*LENGTH+3,L"F");
}
}
}
//在地图上更新蚂蚁的位置
for(i=0;i<kMaxEntities;i++)
{
if(entityList[i].type==kRedAnt)
{
pDC->SetTextColor(RGB(255,0,0));
pDC->TextOutW(entityList[i].col*LENGTH+1,entityList[i].row*LENGTH+1,L"A");
}
if(entityList[i].type==kBlackAnt)
{
pDC->SetTextColor(RGB(0,0,0));
pDC->TextOutW(entityList[i].col*LENGTH+1,entityList[i].row*LENGTH+1,L"A");
}
//显示蚂蚁,食物,水,毒药的数量
CString s;
s.Format(_T("红色蚂蚁:%d"),RedNum);
pDC->TextOutW(23*LENGTH,0,s);
s.Format(_T("黑色蚂蚁:%d"),BlackNum);
pDC->TextOutW(23*LENGTH,2*LENGTH,s);
s.Format(_T("食物数量:%d"),kMaxFood);
pDC->TextOutW(23*LENGTH,4*LENGTH,s);
s.Format(_T("水数量:%d"),kMaxWater);
pDC->TextOutW(23*LENGTH,6*LENGTH,s);
s.Format(_T("毒药数量:%d"),kMaxPoison);
pDC->TextOutW(23*LENGTH,8*LENGTH,s);
}
}
// CMAYIView 打印
BOOL CMAYIView::OnPreparePrinting(CPrintInfo* pInfo)
{
// 默认准备
return DoPreparePrinting(pInfo);
}
void CMAYIView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加额外的打印前进行的初始化过程
}
void CMAYIView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加打印后进行的清理过程
}
// CMAYIView 诊断
#ifdef _DEBUG
void CMAYIView::AssertValid() const
{
CView::AssertValid();
}
void CMAYIView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CMAYIDoc* CMAYIView::GetDocument() const // 非调试版本是内联的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMAYIDoc)));
return (CMAYIDoc*)m_pDocument;
}
#endif //_DEBUG
// CMAYIView 消息处理程序
//执行菜单的函数,根据蚂蚁的状态进入对应的函数
void CMAYIView::OnStart()
{
// TODO: 在此添加命令处理程序代码
for(int i=0;i<kMaxEntities;i++)
{
switch(entityList[i].state)
{
case kForage:
entityList[i].Forage();
break;
case kGoHome:
entityList[i].GoHome();
break;
case kThirsty:
entityList[i].Thirsty();
break;
case kDead:
entityList[i].Dead();
break;
default:
break;
}
}
Invalidate();
}
//设置菜单的函数
void CMAYIView::OnSet()
{
// TODO: 在此添加命令处理程序代码
//初始化蚂蚁位置
entityList[0].New(kRedAnt,kForage,5,5);
entityList[1].New(kRedAnt,kForage,8,5);
entityList[2].New(kBlackAnt,kForage,5,8);
entityList[3].New(kBlackAnt,kForage,9,9);
//先把地图都设置成地面
int i,j;
for(i=0;i<kMaxRows;i++)
for(j=0;j<kMaxCols;j++)
{
terrain[i][j]=kGround;
}
//定位红黑蚂蚁房子的坐标
terrain[kRedHomeRow][kRedHomeCol]=kRedHome;
terrain[kBlackHomeRow][kBlackHomeCol]=kBlackHome;
srand(time(NULL)); //取系统时间为随机种子
//根据程序开始定义的kMaxWater,kMaxPoison,kMaxFood,随机定位水,毒药,食物的位置
int r,c;
for(i=0;i<kMaxWater;i++)
{
r=Rnd(-1,kMaxRows);
c=Rnd(-1,kMaxCols);
if(terrain[r][c]==kGround)
terrain[r][c]=kWater;
else
i--;
}
for(i=0;i<kMaxPoison;i++)
{
r=Rnd(-1,kMaxRows);
c=Rnd(-1,kMaxCols);
if(terrain[r][c]==kGround)
terrain[r][c]=kPoison;
else
i--;
}
for(i=0;i<kMaxFood;i++)
{
r=Rnd(-1,kMaxRows);
c=Rnd(-1,kMaxCols);
if(terrain[r][c]==kGround)
terrain[r][c]=kFood;
else
i--;
}
FLAG = true; //初始化完毕后,FLAG变真
Invalidate();
}