人工智能与专家系统课程设计---------迷宫游戏目录序言-------------------------------------------------------------3算法详解-------------------------------------------------------3程序代码内容与说明程序各个全局变量的声明---------------------------------7主体程序的实现----------------------------------------------8执行结果演示------------------------------------------------15设计心得体会------------------------------------------------17参考书目------------------------------------------------------17附录:程序源代码------------------------------------------18序言“人工智能”也就是所谓的AI(artifical intelligence),它是一门抽象的技术,人工智能程序的编写不需要遵循任何即定的思考模式或者规则,而游戏中的AI完全按照程序员自己的思考逻辑而发展。
这就是说,程序员越是聪明越是能够写出更为精明的计算机人工智能程序,这和程序员自身的条件有着很大的关系。
如果对于一个很陌生不熟悉的游戏领域,程序员从来没有接触过,这样即使有很高的编程水平,也没有办法实现我们想要达到的目标,根本不可能在游戏中将所有的情况包罗其中。
人工智能具有特定的三种思考模式,分别为移动模式,行为模式和策略模式。
顾名思义,给定一个物体移动路径的公式,物体按照这样的公式来移动的就是移动模式。
这种情况很多见,例如:某个物体追着玩家跑,目标射击等等。
它又可以分为固定模式移动,追逐移动,躲避移动。
策略型人工智能是AI中比较复杂的一种,最常见的运用策略型AI游戏是棋盘类的游戏,通常计算机必须判断目前情况下所有可走的棋步和可能获胜的情况,并计算目前计算机可走棋步的制胜分数或者是玩家可走棋步的制胜分数,最后决定出最佳的走法。
行为型AI在游戏中是经常会运用到的,它的主要意义是物体会随着情况的改变来做出一些行为动作,而这些物体可以是游戏中的主角、怪物或者是四周环境中的物品。
而此次迷宫游戏的设计也是属于人工智能中的行为模式。
算法详解路径搜寻的概念路径搜寻与行为型人工智能有直接的关系。
在迷宫游戏中,涉及路径搜寻时必须设定物体的一些走出迷宫的法则。
如前面有路时就往前走,前面的路走过就往没走过的地方走等。
这些法则必须确实可以让物体搜索迷宫中的每一块区域来找到出口,若走迷宫的法则设定得不完整,那么物体就有可能在同一个地方兜圈子,永远找不到出口了。
此外,为了让物体在走出迷宫后能知道正确走出迷宫的路径,必须给物体一张地图来记录所走过的路径,这张图就是一个链表结构,当物体成功走出迷宫后,整个链表就是正确走出迷宫的路径。
如图1所示图 1图1中,实线部分为小球走迷宫的最短路径,依照走迷宫的规则每移动到新一格时,该区域就被增加到链表中,而当走过的区域并非正确路径时(图中虚线部分),则从链表中删除。
例如:上图中虚线部分为小球所走过的区域,但小球进入该区域后发现是死路,因此必须倒退,每倒退一格时,就表示该格不是正确路径,因此从链表中删除;最后,当小球走出迷宫后,正确路径便会记录在链表中。
●搜寻最佳路径在这个迷宫路径搜寻的程序中,我以一颗小球来走迷宫,小球会自动搜寻到迷宫的入口,接着自动找寻出口,当找到出口后便记录着正确走出迷宫的路径,按[F2]键察看此最短路径。
●定义迷宫的方式使用一个整数的二维数组maze[8][8]来存储整个迷宫的状态。
如图2入口出口图 2定义数组时,设定出口元素值为3,入口的元素值为2,墙元素值为1,通道的元素值为0。
图2中,代表入口的数组元素为maze[0][1],同时,以变量m,n分别代表数组一维与二维的索引值,具体如下所示:maze[m][n]=3 // 出口maze[m][n]=2 // 入口maze[m][n]=1 // 墙maze[m][n]=0 // 通道●双向链表的使用在程序中我使用双向链表记录小球所走过的路径,结构定义如下:struct list //定义链表结构{int m;int n;struct list*next; //指向下一结点struct list*back; //指向前一个结点};typedef struct list node; //定义结点typedef mode*pointer; //定义动态指针当小球走迷宫时,主要王没有走过的格子走,程序使用一个二维的布尔数组pass[8][8]来记录格子是否走过,小球走向未走过的格子时,这一格会被加到链表里,而当小球走到其上、下、左、右有墙或者都已经走过的格子时,此时必须倒退,而每倒退一格就表示那一格是错误的格,因此将其从链表中删除,直到最后走出迷宫时,链表中每一结点便是正确的行进路线。
如图3:图3图中,虚线部分是小球所走过的错误路径,在走进错误区域后,都是死路。
因此小球必须沿原先进入的路径后退。
在后退后,原先加到链表中的错误结点也会同时从链表中删除,而后退到有其他未走过的格子可以走时,就往那一个格子前进,最后找到出口后,正确的行进路线的结点便记录在链表中。
●走迷宫的规则✧先试着往下走,若下一格有墙或者走过,则试着往右走✧若右一格有墙或者走过,则试着往左走✧若左一格有墙或者走过,则试着往上走✧若上一个有墙或者走过,此时表示上、下、左、右都有未走过的格,便必须往后退,回到上一结点位置并删除目前结点以下列出依各条规则所设定出的算法:1)试图往下走的程序代码:if(下一格是墙)/*试图往右走的程序代码*/elseif(下一格走过)/*试图往右走的程序代码*/else//往下走并新增结点2)试图往右走的程序代码:if(右一格是墙)/*试图往左走的程序代码*/elseif(右一格走过)/*试图往左走的程序代码*/else//往右走并新增结点3)试图往左走的程序代码:if(左一格是墙)/*试图往上走的程序代码*/elseif(左一格走过)/*试图往上走的程序代码*/else//往左走并新增结点4)试图往上走的程序代码:if(上一格是墙)//回上一个结点并删除目前结点elseif(上一格走过)//回上一个结点并删除目前结点else//往上走并新增结点将上面4组算法结合起来,就得到整个走迷宫的判断式结构了●程序内容说明:本迷宫游戏的主要功能如下:✧程序执行式自动搜寻入口与出口✧按[F1]键可重新进行搜寻✧按[F2]键辉县是正确走迷宫的路径✧若迷宫无出口,则搜寻结果会显示无出口的信息程序代码内容与说明一程序各个全局变量的声明int maze[8][8] ={1,1,1,1,1,1,1,1,2,0,0,1,0,0,0,1,1,1,0,0,0,1,1,1,1,0,0,1,0,0,0,1,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,1,1,0,1,0, 1,0,0,1,1,3,1,1,1,1,1,1};BOOL pass[8][8];int i,j,m,n,lastm,lastn;BOOL start= true,search= true,go;pointer ptr,preptr,first;char str[10];说明:1)第1、2行程序代码定义大小为8×8迷宫数组的内容,其中值为2与3的元素就是迷宫的入口与出口2)第3行程序代码定义一个pass数组,用来记录迷宫中各个格子是否走过,举例来说,若maze[4][5]走过,则pass[4][5]会被设定为true3)第4行程序代码定义的格个整数变量用途说明如下变量名称说明i 计数变量j 计数变量m 小球所在位置的第一个索引值n 小球所在位置的第二个索引值lastm 上一次小球所在位置的第一个索引值lastn 上一次小球所在位置的第二个索引值4)第5行程序代码所定义的3个布尔变量start、search、go分别用以表示程序开始,重新搜寻以及显示最短路径5)第6行程序代码定义了ptr、preptr与first动态指针,分别代表目前结点、上一个结点与第一个节点。
二主体程序的实现canvasFrame::canvasFrame(){/*建立窗口与加载图文件的程序代码*/for(i=0;i<7;i++){for(j=0;j<7;j++)if(maze[i][j]==2)break;if(maze[i][j]==2)break;}m = i;n = j;ptr = (pointer)malloc(sizeof(node));ptr->m = m;ptr->n = n;ptr->next = NULL;ptr->back = NULL;first = ptr;}说明:1)第3---10行程序代码为一个双层循环,用来搜寻二位数组中,元素值为2的元素;第6---8行程序代码判断若找到了此元素,则结束循环,此时I与j的值便是代表迷宫入口的索引值2)第11、12行程序代码将i,j的值赋予给m、n,这是第一个链表结点中所要存储的值3)第13行程序代码建立第一个节点的指针ptr,接着14、15行程序代码设定其中的成员变量m与n的值,第16、17行程序代码则将结点的前后指针指向NULL。
如此,第一个结点结构如下:其中结点的back指针是用以指向链表中的上一个结点,next指针则是指向下一个结点,如此便形成双向链表,而小球在走迷宫时才能够前进与后退4)第18行程序代码则设定first等于ptr,用来记录链表第一个结点的位置void canvasFrame::OnTimer(UINT nIDEvent){if(start)Start(); //开始搜寻else{if(search)Search(); //进行搜寻if(go)Go(); //显示最短路径}CFrameWnd::OnTimer(nIDEvent);}说明:在OnTimer函数中则是会依目前程序的状况来执行开始搜寻,显示最短路径等于自定义函数。
程序于一开始进行搜寻时便会执行Start函数,将小球的图案显示于入口上。
接下来每次进行搜寻而小球移动时,会执行Search函数,而当用户按下[F2]键时,则会调用Go函数来显示走出迷宫最短路径void canvasFrame::Start(){CClientDC dc(this);mdc->SelectObject(tile);for(i=0;i<=7;i++)for(j=0;j<=7;j++)if(maze[i][j] == 1)dc.BitBlt(j*40,i*40,40,40,mdc,0,0,SRCCOPY);mdc->SelectObject(ball);dc.BitBlt(ptr->n*40,ptr->m*40,40,40,mdc,0,0,SRCCOPY);start = false;lastn = ptr->n;lastm = ptr->m;}说明:1)在start函数中,第4---8行程序代码会先贴上迷宫中的墙。