人工智能与及应用.docx
《人工智能与及应用.docx》由会员分享,可在线阅读,更多相关《人工智能与及应用.docx(9页珍藏版)》请在冰豆网上搜索。
人工智能与及应用
实验报告
|
|
实验名称图搜索问题求解
课程名称人工智能及应用
一、实验目的及要求
熟悉PROLOG语言的特点和某种PROLOG编程环境;掌握编写与调试简单的PROLOG程序的方法。
通过设计、编写和调试了解PROLOG编译器;掌握PROLOG语言中常量、变量的表示方法和PROLOG进行事实库、规则库的编写方法。
加深对逻辑程序运行机理的理解,掌握PROLOG语言的特点,熟悉其编程环境。
针对实际应用问题,分析题目背景,利用编程实现图搜索技术的问题求解方法,以牢固掌握图搜索技术的基本原理和常用算法,加深对图搜索技术的理解。
实验要求采用PROLOG编程求解8*8骑士周游问题以及农夫、狼、羊、菜问题。
采用熟悉的高级语言编程实现“过河问题”、“九宫格”等问题的求解。
二、所用仪器、设备
计算机、TRINC-PROLOG及高级语言程序设计环境。
三、实验原理
1.8*8骑士周游问题求解,以squre(x,y)表示骑士的位置,然后寻找一条是否存在的路径判断是否存在此路径的周游方法。
通过x与y的值的范围,判断是否可以向左右方向移动,达到求解周游的问题。
2.农夫、狼、羊、菜问题求解,采用宽度优先搜索算法,寻找一条安全的路径,农夫把三物品从河的一岸送到对岸,设计状态state(x,y,z,w)表示当前四物所处在的状态,按照算法寻找出最后的路径。
3.四皇后问题解决,封装Queen类,包括皇后个数,以及皇后位置是否正确而的判断方法,然后再主方法中调用方法即可。
4.极大极小方法求解井字棋问题,对状态空间采用最大最小值搜索,计算机在生成的子节点中选择评估函数值最大的节点,而计算机在选择着数时使人选择评估函数值最小的节点,也就是对计算机一方最不利的节点。
四、实验方法与步骤
1.8*8骑士周游问题,通过当前点的坐标范围判断是否可以向“加一”,“加二”方向移动,而实现8*8周游问题的解决。
通过对横纵坐标的范围,确定是否可以对其进行移动而得到判断,只需要写好对应的坐标变化,然后与当前要移动的坐标是否合一,而确定是否存在这样的路径。
Path()则是对于在两坐标判断是否存在其中的路径然后对其蕴含式的解析。
当path(x,y)的x与y参数相同是则退出。
实现算法:
move(squre(Row,Column),squre(New_Row,New_Column)):
-
Row=<6,New_RowisRow+2,Column=<7,New_ColumnisColumn+1.
move(squre(Row,Column),squre(New_Row,New_Column)):
-
Row=<6,New_RowisRow+2,Column>=2,New_ColumnisColumn-1.
move(squre(Row,Column),squre(New_Row,New_Column)):
-
Row>=3,New_RowisRow-2,Column=<7,New_ColumnisColumn+1.
move(squre(Row,Column),squre(New_Row,New_Column)):
-
Row>=3,New_RowisRow-2,Column>=2,New_ColumnisColumn-1.
move(squre(Row,Column),squre(New_Row,New_Column)):
-
Row=<7,New_RowisRow+1,Column=<6,New_ColumnisColumn+2.
move(squre(Row,Column),squre(New_Row,New_Column)):
-
Row=<7,New_RowisRow+1,Column>=3,New_ColumnisColumn-2.
move(squre(Row,Column),squre(New_Row,New_Column)):
-
Row>=2,New_RowisRow-1,Column=<6,New_ColumnisColumn+2.
move(squre(Row,Column),squre(New_Row,New_Column)):
-
Row>=2,New_RowisRow-1,Column>=3,New_ColumnisColumn-2.
been(squre(0,0)).
path(X,X).
path(X,Y):
-move(X,Z),not(been(Z)),dynamic(knight_tour,been/1),asserta(knight_tour,been(Z)),path(Z,Y).
2.农夫、狼、羊、菜过河问题,定义状态state(x,y,z,w)表示四个物体当前所在的位置(河东还是河西用e跟w表示),move(state(x,y,z,w),state(u,v,w,g))表示从和的一岸向另一岸移动,当然移动必须满足要求,移动之后的状态必须处在一个安全的状态,用unsafe(state())来检测所处位置是否安全,并且是农夫与移动的物体一起移动,采用go(start,goal)表示从现在开始的状态以及要达到的目标态而进行路径搜索,path(Open_queue,Closed_set,Goal)表示移动路径所需要满足的条件之一,即就是本宽度算法中的open,closed表,当然在本算法中涉及到队列的各种方法,拼接,判空等操作都需要在算法中给予具体的实现。
具体实现的算法为:
move(state(X,X,G,C),state(Y,Y,G,C)):
-opp(X,Y).
move(state(X,W,X,C),state(Y,W,Y,C)):
-opp(X,Y).
move(state(X,W,G,X),state(Y,W,G,Y)):
-opp(X,Y).
move(state(X,W,G,C),state(Y,W,G,C)):
-opp(X,Y).
unsafe(state(X,Y,Y,C)):
-opp(X,Y).
unsafe(state(X,W,Y,Y)):
-opp(X,Y).
opp(e,w).
opp(w,e).
go(Start,Goal):
-empty_queue(Empty_open_queue),
enqueue([Start,nil],Empty_open_queue,Open_queue),
empty_set(Closed_set),
path(Open_queue,Closed_set,Goal).
path(Open_queue,_,_):
-empty_queue(Open_queue),
write("Nosolutionfoundwiththeserules").
path(Open_queue,Closed_set,Goal):
-
dequeue([State,Parent],Open_queue,_),State=Goal,
write("Asolutionisfound:
"),nl,
printsolution([State,Parent],Closed_set).
%printsolution1(Closed_set).
path(Open_queue,Closed_set,Goal):
-
dequeue([State,Parent],Open_queue,Rest_open_queue),
get_children(State,Rest_open_queue,Closed_set,Children),
add_list_to_queue(Children,Rest_open_queue,New_open_queue),
union([[State,Parent]],Closed_set,New_closed_set),
path(New_open_queue,New_closed_set,Goal).
get_children(State,Rest_open_queue,Closed_set,Children):
-
bagof(Child,moves(State,Rest_open_queue,Closed_set,Child),Children).
moves(State,Rest_open_queue,Closed_set,[Next,State]):
-
move(State,Next),not(unsafe(Next)),
not(member_queue([Next,_],Rest_open_queue)),
not(member_set([Next,_],Closed_set)).
%printsolution1(L):
-empty_set(L).
%printsolution1([H|T]):
-printsolution1(T),write(H),nl.
printsolution([State,nil],_):
-write(State),nl.
printsolution([State,Parent],Closed_set):
-
member_set([Parent,Grandparent],Closed_set),
printsolution([Parent,Grandparent],Closed_set),
write(State),nl.
empty_set([]).
member_set([State,Parent],[[State,Parent]|_]).
member_set(X,[_|T]):
-member_set(X,T).
empty_queue([]).
enqueue(E,[],[E]).
enqueue(E,[H|T],[H|Tnew]):
-enqueue(E,T,Tnew).
dequeue([State,Parent],[[State,Parent]|T],T).
add_list_to_queue(List,Queue,New_queue):
-append(Queue,List,New_queue).
append(X,Y,Z):
-X=[],Z=Y.
append(X,Y,Z):
-X=[A|B],Z=[A|W],append(B,Y,W).
member(X,[X|T]).
member(X,[_|T]):
-member(X,T).
member_queue(Element,Queue):
-member(Element,Queue).
union([],Set,Set).
union([H|T],S,Snew):
-union(T,S,S2),add_if_not_in_set(H,S2,Snew).
add_if_not_in_set(X,S,S):
-member(X,S),!
.
add_if_not_in_set(X,S,[X|S]).
3.四皇后问题,在类中封装方法,boolbCanPlace(intk),oidBackTrack(intk),voidPrintX(void),实现实现对皇后位置的检测,最后打印出结果为每行皇后的位置的列即就是为一个有效的序列。
主要方法:
classQueen{
friendintnQueen(int);
private:
boolbCanPlace(intk);
voidBackTrack(intk);
voidPrintX(void);
intn,*x,sum;
};
boolQueen:
:
bCanPlace(intk)//判断是否合法
{
boolbOk=true;
for(inti=1;i{
if((abs(k-i)==abs(x[k]-x[i]))||(x[k]==x[i]))
{
bOk=false;
break;
}
}
returnbOk;
}
4.极大极小值求井字棋问题,voidInit()棋盘初始化函数,voidPrintQP()打印棋盘函数voidUserInput()用户输入落子位置函数,这三份方法程序中当前的棋局进行读写操作;ntIsWin(States)判断当前棋局是否有一方获胜,并判断哪一方获胜的函数,inte_fun(States)评估函数值计算函数,当前的棋局进行判断;intAutoDone()极大极小值算法主函数,计算机决定在哪个位置落子所采用的核心算法,并且可以判断计算机落子前后棋局的状态,如果在搜索树的深度范围内能判断哪一方必胜,则可提前打印输赢信息,并结束本棋。
主要方法:
intIsWin(States)//有人赢了吗?
返回0表示没有人赢,返回-1表示人赢了,返回1表示计算机赢了
{
for(inti=0;i<3;i++)
{
if(s.QP[i][0]==1&&s.QP[i][1]==1&&s.QP[i][2]==1)return1;
if(s.QP[i][0]==-1&&s.QP[i][1]==-1&&s.QP[i][2]==-1)return-1;
}
for(i=0;i<3;i++)
{
if(s.QP[0][i]==1&&s.QP[1][i]==1&&s.QP[2][i]==1)return1;
if(s.QP[0][i]==-1&&s.QP[1][i]==-1&&s.QP[2][i]==-1)return-1;
}
if((s.QP[0][0]==1&&s.QP[1][1]==1&&s.QP[2][2]==1)||(s.QP[2][0]==1&&s.QP[1][1]==1&&s.QP[0][2]==1))return1;
if((s.QP[0][0]==-1&&s.QP[1][1]==-1&&s.QP[2][2]==-1)||(s.QP[2][0]==-1&&s.QP[1][1]==-1&&s.QP[0][2]==-1))return-1;
return0;
}
inte_fun(States)//评估函数
{
boolflag=true;
for(inti=0;i<3;i++)
for(intj=0;j<3;j++)
if(s.QP[i][j]==0)flag=false;
if(flag)returnNO_BLANK;
if(IsWin(s)==-1)return-MAX_NUM;//如果计算机输了,返回最小值
if(IsWin(s)==1)returnMAX_NUM;//如果计算机赢了,返回最大值
intcount=0;//该变量用来表示评估函数的值
//将棋盘中的空格填满自己的棋子,既将棋盘数组中的0变为1
for(i=0;i<3;i++)
for(intj=0;j<3;j++)
if(s.QP[i][j]==0)tmpQP[i][j]=1;
elsetmpQP[i][j]=s.QP[i][j];
//电脑一方
//计算每一行中有多少行的棋子连成3个的
for(i=0;i<3;i++)
count+=(tmpQP[i][0]+tmpQP[i][1]+tmpQP[i][2])/3;
//计算每一列中有多少列的棋子连成3个的
for(i=0;i<3;i++)
count+=(tmpQP[0][i]+tmpQP[1][i]+tmpQP[2][i])/3;
//斜行有没有连成3个的?
count+=(tmpQP[0][0]+tmpQP[1][1]+tmpQP[2][2])/3;
count+=(tmpQP[2][0]+tmpQP[1][1]+tmpQP[0][2])/3;
//将棋盘中的空格填满对方的棋子,既将棋盘数组中的0变为-1
for(i=0;i<3;i++)
for(intj=0;j<3;j++)
if(s.QP[i][j]==0)tmpQP[i][j]=-1;
elsetmpQP[i][j]=s.QP[i][j];
//对方
//计算每一行中有多少行的棋子连成3个的
for(i=0;i<3;i++)
count+=(tmpQP[i][0]+tmpQP[i][1]+tmpQP[i][2])/3;
//计算每一列中有多少列的棋子连成3个的
for(i=0;i<3;i++)
count+=(tmpQP[0][i]+tmpQP[1][i]+tmpQP[2][i])/3;
//斜行有没有连成3个的?
count+=(tmpQP[0][0]+tmpQP[1][1]+tmpQP[2][2])/3;
count+=(tmpQP[2][0]+tmpQP[1][1]+tmpQP[0][2])/3;
returncount;
}
五、实验结果
图一八骑士周游结果一
图二八骑士周游结果二
图三农夫、狼、羊、菜问题结果
图四四皇后的一个解
图五下棋过程截图
六、讨论与结论
通过本次实验,对在人工智能课上学习的内容有了更加深刻的理解,真正的学习必须得自己在实践中寻找问题发现问题,最终解决问题,我们要的不是一个答案,而是发现答案的过程,在不断的出错中不断的进步才是学习的进步。
通过在实验中对课上学习的内容的实践,真正的体会算法的作用图搜索算法的作用,在一般的计算方式下,计算模式是多么不科学,时间耗费,是否最优的达到时间以及空间的复杂度,解决实际的问题,首先的抽象出问题的数学模型,转化为数学计算,最后运用程序设计语言设计数据模型,将问题抽象解决。
当然在这个过程中,需要付出时间与精力,在本实验的过程中,由于对prolog语言不太熟悉,所以在真正的写算法的过程中遇到了很多的问题,并且在编写的过程中也是出现了很多的错误,最后通过向老师请教,一步一步的改进与进步,最终实现了部分功能。
高级语言设计部分,因为比较的了解,相对来说比较的容易一些。