游戏人工智能——有限状态机实验

实验四:有限状态机实验

 

一、实验目的

通过蚂蚁世界实验掌握游戏中追有限状态机算法

 

二、实验仪器

Win10下的Visualstudio

 

三、实验原理及过程

//描述有限状态机的算法原理

//描述程序实现时的思路包括对每个函数模块进行详细说明

有限状态机(FSM)是表示有限个状态及在这些状态之间的转移和动作等行为的数学模型,在计算机领域有着广泛的应用。通常FSM包含几个要素:状态的管理、状态的监控、状态的触发、状态触发后引发的动作。有限状态机是由寄存器组和组合逻辑构成的硬件时序电路。有限状态机的状态(即由寄存器组的1和0的组合状态所构成的有限个状态)只可能在同一时钟跳变沿的情况下才能从一个状态转向另一个状态。

  有限状态机的下一个状态不但取决于各个输入值,还取决于当前所在状态。这里指的是米里Mealy型有限状态机,而莫尔Moore型有限状态机的下一个状态只决于当前状态。

  1. 制作菜单

f051a172a6894380bb675b677d70e773.png

设置参数:点击会弹出对话框,设置一些参数,红、黑蚂蚁的家会在地图上标记出来
运行:设置好参数后点击运行,毒药、食物、水会在地图上随机显示 
下一步:2只红蚂蚁和2只黑蚂蚁会随机出现在地图上,窗口右方还会出现红、黑蚂
蚁当前数量的统计
不断按下一步,有限状态机就会不断运行,使蚁群产生变化
2)添加加速键

资源视图中

下方362a3f807f4748a693f5feefdef044f0.png

c4a185c40ae042a188f2909ae666d6ac.png

选择ID和键值

591b29b3e19a4490a0d4cfc3487a04ee.png

 

四、实验结果

 

35fa85d87d10433db840082e280cbafd.png

5aeb807770024935bda66a600a217387.png

3c18970338e8475cac3ee53324c54d39.png

c9f1e4c71967438fa630a3506f2d1238.png

880f00b0856e4e30ae9f0be803875885.png

6a885669321646f9b0f7308120016b25.png

五、实验心得(需包括有何不足如何改进)

//你认为你目前实现的程序有什么不足之处,如何改进

通过有限状态机实现蚂蚁的繁殖的一个实验,代码还是有点复杂,程序还有很多需要改进的地方。代码规范还需要进一步规范,使之将代码简洁明了。

 

六、主要代码

 

#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();

}

 

 

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

平杨猪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值