沈阳工业大学人工智能实验报告

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

人工智能实验报告
报告名称:人机对弈五子棋的设计与实现学院:软件学院
专业班级:软件1001班
组别:第一组
小组成员:
目录
第1章项目背景 (2)
第2章项目任务书 (3)
第3章相关技术综述 (4)
第4章人机对弈五子棋的设计与实现 (5)
第5章总结 (11)
参考文献 (12)
附录 (13)
第1章项目背景
人工智能是近年来很活跃的研究领域之一,计算机博弈是人工智能研究的一个重要分支,它的研究为人工智能带来了很多重要的方法和理论,产生了广泛的社会影响和学术影响
五子棋是起源于中国古代的传统黑白棋种之一。

现代五子棋日文称之为“連珠”,英译为“Renju”,英文称之为“Gobang”或“FIR”(FiveinaRow的缩写),亦有“连五子”、“五子连”、“串珠”、“五目”、“五目碰”、“五格”等多种称谓。

五子棋不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。

五子棋既有现代休闲的明显特征“短、平、快”,又有古典哲学的高深学问“阴阳易理”;它既有简单易学的特性,为人民群众所喜闻乐见,又有深奥的技巧和高水平的国际性比赛;它的棋文化源渊流长,具有东方的神秘和西方的直观;既有“场”的概念,亦有“点”的连接。

它是中西文化的交流点,是古今哲理的结晶。

五子棋作为一个棋类竞技运动,在民间十分流行,这款游戏集趣味性、娱乐性、互动性和益智性于一体,已经成为多数人群的休闲方式。

五子棋是当前非常流行的一种棋类游戏,它在我国的历史可谓是源远流长,它不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。

目前网络上有很多五子棋子游戏,玩法简单,娱乐性也很高。

五子棋不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。

通过对五子棋的设计与开发,了解和掌握游戏开发的原理与方法。

让电脑像人脑一样思考,一直是人工智能发展的最终目标。

作为一门边缘学科,它有诸多的研究领域,博弈即为其中之一。

博弈的参加者可以是个人、集体、某种生物或机器,他们都力图用自己的“智力”去击败对手。

博弈为人工智能提供了一个极好的试验场所,人工智能中的许多概念和方法都是从博弈程序中提炼出来的,人工智能中大多以下棋为例来研究博弈规律。

本文以五子棋为入口,设计了一个五子棋人机对弈系统,以实现人和计算机的博弈,最终的目的是为了建立一个有具体规则的五子棋平台。

完成这个项目的研究,需要学生应该熟悉五子棋规则及技巧,并研究简单的人工智能,课题选用C++开发五子棋游戏,主要完成了人与电脑对战的功能。

在人机对弈中通过深度搜索和估值,来提高电脑棋手的智能。

分析估值中的影响精准性的几个要素,以及对它们搜索的节点数进行比较,在这些算法的基础上分析一些提高电脑的胜率。

算法的研究有助于理解程序结构,增强逻辑思维能力,在其他人工智能方面也有很大的参考作用。

第2章项目任务书
(1) 班级:软件1001班
(2) 组长:
(3) 成员:
(4) 项目名称:人机对弈五子棋
(5) 项目分工:
(7) 项目进度:1-2天:前期准备,各类资料收集,流程图,算法
等同时完成。

3-5天:实现基本功能和附加功能。

6-7天:最后测试,最后优化。

(各类文档的设计
与编写穿插于始终)
(8)拟完成时间:2012年11月9日
第3章相关技术综述
3.1 五子棋规则概述
五子棋是一种两人对弈的纯策略型棋类游戏,棋具与围棋通用,是起源于中国古代的传统黑白棋种之一。

传统五子棋的棋具与围棋大致相同,棋子分为黑白两色,棋盘为15×15,棋子放置于棋盘线交叉点上。

两人对局,各执一色,轮流下一子,先将横、竖或斜线的5个或5个以上同色棋子连成不间断的一排者为胜。

五子棋是黑白双方或两个人之间的竞技活动,由于对黑白双方规则不同,黑棋必须先行。

一般采用猜先的方法来决定谁执黑先行,即双方各抓一种颜色的几枚棋子,大数减小数,单数双方交换,偶数不换;黑方在落下关键的第五子即形成五连的同时,如又形成禁手,此时因黑方已经成五,而“五”在五子棋中是至高无上的,故禁手失效,黑方胜;所谓黑方形成禁手,是指黑方落下一子同时形成两个或两个以上的活三、冲四及长连等。

此时白方应立即指出,自然而胜。

专业连珠五子棋虽然对黑棋采取了种种限制,但是黑棋先行的优势依然很大。

因此,在高段位的专业比赛中,又出现了三种特殊的规定:(1)“指定打法”:指比赛双方按照约定好的开局进行对弈。

例如“斜月局”、“长星局”等。

(2)“三手可交换”:指黑棋下第二手棋〔盘面第三手棋〕之后,白方如感觉黑方棋形不利于己方,可提出交换,即执白棋一方变为执黑棋一方〔此方法不适用于指定开局打法,而用于随意开局〕。

采用此规定以后,黑棋就不会再使用诸如“浦月”、“花月”之类的必胜开局了。

(3)“五手两打”:指黑棋在下盘面上关键的第五手棋时,必须下两步棋,让白方在这两步棋中任选一步,然后再继续下。

采用这一系列规定以后,黑棋先行就再无优势可言。

3.2 开发及运行环境
本项目的代码完全用C++语言编写,是在DEV C++ 5下完成编写,编译,运行及调试。

3.2.1 DEV C++ 简介
Dev-C++是一个Windows环境下C&C++开发工具,它是一款自由软件,遵守GPL协议。

它集合了GCC、MinGW32等众多自由软件,并且可以取得最新版本的各种工具支持,而这一切工作都是来自全球的狂热者所做的工作,并且你拥有对这一切工具自由使用的权利,包括取得源代码等,前提是你也必须遵守GNU协议。

Dev-C++每一天都在进步着,因为它是一个自由软件。

Dev-C++是一个非常实用的编程软件,多款著名软件均由它编写而成,它在C的基础上,增强了逻辑性。

Dev-C++使用MingW32/GCC编译器,遵循C/C++标准。

开发环境包括多页面窗口、工程编辑器以及调试器等,在工程编辑器中集合了编辑器、编译器、连接程序和执行程序,提供高亮度语法显示的,以减少编辑错误,还有完善的调试功能,能够适合初学者与编程高手的不同需求,是学习C或C++的首选开发工具!多国语言版中包含简繁体中文语言界面及技巧提示,还有英语、俄语、法语、德语、意大利语等二十多个国家和地区语言提供选择。

该软件采用 Delphi 开发。

3.2.2 运行环境
Intel®Pentium®2及以上处理器,32M以上内存,4G以上硬盘;
Microsoft®Windows™98/xp/7 操作系统;
800*600或以上的屏幕分辨率。

第4章人机对弈五子棋的设计与实现
4.1项目总体设计
五子棋作为一款休闲益智
游戏,它最大的优点在于游戏规
则家喻户晓,简单,上手快,趣
味性强,所以受广大用户青睐,
在各大提供棋牌类游戏的平台
都可以看到玩五子棋游戏的人
很多。

休闲益智游戏中等级并不
是最重要的追求目标,通过对游
戏规则的熟悉,能很快上手掌握
其操作方式,也更适合男女老幼
全家共同娱乐,花费时间简短,
速战速决,在短时间内感受到游
戏的乐趣,完全享受气氛轻松活
跃的游戏过程。

此种娱乐方式既
不耽误时间也能轻松调剂娱乐,
充分适合现代人们的娱乐需求。

图4-1 系统流程图
更主要的是开发了人的智力,成为年轻一代最流行的游戏,据统计,五子棋游戏的玩家中,学生占了接近三分之一的比例,对学生的智力健康成长起一定作用,正所谓休闲娱乐两不误。

五子棋游戏规则简单,在每次玩家或电脑落棋后,都要去判断是否游戏是否分出胜负,如没有,另一方才能继续下棋。

一局游戏结束后,可以选择再来一盘,这时将棋盘数据清空,又开始新的棋局。

系统流程如图4-1所示。

4.2 功能设计
要求系统界面简洁,操作方便,把五子棋游戏规则中最基本的规则体现出来,比如“和棋”、“重新开局”等。

五子棋还有一大特点就是速战速决,电脑应在很短时间内就应做出判断,并能提供一定的帮助,违反游戏规则的时候应立即指出。

在正规五子棋比赛中,都设置了“禁手”这一规则,但广大玩家之所以喜爱五子棋游戏,就是因为五子棋游戏规则简单,“禁手”这一规则很复杂,所以在本系统中,采用“无禁手”的规则,让规则简单化。

判断胜负是本项目必不可少的一部分,获胜情况分析表如表4-1所示。

棋盘上的情况:获胜所需步数优先级电脑已有任意组活四或已有任意组死四一 1
玩家已有任意组活四或已有任意组死四一 2
电脑已有任意组活三或已有多于一组的死三二 3 玩家已有一组死三和任意组的活二三 4 玩家已有任意组活三或已有多于一组的死三三 5 玩家已有一组死三和任意组的活二三 6
表4-1 获胜情况分析表
4.3 详细设计
4.3.1 棋盘设计
程序的实现上,首先完成界面的设计,在界面的设计上,使用了二维数组的棋盘格式,考虑到五子棋的落子后,是不会再次移动的,所以采用划直线的方法模拟一个棋盘。

棋盘大小为15×15。

在这些都完成了之后,对界
面进行最后的完善,通过添加按
钮来使用户在和电脑对弈的同
时,可以从这些按钮中选择由玩
家先下还是电脑先下。

并添加标
题“软件1001班第一组”。

本系统一共设置了两个按
钮:“玩家先下”、“电脑先下”。

它们的画法采用文本框模拟按
钮,先画一个矩形,在矩形里填
充提示信息,用鼠标单击事件来
响应各个按钮。

因此综上所述,在界面的设
计上,主要有两个模块,一个是
棋盘模块,一个是按钮模块。

界图4-2 界面的设计
面如图4-2所示。

4.3.2 棋盘局势状态表示
要让计算机学会下棋,首先就要把下棋问题表示成计算机可理解的形式,即把五子棋问题形式化,存在计算机中,并能让搜索算法对这些数据进行操作。

需要在计算机中表示的主要问题有棋盘局势状态及落子的顺序等。

棋盘表示主要探讨的是是什么数据结构来表示棋盘上的信息。

一般说来,这与具体的棋类知识密切相关。

通常,用来描述棋盘及其上棋子信息的是一个二维数组。

要让计算机知道棋盘局势状态,就是要它记住棋盘中哪个位置有黑子,哪个位置有白子以及哪个位置是空点。

因为五子棋的棋盘是15行,15列,因此可以将棋盘状态的描述用一个15×15的二维数组表示。

4.3.3具体算法
电脑要选择有利于它的最佳下法,就要能判断哪种形势对它最有利。

但往往对一个形势的判断是很难做到准确的,特别是一盘棋刚开始的时候,棋盘的形势不明朗,即使是专家也不能做出准确的判断。

为了判断哪种下法最有利,我们往往需要向后面计算几步,看看在走了几步棋之后,局面的形势如何。

这被称为“多算胜”,也就是说,谁看得越深远,谁就可以获胜。

具体代码详见附录。

这种思
维方式被用到了计算机上。

向后面计算的步数越多,系统开销就越大,本系统只向后计算一步,根据威胁的优先级来选择落棋的最佳点。

轮到电脑下棋时,电脑先向棋盘搜索合法的落棋点,即棋盘的空白点。

然后再利用下面的算法先择最佳落棋点。

在每个空白点,都有四个方向需要考虑,即横,竖,交叉四个方向。

在设计的时候,尽可能把所有情况全面考虑,设置为搜索一个最佳落棋点位置的时候,需要保证左右展开后碰壁,之间的空间距离至少要有六格(而不是五子),否则就是死子。

4.4 系统测试与分析
4.4.1 运行结果
本系统在DEV C++ 5 下调试通过,调试成功后,打开目录下“第一组五子棋.exe”,开始运行五子棋游戏。

从界面、按钮功能、胜负的判断几个方面来测试系统。

(1)提示界面:本界面显示了本游戏的信息及必要的玩法提示,此界面在运行之前出现,2秒后自动消失,该界面如图4-3所示。

图4-3 初始界面
(2)主界面:该窗口具有最小化,关闭按钮,标题栏,边框,背景色为黑色,棋盘大小为15×15,棋盘线为红色。

由于窗口大小的限制故最大化按钮不起任何作用。

此部分运行结果亦如图4-2所示。

(3)判断胜负:当棋盘上“一”、“∣”、“∕”、“﹨”四个方向有同一种颜色的五颗棋连成同一条直线时,系统会弹出提示消息表示已经分出胜负,并发出提示音。

图4-4与图4-5分别为玩家获胜和电脑获胜的两种情况。

图4-4 玩家获胜
图4-5 电脑获胜
4.4.2 问题的发现与解决
在游戏开始阶段,程序有不少小BUG,每次开始游戏后,玩家落棋后,会在窗口(0,0)位置多显示了一颗棋子,经过后来指参考相关书籍后,解决了问题。

原因在于由于电脑所执的棋子后画,所以就把棋子覆盖了,我们就只看得到一颗棋子了,其实是画了两颗,所以需要在画图函数处,加限制条件,限制它在棋盘外画棋。

另外一个小BUG 就是,系统可能在下棋过程中覆盖存在的棋子,棋盘上数据不为零的点均为已落棋的点,这种点只被搜索,不会被重新赋值,所以在赋值的时候选择最佳落棋点之前,应该对这些点进行限制,就可以解决这个问题。

4.4.3 不足与改进
本系统是从P[0][0]开始搜索,但落棋一般都是从中心开始,以后都是围绕中心的棋展开的,在棋盘的边缘,基本上都是空点,这样就浪费了很多系统资源,增加了搜索时间,如能从棋盘最有可能下的点开始搜索就可以了,比如查找P[][]里面最小的点。

在棋盘界面上也需要有所改进,本系统还不能保存棋局,如能增加保存棋局功能,游戏结束后就能分析棋局,对玩家提高自身的水平有所帮助。

第5章总结
随着计算机的普及,人们对游戏的要求也越来越高,像五子棋这种休闲游戏丰富了人们的业余生活。

至此,对用 C++/API 函数来开发 Windows 小游戏有了一个较全面的了解。

通过本课题的研究及设计与开发,基于C++的五子棋游戏软件开发完毕,实现了五子棋的人机对战。

本课题按软件工程的要求设计与实现了整个系统,即需求分析、系统总体设计、详细设计与编码实现等步骤,最后进行了系统测试,并通过了系统测试。

在本软件的开发中,还是有不少地方是不太满意的,首先通过单纯的C++语言来实现功能。

虽然C++的强大功能足以应付这种软件的开发要求了,但是由于控件的缺乏,语法的繁琐,在实现很多功能的实现中花费了不少力气。

但是由于知识水平的缺乏,无法使用Delphi,flash等更简便的手段来实现功能,希望以后可以弥补这一点。

其次,缺乏完成大工程的经验,没有建立一个有效可行的工作计划。

在工作中时而通宵奋战,时而停顿不前,既浪费了宝贵的时间,也耗费了大量精力,实在得不偿失。

但值得注意的是,在软件的开发中,我们学到了很多书本上学不到的经验。

首先,使用了别人开发的思想,虽然开始很不习惯,但是上手之后就深深的体会到模块化开发和面向对象语言的方便与高效。

其次,这次开发中我使用了很多以前没接触过的函数。

除了上网学习资料外。

熟练的使用同学提供的参考资料,相信对以后的工作会有很大的益处。

在开发过程中小组成员都积极的参与,在完成了自己负责的部分之后都能够主动帮助其他未完成的同学解决相关问题,使得该项目于计划完成时间顺利完成,很好的体现了团队精神,非常值得肯定。

参考文献
[1] 四维科技,丁展,汤倩. C++ 游戏开发技术与实例[M].北京:人民邮电出版
社,2005
[2] 牛连强.C++ 程序设计[M]. 北京:人民邮电出版社,2005
[3] 蔡自兴,徐光佑.人工智能及其应用(第四版)[M]. 北京:清华大学出版
社,2010
[4]黄维通.Visual C++ 面向对象与可视化程序设计[M]. 北京:清华大学出版
社,2003
[5] 谢希任.五子棋技巧 [M]. 北京:电子工业出版社,2005
[6] (美)W. Richard Stevens. 窗口设计[M]. 北京:机械工业出版社,2005
[7] 北京现代富博科技有限公司,陈兵旗,孙明. 北京: C++实用图象处理专业教
程[M] .清华大学出版社,2004
[8] 张静.Windows多媒体编程基础[M].北京:清华大学出版社,2005
[9] 百度百科
[10]百度文库
[11]程序员联合开发网
附录
//本项目部分源代码
#include <windows.h>
#include <conio.h>
#include <string>
#include <ctime>
#include <iostream>
using namespace std;
struct pt //逻辑的
{
int x; //对应棋盘x方向上的坐标,x的值从0开始
int y; //对应棋盘y方向上的坐标,y的值从0开始
};
#define _or_ptx 0 //棋盘原点x坐标
#define _or_pty 0 //棋盘原点y坐标
#define _max_ptx 14 //棋盘最大x坐标
#define _max_pty 14 //棋盘最大y坐标
#define computerturn 1 //轮到电脑下棋
#define playturn 0 //轮到玩家下棋
#define maxelem 15 //棋盘大小,此值为实际大小,从1开始
pt m_pplastpos;//玩家走的前一步棋
pt m_pclastpos;//计算机走的前一步棋
bool m_bwfirst=false;//谁先走,1为电脑先走,0为玩家先走
bool m_binit=false;//判断游戏是否是处于刚开始阶段void InitializeBoard();
void IsWin();//判断是否已有一方
bool pwin;
bool cwin;
bool ctable[15][15][572];
int win[2][572];
bool ptable[15][15][572];
pt ComTurn();
int GiveScore(int type,int x,int y);
bool SearchBlank(int &i,int &j,int nowboard[][15]);
void GetBoard(int tempboard[][15],int nowboard[][15]); bool start;
int cpflag=playturn; //cpflag标记轮流走棋,当cpflag=2时为玩家下期,当cpflag=1时为电脑下期bool player=false;
int board[15][15];
bool computer=false;
pt getpoint(int table[maxelem][maxelem], int max); //注:数组本来就是指向一个地址的,所以不需要加引用也可以改变其中的值
int table[maxelem][maxelem]; //如果电脑下子标记为1(电脑棋子颜色0x0b),玩家下子标记为2(玩家棋子颜色0x0e)
void gotoxy(int x, //前往x方向上对应的位置
int y); //前往y方向上对应的位置void gotoxy(pt p); //上面函数的重载形式,传进一个点坐标
void gotoxy2(int x, int y) //逻辑的
{
//逻辑原点
COORD pos = {x, y};
SetConsoleCursorPosition(GetStdHandle(STD_OUT PUT_HANDLE), pos);
}
void Chang_Console_size(int max_x, //x方向上的长度,长度值从1开始
int max_y); //y 方向上的长度,长度值从1开始
void color(int n_color); //n_color为颜色值,十六进制形式
void out(char* chars); //输出chars所指向的字符串
void out(int flag); //上面函数的重载形式flag
= 0时输出●,flag = 1时输出■
void hidecur(); //隐藏光标
char getudlr(); //接受上下左右及回车按键
int get_rnum(int maxrand); //得到一个不大于maxrand的随机数
bool check(pt checkpoint, int table[maxelem][maxelem], int max, int checkcpflag); //检查是否获胜,checkcpflag=1是检查电脑是否获胜,checkcpflag=2是检查玩家是否获胜
void begin();
void mouse(int &x, int &y, int flag=0);
void ClearScreen(void)
{
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OU TPUT_HANDLE), &bInfo);
COORD home = {0, 0};
unsigned long size = bInfo.dwSize.X * bInfo.dwSize.Y;
FillConsoleOutputAttribute(GetStdHandle(STD_OUT PUT_HANDLE), bInfo.wAttributes, size, home, NULL);
FillConsoleOutputCharacter(GetStdHandle(STD_OU TPUT_HANDLE), ' ', size, home, NULL);
}
void cls()
{
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( GetStdHandle(STD_O UTPUT_HANDLE), &bInfo );
COORD home = {0, 0};
WORD att = bInfo.wAttributes;
unsigned long size = bInfo.dwSize.X * bInfo.dwSize.Y;
FillConsoleOutputAttribute(GetStdHandle(STD_OUT PUT_HANDLE), att, size, home, NULL);
FillConsoleOutputCharacter(GetStdHandle(STD_OU TPUT_HANDLE), ' ', size, home, NULL);
}
void help()
{
cls(); }
static int mainflag = 0;//指示缓冲区是否改变,如果没有改变则调用主函数,直到改变为止
int main()
{
begin();
while(mainflag++!=0){getch();getch();};
main();
return 0;
}
bool check(pt checkpoint, int board[maxelem][maxelem], int max, int checkcpflag) //检查是否获胜,checkcpflag=1是检查电脑是否获胜,checkcpflag=0是检查玩家是否获胜
{//本模块存在的问题:边缘判定具有BUG
switch(checkcpflag)
{
case 1:
if(1)
{
int ncount=0;
int ncount1=0;
int ncount2=0;
//横向扫描
for (int i=checkpoint.x; board[i][checkpoint.y]==checkcpflag; i--)
{
if (i>=0)
{
ncount1++;
}
}
for (int j=checkpoint.x; board[j][checkpoint.y]==checkcpflag; j++)
{
if (j<=max)
{
ncount2++;
}
}
ncount = ncount1 + ncount2;
if (ncount>=6)
{
return true;
}
ncount=0;
ncount1=0;
ncount2=0;
//初始化计算机和玩家的获胜组合情况for(i=0;i<15;i++)
for(j=0;j<15;j++)
for(k=0;k<572;k++)
{
ptable[i][j][k]=false;
ctable[i][j][k]=false;
}
for(i=0;i<2;i++)
for(j=0;j<572;j++)
win[i][j]=0;
for(i=0;i<15;i++)
for(j=0;j<15;j++)
board[i][j]=2;
for(i=0;i<15;i++)
for(j=0;j<11;j++)
{
for(k=0;k<5;k++)
{
ptable[j+k][i][count]=true;
ctable[j+k][i][count]=true;
}
count++;
}
for(i=0;i<15;i++)
for(j=0;j<11;j++)
{
for(k=0;k<5;k++)
{
ptable[i][j+k][count]=true;
ctable[i][j+k][count]=true;
}
count++;
}
for(i=0;i<11;i++)
for(j=0;j<11;j++)
{
for(k=0;k<5;k++)
{
ptable[j+k][i+k][count]=true;
ctable[j+k][i+k][count]=true;
}
count++;
} for(i=0;i<11;i++)
for(j=14;j>=4;j--)
{ for(k=0;k<5;k++)
{
ptable[j-k][i+k][count]=true;
ctable[j-k][i+k][count]=true;
}
count++;
} }
注:其余各个功能实现的详细代码请参见本组成员撰写的个人实验报告。

相关文档
最新文档