《人工智能基础》实验报告实验名称数独游戏设计与实现Word文档格式.docx
- 文档编号:6197776
- 上传时间:2023-05-06
- 格式:DOCX
- 页数:23
- 大小:271.60KB
《人工智能基础》实验报告实验名称数独游戏设计与实现Word文档格式.docx
《《人工智能基础》实验报告实验名称数独游戏设计与实现Word文档格式.docx》由会员分享,可在线阅读,更多相关《《人工智能基础》实验报告实验名称数独游戏设计与实现Word文档格式.docx(23页珍藏版)》请在冰点文库上搜索。
SudokuDlg类:
程序的界面类。
Solve类:
实现数独题目求解功能。
Make类:
实现数独题目出题功能。
Pre类:
对数据进行预处理。
3.4界面设计
3.5算法设计
3.5.1数独求解算法
解决该数独求解问题时的要考虑的主要方面有:
①判断题目合法性,即验证给出数据本身是否符合游戏规则,行、列以及小九宫中从不重复地出现数字1-9;
②采用递推算法,若可以填入数字则填入数字,并入栈以便回溯,否则回溯至前面填入数字处重新填数;
③所有空白处都要填满数据;
其中,最重要的就是如何通过递推算法填入正确的数字,或者通过回溯算法重新填入数字并得到最终解,这是本算法的核心内容。
回溯法是解决数独问题的有效方法,有着较快的解题速度。
然而一般的常用的回溯算法仍然有不足之处,比如会进行重复的运算。
所以在采用回溯法之前,还可以利用一点小技巧,以缩短回溯算法的运行时间,甚至可将运行时间缩短接近于0。
这个小技巧即在回溯算法的基础上,采用有限递推算法进行预处理。
算法活动图如下:
3.5.1数独出题算法
要想设计一个算法用以生成各种难度等级的数独题,通过对游戏规则的分析,首先从三个方面定义难度等级,分别是已知格总数、已知格的分布和穷举搜索复杂度。
本算法采用“挖洞”思想,经过以下步骤生成数独题:
①用随机算法生成一个数独题目;
②用求解算法生成终盘;
③根据难度挖去部分数字;
整个生成数独题的算法分为两步执行:
先利用拉斯维加斯随机算法随机生成一个填满数字且符合游戏规则的终盘;
而后根据所需求的难度等级抹去一些数字,难度等级由随机数出现的概率来决定。
4系统实现
4.1开发平台
本项目基于VisualStudio2010平台的MFC,采用C++语言进行开发与测试。
4.2运行环境
本项目可在各个版本的Win7系统或者WindowsXP系统下运行。
4.3数据结构
数据结构是计算机存储、组织数据的方式。
通常情况下,精心选择的数据结构可以带来拥有更高的运行或存储效率的算法。
一般认为,一个数据结构是由数据元素依据某种逻辑联系组织起来的,对数据元素间逻辑关系的描述称为数据的逻辑结构;
数据必须在计算机内存储,数据的存储结构是数据结构的实现形式,是其在计算机内的表示。
数独从形式上看是一个方阵,十分适合用数组来表示。
4.3.1主要数组
本项目中所用到的主要数组有:
①intsudoku[82]
该数组的用途是存储题目以及保存最终结果,所有的9×
9个数字被依次存储在该数组中,空白处则初始化为0。
之所以把数组范围设计成82而不是81,是为了程序的易读性,使得数组元素的最大下标可达81,下同。
②intfix[82]
该数组的用途是若sudoku数组中某位置的数字不为空,则fix数组相应位置的元素值为1,否则为0,即fix数组是用来记录哪些位置的数字是已经确定下来的。
③intpossible[82][10]
该数组的用途是记录所有未确定数字的所有可能性,possible数组各元素的值在初始化时被初始化为与其第二维的下标一致,即0-9(其中0表示空值);
在中间计算过程中,若发现第一维某位置的某种可能性已不复存在,则将第一维下标是该位置而第二维下标是该不再可能的数字的元素值改为-1。
④intreview[82]
该数组的用途类似于栈,在回溯算法过程中起到至关重要的作用。
回溯之前,要把所有fix数组中值为0的位置依次存放进review数组;
回溯中,由低到高依次逐渐确定这些位置的数值,无法确定者(即1-9的数字都不适合者)则应当回退到前一个位置,并修改其fix数组中的值,依次类推,直至review数组所存放的所有位置的值都能确定(即题目完成),或回退到最初点的前一个位置(即题目有误)。
4.3.2相关函数
本项目中为实现算法的数据结构所用到的主要函数如下:
①voidsetPossible()
该函数是用来设置possible数组中元素的值,其具体功能是:
对于fix数组中每一个值为0的位置(即对于每一个没有确定下数字的位置),考察其可能的数字是哪些,并记录下来。
考察的方法是:
在1-9这些数字中除去在当前行、列、九宫中已有的数字,剩下的即为可能的取值对象。
②boolfixPossible()
该函数是用来修改fix数组和possible数组中元素的值,其返回值表示了在此次运行该函数过程中是否执行了修改。
其具体功能是:
对于fix数组中每一个值为0的位置(即对于每一个没有确定下数字的位置),考察其可能的数字的个数,若为1,则将fix数组该位置的值改为1且sudoku数组该位置的值改为该唯一可能的数字(即该位置的值已确定下来),且返回真;
若没有只有一种可能性的位置,则返回假。
③boolisExist(inti,intj)
该函数用于回溯过程中,其用途是:
判断sudoku数组中位置为i的元素的值是否可能为j,即判断的是位置i所在的行、列以及九宫中是否已经存在数字j,若存在则返回真,否则返回假。
4.4求解算法实现
4.4.1有限递推
在执行一次fixPossible函数之后,就可能会确定下一些原来没有确定的数字,那么此时possible数组的值必然也会变动。
这是因为确定下的数字越多,某些位置的可能数字的数目就会减少,那么此时就应再执行setPossible函数修改possible数组。
而修改之后可能又会出现一些只有一种可能性的位置,那么就应该再执行fixPossible函数。
于是,只要如此循环往复下去,就能最大限度地确定下根据题目本身含义和规则而确定下的内容。
确定的数字越多,对于将来回溯也就越有利。
经验表明,有些数独题直接就可以通过执行大约10多次的有限递推循环体解决。
一般情况下,有限递推的循环结束只有两种情况:
一是推出了全部结果;
二是fixPossible函数返回值为假,即不存在只有一种可能性的位置。
预处理的主要代码见附录。
4.4.2回溯
回溯是数独求解算法中最为关键的部分,其主要步骤是:
①按下标的由低到高扫描fix数组,将值为0的位置记录进review数组,记录的顺序也是由低到高,最后记录下fix数组中为0位置的个数再加1;
②把review数组看作栈,记录栈顶;
③先设置一个bool型标志变量flag并初始化为true,下面各步骤都将在一个条件始终为真的死循环中进行,该循环由一条对flag进行真假判断的语句分成两大部分。
若当前栈顶是经过了回退操作而达到的,则flag会已被记录为false;
否则flag为true。
死循环结束的条件是review数组(栈)中top与max的值相等,即解出最终结果,或者是无解,最终top小于0。
在死循环中,若flag为true,则进入步骤④,否则进入步骤⑤。
④若flag为true,则说明栈顶是经过正常的假设而达到的,并非由回退达到,那么根据possible数组以及isExist函数对栈顶所保存位置的可能出现的数字进行判断,把遇到的第一个可能数字放进sudoku数组,并把fix数组的该位置的值设为1,并判断是否已经解出结果,即review数组(栈)中top和max的值是否相等。
若相等,则得出结果并退出死循环;
若发现1-9都不可能应用在栈顶所保存的位置,则说明前面的假设有错误,此时应当回退。
即fix数组和sudoku数组的该位置重设为0,top减1,并将flag的值设为false。
然后结束本轮循环体,继续下一轮的循环。
⑤若flag为false,说明是经过了回退才达到现在这个栈顶的,那么若仍然没有可能的数字可以应用在当前栈顶所保存的位置上,则继续执行出栈操作,即fix数组和sudoku数组的该位置的值重设为0,top减1;
否则将遇到的第一个可能数字应用到该位置,即再设好sudoku数组和fix数组,将top加1,并将flag的值设为true。
回溯的主要代码见附录。
4.5出题算法实现
4.5.1生成终盘
数独出题时要先采用拉斯维加斯算法随机生成一个数独题的终盘。
首先,在一个数独空盘中随机选中n个格子,在这些格子内随机填人数字1-9;
然后,调用数独求解算法对这个已知n格的数独题S(n)进行求解。
如果S(n)有解,则返回true,否则返回false。
拉斯维加斯算法的思想便是不断重复执行上述步骤,直至其返回值为true为止。
生成随机数的主要代码见附录。
4.5.2挖洞算法
挖洞算法的基本思想就是挖去一个数独终盘上的一些格子,使其成为有唯一解的数独题目。
然而挖洞的机制是多种多样的,本项目为了加快出题算法的速度,利用不同的随机挖洞概率来区分不同的难度。
挖洞的主要代码见附录。
4.6程序运行截图
开始:
数独求解,手动输入题目:
数独求解,读取保存的题目:
解出答案:
数独出题,选择难度:
得出题目:
保存题目:
保存和打开题目的文件格式:
5测试
5.1解题测试
选取5个难度共25道不同的数独题目进行解题测试,记录程序运行时间,检验运算结果是否正确,并对实验结果进行分析。
难度1:
题目
1
2
3
4
5
Average
时间
14ms
13ms
22ms
20ms
18.2ms
结果
正确
-
难度2:
21ms
33ms
23.0ms
难度3:
26ms
25ms
23ms
24.4ms
难度4:
28ms
24ms
35ms
29ms
28.4ms
难度5:
50ms
44ms
34.6ms
通过对实验数据的分析可知:
①本算法得出的结果全部正确,说明本算法成功实现了通过计算机人工智能方法对数独问题求解;
②随着题目难度加大,平均运行时间逐渐加长;
③本次试验中,运行时间最长的题目不超过50ms,大多数题目在20-30ms内完成,说明本算法的运行速度是比较快捷的。
5.2出题测试
5个难度各进行5次数独出题运算,记录运行时间,并比较得出的题目是否会有重复。
9ms
10ms
6ms
7ms
8.2ms
重复
无
8ms
5ms
7.6ms
11ms
8.8ms
①本此实验中,各组均无重复的题目出现,说明本算法成功实现了通过计算机人工智能方法对数独问题的出题;
②程序的运行时间不随难度增加而加长,个难度的运行时间基本一样;
③运行时间基本维持着8-9ms左右,说明本算法的运行速度是比较快捷的。
6工作总结
①较好地完成了数独求解和数独出题的算法的设计与实现;
②对算法进行功能测试,验证了算法的有效性,并证明了算法具有良好的时间效率;
③实现了良好的用户界面;
④实现了数独题目的读取和保存功能;
⑤通过本项目,对人工智能技术有了进一步的了解,并初步掌握了MFC编程;
⑥锻炼了团队合作能力。
7项目安排
任务
负责人
项目建议书
王郑合、文宽、栾杰
9.19-9.30
数独求解功能
王郑合、栾杰
10.1-10.21
数独出题功能
王郑合、文宽
测试
栾杰
10.22-10.23
中期进展报告
10.24-10.28
界面
文宽
10.29-11.4
功能集成
王郑合
11.5-11.9
测试与改进
文宽、栾杰
11.10-11.20
11.21-11.25
参考文献
[1]刘晓宝.数独游戏的解题算法[J].电脑编程技巧与维护,2007,(5):
64-67.
[2]严蔚敏,吴伟民.数据结构[M].第二版.北京:
清华大学出版社,1993:
93-95,43-45,220-221.
[3]StanleyBLippman,JoseeLajoie著,潘爱民等译.C++Primer(第三版)[M].中国电力出版社,2002.
[4]王晓东.算法设计与分析[M].第一版.清华大学出版社,2003.
[5]王万良.人工智能及其应用[M].第二版.高等教育出版社,2008.
附录
预处理算法的主要代码:
while
(1)
{
setPossible();
if(!
fixPossible(sudoku,fix,possible))//即不存在只有一种可能性的位置
break;
if(isFull(sudoku))//若已推出全部结果
}
if(isFull(sudoku))
printAll();
//输出结果
回溯算法的主要代码:
if(isFull(sudoku))
returntrue;
inttop=0;
//所有值为0的位置入栈
for(inti=1;
i<
82;
i++)
{
if(fix[i]==0)
review[top++]=i;
intmax=top;
//记录最大数加1
top=0;
//指向栈顶
inttemp;
boolflag=true;
//是否正常入栈的标志
while
(1)
assert(top>
=0);
//宏定义,用于调试程序
if(flag)
{
intj;
for(j=1;
j<
=9;
j++)
{
if(possible[review[top]][j]!
=-1&
&
!
isExist(review[top],j))
{
fix[review[top]]=1;
sudoku[review[top]]=j;
toRead(review[top]);
//实现read[line][row]与sudoku[i]同步
++top;
if(top>
=max)
return1;
break;
}
}
if(j>
9)//若该位置所有可能值都不成立,则回退一格
{
--top;
if(top<
0)
printAll();
return0;
flag=false;
}
else
if(sudoku[review[top]]==9)//若当前位置的top也没有可以选择的值,则继续回退
fix[review[top]]=0;
sudoku[review[top]]=0;
toRead(review[top]);
else
temp=sudoku[review[top]];
temp++;
while(possible[review[top]][temp]==-1||isExist(review[top],temp))
temp++;
if(temp>
9)
break;
if(temp>
9)//当前节点没有更换的可能,继续回退
fix[review[top]]=0;
sudoku[review[top]]=0;
--top;
if(top<
{
printAll();
return0;
}
else
sudoku[review[top]]=temp;
flag=true;
//重新设置flag的值
生成随机数算法的主要代码:
inti,j,r;
boolchange=true;
inttemp[10]={0,0,0,0,0,0,0,0,0,0};
for(i=1;
)
change=true;
j=1+rand()%9;
for(r=1;
r<
r++)
if(temp[r]==j)
change=false;
if(change==true)
temp[i]=j;
i++;
}
sudoku[i]=temp[i];
toRead(i);
挖洞算法的主要代码:
inti,f;
do
f=getch()-48;
}while(f>
5||f<
1);
//共5个难度
=81;
if(rand()%6>
=f)//利用随机数出现的概率出题
printf("
%4d"
sudoku[i]);
0"
);
if(i%9==0)
\n\n"
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 人工智能基础 人工智能 基础 实验 报告 名称 游戏 设计 实现