《人工智能导论》上机实验指导书
基于人工智能的状态空间搜索策略研究
——八数码问题求解
(一)实验软件
TC2.0 或 VC6.0 编程语言或其它编程语言
(二)实验目的
1. 熟悉人工智能系统中的问题求解过程;
2. 熟悉状态空间的盲目搜索和启发式搜索算法的应用;
3. 熟悉对八数码问题的建模、求解及编程语言的应用。
(三)需要的预备知识
1. 熟悉TC2.0 或 VC6.0 编程语言或者其它编程语言;
2. 熟悉状态空间的宽度优先搜索、深度优先搜索和启发式搜索算法;
3. 熟悉计算机语言对常用数据结构如链表、队列等的描述应用;
4. 熟悉计算机常用人机接口设计。
(四)实验数据及步骤
1. 实验内容
八数码问题:在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所示,要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态。
(a) 初始状态 (b) 目标状态
图1 八数码问题示意图
请任选一种盲目搜索算法(深度优先搜索或宽度优先搜索)或 任选一种启发式搜索方法(A 算法或 A* 算法)编程求解八数码问题(初始状态任选),并对实验结果进行分析,得出合理的结论。
2. 实验步骤
(1)分析算法基本原理和基本流程;
程序采用宽度优先搜索算法,基本流程如下:
(2)确定对问题描述的基本数据结构,如 Open 表和 Closed 表等;
(3)编写算符运算、目标比较等函数;
(4)编写输入、输出接口;
(5)全部模块联调;
(6)撰写实验报告。
(五)实验报告要求
所撰写的实验报告必须包含以下内容:
1. 算法基本原理和流程框图;
2. 基本数据结构分析和实现;
3. 编写程序的各个子模块,按模块编写文档,含每个模块的建立时间、功能、输入输出参数意义和与其它模块联系等;
4. 程序运行结果,含使用的搜索算法及搜索路径等;
5. 实验结果分析;
6. 结论;
7. 提供全部源程序及软件的可执行程序。
附:实验报告格式
一、实验问题
二、实验目的
三、实验原理
四、程序框图
五、实验结果及分析
六、结论
七、源程序及注释
#include<stdio.h>
#include<conio.h>
int n,m;
typedef struct Node
{
char matrix[10];/*存储矩阵*/
char operate;/*存储不可以进行的操作,L代表不能左移R代表不能右移U代表不能上移D代表不能下移*/
char extend;/*是否可以扩展,Y代表可以,N代表不可以*/
int father;/*指向产生自身的父结点*/
}Node;
char start[10]={"83426517 "};/*此处没有必要初始化*/
char end[10]={"1238 4765"};/*此处没有必要初始化*/
Node base[4000];
int result[100];/*存放结果的base数组下标号,逆序存放*/
int match()/*判断是否为目标*/
{
int i;
for(i=0;i<9;i++)
{
if(base[n-1].matrix[i]!=end[i])
{
return 0;
}
}
return 1;
}
void show()/*显示矩阵的内容*/
{
int i=1;
while(m>=0)
{
int mm=result[m];
//clrscr();
printf("\n\n\n 状态方格\t\t步骤 %d",i);
printf("\n\n\n\n\n\t\t\t%c\t%c\t%c\n",base[mm].matrix[0],base[mm].matrix[1],base[mm].matrix[2]);
printf("\n\n\t\t\t%c\t%c\t%c\n",base[mm].matrix[3],base[mm].matrix[4],base[mm].matrix[5]);
printf("\n\n\t\t\t%c\t%c\t%c\n",base[mm].matrix[6],base[mm].matrix[7],base[mm].matrix[8]);
//sleep(1);
m--;
i++;
}
}
void leave()/*推理成功后退出程序之前要执行的函数,主要作用是输出结果*/
{
n--;
while(base[n].father!=-1)
{
result[m]=n;
m++;
n=base[n].father;
}
result[m]=0;
result[m+1]='\0';
show();
//clrscr();
printf("\n\n\n\n\n\n\n\n\n\t\t\t\t搜索结束\n\n\n\n\n\n\n\n\n\n");
getch();
//exit(0);
}
int left(int x)/*把下标为X的数组中的矩阵的空格左移*/
{
int i,j;
char ch;
for(i=0;i<9;i++)
{
if(base[x].matrix[i]==' ')
break;
}
if(i==0||i==3||i==6||i==9)
{
return 0;
}
for(j=0;j<9;j++)
{
base[n].matrix[j]=base[x].matrix[j];
}
ch=base[n].matrix[i-1];
base[n].matrix[i-1]=base[n].matrix[i];
base[n].matrix[i]=ch;
base[n].operate='R';
base[n].extend='Y';
base[n].father=x;
base[x].extend='N';
n++;
if(match(i))
leave();
return 1;
}
int right(int x)/*把下标为X的数组中的矩阵的空格右移*/
{
int i,j;
char ch;
for(i=0;i<9;i++)
{
if(base[x].matrix[i]==' ')
break;
}
if(i==2||i==5||i==8||i==9)
{
return 0;
}
for(j=0;j<9;j++)
{
base[n].matrix[j]=base[x].matrix[j];
}
ch=base[n].matrix[i+1];
base[n].matrix[i+1]=base[n].matrix[i];
base[n].matrix[i]=ch;
base[n].operate='L';
base[n].extend='Y';
base[n].father=x;
base[x].extend='N';
n++;
if(match(i))
leave();
return 1;
}
int up(int x)/*把下标为X的数组中的矩阵的空格上移*/
{
int i,j;
char ch;
for(i=0;i<9;i++)
{
if(base[x].matrix[i]==' ')
break;
}
if(i==0||i==1||i==2||i==9)
{
return 0;
}
for(j=0;j<9;j++)
{
base[n].matrix[j]=base[x].matrix[j];
}
ch=base[n].matrix[i-3];
base[n].matrix[i-3]=base[n].matrix[i];
base[n].matrix[i]=ch;
base[n].operate='D';
base[n].extend='Y';
base[n].father=x;
base[x].extend='N';
n++;
if(match(i))
leave();
return 1;
}
int down(int x)/*把下标为X的数组中的矩阵的空格下移*/
{
int i,j;
char ch;
for(i=0;i<9;i++)
{
if(base[x].matrix[i]==' ')
break;
}
if(i==6||i==7||i==8||i==9)
{
return 0;
}
for(j=0;j<9;j++)
{
base[n].matrix[j]=base[x].matrix[j];
}
ch=base[n].matrix[i+3];
base[n].matrix[i+3]=base[n].matrix[i];
base[n].matrix[i]=ch;
base[n].operate='U';
base[n].extend='Y';
base[n].father=x;
base[x].extend='N';
n++;
if(match(i))
leave();
return 1;
}
main()
{
int i;
char a[20],b[20];
n=1;
//textcolor(LIGHTGREEN);
//clrscr();
/*以下是输入初始和目标矩阵,并把输入的0转换为空格*/
printf("Please input the start 9 chars:");
scanf("%s",a);
printf("Please input the end 9 chars:");
scanf("%s",b);
for(i=0;i<9;i++)
{
if(a[i]=='0')
{
start[i]=' ';
continue;
}
if(b[i]=='0')
{
end[i]=' ';
continue;
}
start[i]=a[i];
end[i]=b[i];
}
start[9]='\0';
end[9]='\0';
for(i=0;i<9;i++)
{
base[0].matrix[i]=start[i];
}
base[0].operate='N';
base[0].extend='Y';
base[0].father=-1;
/*以上是为第一个base数组元素赋值*/
for(i=0;n<4000;i++)
{
if(base[i].extend=='Y')
{
if(base[i].operate=='L')
{
right(i);up(i);down(i);
}
if(base[i].operate=='R')
{
left(i);up(i);down(i);
}
if(base[i].operate=='U')
{
left(i);right(i);down(i);
}
if(base[i].operate=='D')
{
left(i);right(i);up(i);
}
if(base[i].operate=='N')
{
left(i);right(i);up(i);down(i);
}
}
}
}
昆明理工大学信息工程与自动化学院学生实验报告
( 2012 — 2013 学年第 1 学期)
课程名称:人工智能 开课实验室:信自楼442 2012 年10月 24日
一、上机目的及内容
1.上机内容
用确定性推理算法求解教材65-66页介绍的八数码难题。
2.上机目的
(1)复习程序设计和数据结构课程的相关知识,实现课程间的平滑过渡;
(2)掌握并实现在小规模状态空间中进行图搜索的方法;
(3)理解并掌握图搜索的技术要点。
二、实验原理及基本技术路线图(方框原理图或程序流程图)
(1)设计并实现程序,求解出正确的解答路径;
(2)对所设计的算法采用大O符号进行时间复杂性和空间复杂性分析;
(3)对一般图搜索的技术要点和技术难点进行评述性分析。
三、所用仪器、材料(设备名称、型号、规格等或使用软件)
1台PC及VISUAL C++6.0软件
四、实验方法、步骤(或:程序代码或操作过程)
流程图:
源代码:
Source files:
主函数main:
#include <iostream>
#include "Node.h"
#include "Queue.h"
#include "Search.h"
#include "Tree.h"
void CreateNode1(std::vector<int>& s)
{
s.push_back(2);
s.push_back(8);
s.push_back(3);
s.push_back(1);
s.push_back(0);
s.push_back(4);
s.push_back(7);
s.push_back(6);
s.push_back(5);
}
void CreateNode4(std::vector<int>& d)
{
d.push_back(2);
d.push_back(8);
d.push_back(3);
d.push_back(1);
d.push_back(6);
d.push_back(4);
d.push_back(7);
d.push_back(0);
d.push_back(5);
}
void CreateNode8(std::vector<int>& d)
{
d.push_back(0);
d.push_back(2);
d.push_back(3);
d.push_back(1);
d.push_back(8);
d.push_back(4);
d.push_back(7);
d.push_back(6);
d.push_back(5);
}
void CreateNode20(std::vector<int>& d)
{
d.push_back(2);
d.push_back(0);
d.push_back(8);
d.push_back(1);
d.push_back(4);
d.push_back(3);
d.push_back(7);
d.push_back(6);
d.push_back(5);
}
void CreateNode27(std::vector<int>& d)
{
d.push_back(1);
d.push_back(2);
d.push_back(3);
d.push_back(8);
d.push_back(0);
d.push_back(4);
d.push_back(7);
d.push_back(6);
d.push_back(5);
}
void CreateNode_test1(std::vector<int>& d)
{
d.push_back(7);
d.push_back(6);
d.push_back(5);
d.push_back(4);
d.push_back(0);
d.push_back(1);
d.push_back(3);
d.push_back(8);
d.push_back(2);
}
void test_expand()
{
std::vector<int> s;
CreateNode1(s);
std::vector<int> d;
CreateNode4(d);
Node source(s);
Node dest(d);
source.Display();
Search search(&source);
std::cout << source.Expand(dest, search);
}
void test_search()
{
std::vector<int> s;
CreateNode1(s);
std::vector<int> d;
CreateNode4(d);
Node source(s);
Node dest(d);
source.Display();
dest.Display();
Search search(&source);
search.Find( & dest);
search.DisplayRoute();
}
void test_search2level()
{
std::vector<int> s;
CreateNode1(s);
std::vector<int> d;
CreateNode8(d);
Node source(s);
Node dest(d);
source.Display();
dest.Display();
Search search(&source);
search.Find( & dest);
search.DisplayRoute();
}
void test_search_lab1()
{
std::vector<int> s;
CreateNode1(s);
std::vector<int> d;
CreateNode27(d);
Node source(s);
Node dest(d);
source.Display();
dest.Display();
Search search(&source);
search.Find( & dest);
search.DisplayRoute();
}
int main(int argc, char** argv)
{
// test_expand();
// test_search();
// test_search2level();
// test_search_lab1();
std::vector<int> s;
CreateNode1(s);
std::vector<int> d;
CreateNode27(d);
Node source(s);
Node dest(d);
source.Display();
dest.Display();
Search search(&source);
search.Find( & dest);
search.DisplayRoute();
return 0;
}
Node函数:
#include <iostream>
#include <math.h>
#include "Node.h"
bool IsOpposite(OP opa, OP opb)
{
if (LEFT==opa && RIGHT == opb)
return true;
if (RIGHT==opa && LEFT == opb)
return true;
if (UP==opa && DOWN == opb)
return true;
if (DOWN==opa && UP == opb)
return true;
return false;
}
Node::Node(std::vector<int> const& state)
: m_state(state)
, m_pParent(NULL)
, m_children()
, m_op(EMPTY)
{
}
void ShowOP(OP op)
{
switch (op)
{
case EMPTY:
std::cout << "EMPTY";
break;
case UP:
std::cout << "UP";
break;
case DOWN:
std::cout << "DOWN";
break;
case LEFT:
std::cout << "LEFT";
break;
case RIGHT:
std::cout << "RIGHT";
break;
default:
exit(-1);
}
}
void ShowOPs(std::vector<OP> const& ops)
{
for (int id=0; id<ops.size(); ++id)
{
ShowOP(ops[id]);
std::cout << " ";
}
std::cout << std::endl;
}
bool Node::Expand(Node const& destNode, Search& search)
{
int spaceId = FindEmptySpaceId();
std::cout << "space is at " << spaceId << std::endl;
std::vector<OP> legalOPs = GenerateLegalOperators(spaceId);
ShowOPs(legalOPs);
while ( legalOPs.size() > 0 )
{
OP op = legalOPs[ legalOPs.size() - 1 ];
legalOPs.pop_back();
Node* pChild = CreateChild(op);
if ( *pChild == destNode )
{
search.SetDestPt(pChild);
return true;
}
search.GetQueue().EnQueue(pChild);
}
return false;
}
void Node::Display() const
{
for(int i=0; i<m_state.size(); ++i)
{
std::cout << m_state[i] << " ";
}
std::cout << std::endl;
std::cout << " pParent: " << m_pParent << std::endl;
std::cout << " op: ";
ShowOP(m_op);
std::cout << std::endl;
std::cout << " ";
for(int j=0; j<m_children.size(); ++j)
{
std::cout << m_children[j] << " ";
}
std::cout << std::endl;
}
void Node::DisplayRoute() const
{
std::vector<OP> routeOps;
Node const* pNode = this;
while ( NULL != pNode )
{
routeOps.push_back(pNode->m_op);
pNode = pNode->m_pParent;
}
for(int id=routeOps.size()-2; id>=0 ; --id)
{
ShowOP( routeOps[id] );
std::cout << " ";
}
std::cout << std::endl;
}
bool Node::operator==(Node const& v) const
{
for (int id=0; id<m_state.size(); ++ id)
{
if ( m_state[id] != v.m_state[id] )
return false;
}
return true;
}
Node* Node::CreateChild(OP op)
{
std::vector<int> childState = m_state;
int exchangePos1 = FindEmptySpaceId();
int exchangePos2 = CalIdBasedOP(op, exchangePos1);
int temp = childState[exchangePos1];
childState[exchangePos1] = childState[exchangePos2];
childState[exchangePos2] = temp;
Node* child = new Node(childState);
child->m_pParent = this;
child->m_op = op;
m_children.push_back(child);
return child;
}
int Node::FindEmptySpaceId() const
{
for (int id=0; id<m_state.size(); ++id)
{
if ( 0 == m_state[id] )
{
return id;
}
}
return -1;
}
std::vector<OP> Node::GenerateLegalOperators(int spaceId) const
{
std::vector<OP> allPossibleOps;
allPossibleOps.push_back(UP);
allPossibleOps.push_back(DOWN);
allPossibleOps.push_back(LEFT);
allPossibleOps.push_back(RIGHT);
std::vector<OP> ops;
for (int id=0; id<allPossibleOps.size(); ++id)
{
OP op = allPossibleOps[id];
if( IsOpposite(op, m_op) )
{
continue;
}
if ( IsWithinRange(op, spaceId) )
{
ops.push_back(op);
}
}
return ops;
}
int Node::CalIdBasedOP(OP op, int spaceId) const
{
switch (op)
{
case UP:
spaceId -= int( sqrt( m_state.size() ) );
break;
case DOWN:
spaceId += int( sqrt( m_state.size() ) );
break;
case LEFT:
--spaceId;
break;
case RIGHT:
++spaceId;
break;
default:
return -1;
}
return spaceId;
}
bool Node::IsWithinRange(OP op, int spaceId) const
{
spaceId = CalIdBasedOP(op, spaceId);
if (spaceId >= 0 && spaceId < m_state.size())
{
return true;
}
return false;
}
Queue函数:#include "Queue.h"
void Queue::EnQueue(Node* pNode)
{
m_queue.push_back(pNode);
}
Node* Queue::DeQueue()
{
if ( m_queue.size() == 0 )
{
return NULL;
}
Node* pNode = m_queue[0];
m_queue.pop_front();
return pNode;
}
Search函数:
#include "Search.h"
#include "Node.h"
Search::Search(Node* root)
: m_queue()
, m_pDestNode( NULL )
{
m_queue.EnQueue(root);
}
Node* Search::Select()
{
return m_queue.DeQueue();
}
void Search::Find(Node* destNode)
{
bool isFound = false;
while ( !isFound )
{
Node* pNode = Select();
pNode->Display();
isFound = pNode->Expand(*destNode, *this);
}
}
void Search::DisplayRoute() const
{
m_pDestNode->DisplayRoute();
}
Heard files:
Node:#ifndef PROGECT_1_NODE
#define PROGECT_1_NODE
#include <vector>
#include "Search.h"
enum OP
{
EMPTY,
UP,
DOWN,
LEFT,
RIGHT
};
bool IsOpposite(OP opa, OP opb);
class Node
{
public:
Node(std::vector<int> const& state);
bool Expand(Node const& destNode, Search& search);
void Display() const;
void DisplayRoute() const;
bool operator==(Node const& v) const;
private:
Node* CreateChild(OP op);
int FindEmptySpaceId() const;
std::vector<OP> GenerateLegalOperators(int spaceId) const;
int CalIdBasedOP(OP op, int spaceId) const;
bool IsWithinRange(OP op, int spaceId) const;
std::vector<int> m_state;
Node *m_pParent;
std::vector<Node*> m_children;
OP m_op;
};
#endif // PROGECT_1_NODE
Queue:
#ifndef PROGECT_1_QUEUE
#define PROGECT_1_QUEUE
#include <deque>
class Node;
class Queue
{
public:
void EnQueue(Node* pNode);
Node* DeQueue();
private:
std::deque<Node*> m_queue;
};
#endif // PROGECT_1_QUEUE
Search:#ifndef PROGECT_1_SEARCH
#define PROGECT_1_SEARCH
class Node;
class Search
{
public:
Search(Node* root);
Queue& GetQueue()
{
return m_queue;
}
void Find(Node* destNode);
Node* Select();
void SetDestPt(Node* pDestNode)
{
m_pDestNode = pDestNode;
}
void DisplayRoute() const;
private:
Queue m_queue;
Node* m_pDestNode;
};
#endif // PROGECT_1_SEARCH
Tree:
#ifndef PROGECT_1_TREE
#define PROGECT_1_TREE
#endif // PROGECT_1_TREE
五、实验过程原始记录( 测试数据、图表、计算等)
六、实验结果、分析和结论(误差分析与数据处理、成果总结等。其中,绘制曲线图时必须用计算纸或程序运行结果、改进、收获)
通过本次试验,我对于宽度优先算法的内涵有了一定的了解;通过仔细研读老师给的程序,我对于其中大部分程序代码都有了较为全面的认知;但是部分代码,还是难以理解。
这个实验还可以推广到其他很多的方面,例如:只要是初态进行变化,寻找末态的;都能通过宽度优先算法来实现。
注:教师必须按照上述各项内容严格要求,认真批改和评定学生成绩。
人工智能九宫格重移搜索成员赵春杰20xx210665羊森20xx210653黄鑫20xx210周成兵20xx210664王素娟20…
人工智能课程实验指导书实验内容实验一产生式系统实验实验二移动机器人的路径规划与行为决策实验实验三梵塔问题实验实验四A算法实验实验五…
华北电力大学实验报告实验名称课程名称人工智能及应用专业班级学生姓名号成绩指导教师李继荣实验日期20xx5学华北电力大学实验报告华北…
人工智能第二次实验报告一实验题目遗传算法的设计与实现二实验目的通过人工智能课程的学习熟悉遗传算法的简单应用三实验内容用遗传算法求解…
人工智能技术实验报告实验名称人工智能实验1姓名班级指导教师完成时间20xx04301读程序指出运行结果domainsssymbol…
计算机科学与技术系C语言实验报告实验名称:指针及其应用日期:得分:指导老师:专业:班次:姓名:学号:实验目的(1)掌握变量的指针及…
学生实验报告实验课名称数组函数综合实验实验项目名称数组函数综合实验专业名称测控技术与仪器班学级20xx240801号20xx240…
学生实验报告学院软件与通信工程学院课程名称C语言与程序设计专业班级通信121姓名学号学生实验报告4一实验综述1实验目的及要求1一维…
北京联合大学信息学院程序设计基础课程调研研究报告题目姓名学号专业计算机科学与技术编制时间20xx528版本指导教师北京联合大学信息…
人工智能导论上机实验指导书基于人工智能的状态空间搜索策略研究八数码问题求解一实验软件TC20或VC60编程语言或其它编程语言二实验…