一、目标与要求
基本要求
1、程序的用户作为玩者的角色,计算机是猜者的角色。
2、程序保存了一个基本问题的知识,每一个问题让它减少考虑中的动物数。当程序已经减少它的考虑到仅一只动物,它就猜这个动物。假如猜者是对的,程序赢了,否则,程序问玩者想的动物名字。然后,问如何区分新的动物和所猜的动物。它保存这个问题并且储存这个新的动物在下一次玩的游戏的基本知识中。
3、每一次学到的新动物的特征,就被这个程序加入到基本知识中。随着时间的流逝,程序的基本知识在增长,玩者想出不在基本知识中的动物变得越来越难—这个程序在猜动物时变成一位专家。在某些领域通过用一些基本知识来陈述专家见解的程序叫做专家系统,并且这个系统的研究是人工智能的一个分支。尽管大部分专家系统使用程序不能修改的固定知识,动物游戏的程序是一个特殊的自学习专家系统的例子,因为当它们遇见新的情况时就增加新的动物到基本知识里。这个改变基本知识的能力,使得动物程序能模仿学习的过程。
二、工具/准备工作
复习数据结构与算法课程的查找的相关内容、文本编辑功能,实现文本的读取和编写、建立二叉树的相关知识等数据查找结构,对问题进行分析需要采取什么数据结构对动物信息存储,根据相关关键词查找具有该特征的动物,画出二叉树结构树;以哺乳动物为根结点,左孩子指针为“是”,右孩子为“否”,第二个关键字为“是否会飞。共四种情况,分别下图所示:
三、实验分析
分析算法设计方法,类结构与主要算法实现原理等内容。
1、首先要建立数据结构存储信息。建立树类BinaryTree、树节点类BinaryTreeNode,左右孩子指针LeftChild、Rightchild,用于存储动物具体信息,根节点储存关键字,“”是“则选择左节点,“否”则选择右节点
2、建立文本文件“知识库.txt”,用于动物学习专家来读取相关信息。通过对文本文件“知识库.txt”进行读取,动物游戏专家就可以轻易的掌握固定的知识,根据动物游戏专家的知识可以完成简单的猜动物游戏。
3、 将专家从知识库中读取的信息,根据前序遍历的方式存储在队列中,进行查找操作
4. 进行猜动物游戏,玩家想一个动物,与专家进行游戏,
举例:
若玩家想的是“猪”,选择是哺乳动物(1号关键字选择“是”)、不会飞的动物(2号关键字选择“否”),则专家可以猜出答案“猪”。
若玩家想的动物是哺乳动物、会飞的动物:“飞猪”,那么专家将无法得到正确的答案,此时则需要玩家输入“动物名称、动物特征”,飞猪,哺乳动物、会飞的则专家将更新信息,将蝙蝠改为“飞猪”;
5. 玩家可以继续上述的3过程,直到不再游戏,选择“否”。
四、实验步骤
详细介绍实验操作步骤。
1、建立数据结构二叉树及其结点类
class BinaryTree;//树类
class BinaryTreeNode;//树节点类
class BinaryTreeNode
{
friend class BinaryTree;
public:
BinaryTreeNode() { L = NULL; R = NULL; }//构造函数,构造根结点
BinaryTreeNode(string &an, BinaryTreeNode *l = NULL, BinaryTreeNode *r = NULL);
//分支结点构造函数,主要使用这个
void GetAn(string & data)const { data=Data; }
void release();
protected:
string Data; //所有数据
BinaryTreeNode * L; //左孩子指针
BinaryTreeNode * R; //右孩子指针
};
class BinaryTree
{
public:
BinaryTree() { T = NULL; } //构造函数
BinaryTree(BinaryTreeNode*P) { T =P; }
~BinaryTree(); //析构函数
void readfile(); //专家读取“知识库”中的资料
void writefile(); //写入专家的“知识库”中
void queuetotree(BinaryTreeNode**);//将队列中的内容以前序遍历生成二叉树
void treetoqueue(BinaryTreeNode*); //将二叉树中的内容以前序遍历存入队列
void expert(BinaryTreeNode*); //专家提问和推测 玩家回答
protected:
BinaryTreeNode *T;
};
2、建立文本文件“知识库.txt”,将相关的动物特征和动物名称输入进入保存,
3、建立动物游戏专家,
① 专家猜出正确答案,动物游戏专家胜利
② 专家未能猜出正确答案,玩家胜利,专家开始学习功能(更新数据)
void BinaryTree::expert(BinaryTreeNode *T)//专家提问和推测 玩家回答
{
string str1="是",str2="否",str3,str4,str5;
while(1)
{
BinaryTreeNode *N;
N=T;
while(1)
{
cout<<"是否"<<N->Data<<"?"<<endl;
cin>>str3;
if(N->L==NULL&&N->R==NULL)
{ if(str3==str1)
{
cout<<"专家已猜出结果,是否再来一次?"<<endl;
cin>>str3;
break;
}
else if(str3==str2) //没有猜到玩家的答案,专家学习系统自动更新功能
{
cout<<endl;
cout<<"专家没有猜出,快快告诉它动物名称特征" <<endl;
cout<<"动物名称"<<endl;
cin>>str4;
cout<<"相关特征"<<endl;
cin>>str5;
BinaryTreeNode *X,*Y;
X = new BinaryTreeNode;
Y = new BinaryTreeNode;
X->L=X->R=Y->L=Y->R=NULL;
N->L=X;
N->R=Y;
Y->Data=N->Data;
N->Data=str5;
X->Data=str4;
cout<<"上一次失误,要再来一次嘛?"<<endl;
cin>>str3;
break;
}
else
{
cout<<"别输入“奇怪字符”专家会下线,请重新输入。"<<endl;
}
}
else
{
if(str3==str1) //如果回答“是”则选择左孩子指针
{
N=N->L;
}
else if(str3==str2) //如果回答“否”则选择左孩子指针
{
N=N->R;
}
else
{
cout<<"别输入“奇怪字符”专家会下线,请重新输入。"<<endl;
//输入不正确的字符,
}
}
}
if(str3==str2) break; //如果输入“否”游戏结束,程序结束
}
}
五、测试与结论
1、调试程序,检测程序是否能够正常运行
如下图所示:
程序运行正常,动物学习专家系统正常,经过调试:1号关键字选择“是”,2号关键字选择“是”,专家猜出答案“蝙蝠”,专家胜利、玩家失败
2、测试程序二叉树结构,检查“LL、LR、RL、RR”二叉树的叶子结点是否能够正确查找
① LL“是是”(左孩子的左孩子结点):哺乳动物且会飞
程序运行正常,专家知识库中哺乳动物会飞的动物为蝙蝠,
② LR“是否”(左孩子的右孩子结点):哺乳动物且不会飞
程序查找过程正确,专家知识库中的哺乳动物不会飞动物为“猪”
③ RL“否是”(右孩子的左孩子结点):不是哺乳动物且会飞
程序查找过程正确,专家知识库中的不是哺乳动物会飞动物为“鸟”
④ RR“否否”(右孩子的右孩子结点):不是哺乳动物且不会飞
程序查找过程正确,专家知识库中的不是哺乳动物不会飞动物为“蛇”
3.检测动物游戏专家的更新功能,即专家未能猜出正确答案,玩家胜利,专家开始学习功能(更新数据)
测试数据:哺乳动物且会飞,但不是蝙蝠为飞猪
在测试中为哺乳动物会飞但非蝙蝠,修改动物特征:
在测试中为哺乳动物会飞但非蝙蝠,修改动物特征:哺乳动物且会飞,为“飞猪”
修改后测试,哺乳动物会飞的不再是蝙蝠而是“飞猪”
结论:动物游戏专家完成数据更新功能,并能根据玩家想法学习,
六、实验总结
借助二叉树结构来查找动物,并通过文本文件编辑的功能借助文本文件来存储专家系统的知识,读取添加文本文件实现动物游戏专家知识的学习更新,综合性的考察了数据结构的灵活使用,对数据结构与算法的综合性认识加深,不同数据结构的使用使得信息的储存、编辑、查找更高效;
不足之处:仅采用了二叉树,设置两个关键字:”是否为哺乳动物,是否会飞”来区分四种动物,数据结构较为简单,在实现三叉树及多叉树的分类中,对相关知识的掌握程度不熟悉,未能实现更多动物种类的区分。
附原程序:
#include <iostream>
#include <queue> //队列类
#include <sstream>
#include <fstream>
#include <string>
using namespace std;
queue<string>q1,q2;
class BinaryTree;//树类
class BinaryTreeNode;//树节点类
class BinaryTreeNode
{
friend class BinaryTree;
public:
BinaryTreeNode() { L = NULL; R = NULL; }//构造函数,构造根结点
BinaryTreeNode(string &an, BinaryTreeNode *l = NULL, BinaryTreeNode *r = NULL);
//分支结点构造函数,主要使用这个
void GetAn(string & data)const { data=Data; }
void release();
protected:
string Data; //所有数据
BinaryTreeNode * L; //左孩子指针
BinaryTreeNode * R; //右孩子指针
};
void BinaryTreeNode::release()
{
if (L != NULL)
{
L->release();
delete L;
L = NULL;
}
if (R != NULL)
{
R->release();
delete R;
R = NULL;
}
}
class BinaryTree
{
public:
BinaryTree() { T = NULL; } //构造函数
BinaryTree(BinaryTreeNode*P) { T =P; }
~BinaryTree(); //析构函数
void readfile();
void queuetotree(BinaryTreeNode**);
void expert(BinaryTreeNode*);
void treetoqueue(BinaryTreeNode*);
void writefile();
protected:
BinaryTreeNode *T;
};
BinaryTree::~BinaryTree()
{
if (T != NULL)
{
T->release();
delete T;
T = NULL;
}
}
void BinaryTree::treetoqueue(BinaryTreeNode*T)//将二叉树中的内容以前序遍历存入队列
{
string str="#";
if (T == NULL)
{
q2.push(str);
return;
}
q2.push(T->Data);
treetoqueue(T->L);
treetoqueue(T->R);
}
void BinaryTree::queuetotree(BinaryTreeNode**T)//将队列中的内容以前序遍历生成二叉树
{
string str1,str2="#";
str1=q1.front();
q1.pop();
if (str1 == str2)
*T = NULL;
else
{
*T = new BinaryTreeNode;
(*T)->Data = str1;
queuetotree(&(*T)->L);
queuetotree(&(*T)->R);
}
}
void BinaryTree::expert(BinaryTreeNode *T)//专家提问和推测 玩家回答
{
string str1="是",str2="否",str3,str4,str5;
while(1)
{
BinaryTreeNode *N;
N=T;
while(1)
{
cout<<"是否"<<N->Data<<"?"<<endl;
cin>>str3;
if(N->L==NULL&&N->R==NULL)
{ if(str3==str1)
{
cout<<"专家猜出结果,玩家失败,是否再来一次?"<<endl;
cin>>str3;
break;
}
else if(str3==str2)//,未能猜出正确答案,专家学习系统自动学习功能
{
cout<<endl;
N->release();
cout<<"专家没有猜出,快快告诉它动物名称和相关特征" <<endl;
cout<<"动物名称"<<endl;
cin>>str4;
cout<<"相关特征"<<endl;
cin>>str5;
BinaryTreeNode *X,*Y;
X = new BinaryTreeNode;
Y = new BinaryTreeNode;
X->L=X->R=Y->L=Y->R=NULL;
N->L=X;
N->R=Y;
Y->Data=N->Data;
N->Data=str5;
X->Data=str4;
cout<<"上一次失误,要再来一次嘛?"<<endl;
cin>>str3;
break;
}
else
{
cout<<"别输入“奇怪字符”专家会下线,请重新输入。"<<endl;
}
}
else
{
if(str3==str1)
{
N=N->L;
}
else if(str3==str2)
{
N=N->R;
}
else
{
cout<<"别输入“奇怪字符”专家会下线,请重新输入。"<<endl;
}
}
}
if(str3==str2) break;
}
}
void BinaryTree::readfile()//读取文件中的内容存入队列
{
std::ifstream fin("知识库.txt", std::ios::in);
char line[1024] = { 0 };
std::string x = "";
while (fin.getline(line, sizeof(line)))
{
std::stringstream word(line);
word >> x;
q1.push(x);
}
fin.clear();
fin.close();
cout<<"专家已上线,准备开始游戏"<<endl<<endl;
}
void BinaryTree::writefile()//将队列的内容存入文件中
{
int a;
a=q2.size();
ofstream f("知识库.txt ",ios::trunc);
f.close();
ofstream ofresult( "知识库.txt ",ios::app);
for(int i=0;i<a;i++)
{
ofresult<<q2.front()<<endl;
q2.pop();
}
//cout<<"录入成功"<<endl;
}
void main()
{
cout<<"动物学习专家系统"<<endl;
BinaryTreeNode* P=NULL;
BinaryTree tree(P);
tree.readfile();//专家读取“知识库”中的资料
tree.queuetotree(&P);//将队列中的内容以前序遍历生成二叉树
tree.expert(P); //专家提问和推测 玩家回答
tree.treetoqueue(P);//将二叉树中的内容以前序遍历存入队列
tree.writefile(); //写入专家的“知识库”中
}
嘿!被我逮到你了吧。
给小编点个赞呗!