




已阅读5页,还剩23页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
软件综合实习报告题目:五子棋人机博弈游戏院(系): 计算机学院 专 业: 计算机科学与技术 姓 名: 杨祺鹏 班级学号: 191072-03 20071000566 指导教师: 王改芳 2010 年 9 月 18 日目录一 系统需求分析与总体设计1. 需求分析 问题描述 数据流程图2. 总体设计 开发背景 开发语言 开发平台和运行平台 总体功能设计二 详细设计与系统实现1. 类和类的方法设计 类的设计 类的方法设计2. 算法描述三 系统测试1. 功能测试2. 性能测试四 总结1. 系统仍存在的不足2. 结论和体会一 系统需求分析与总体设计1. 需求分析 问题描述题目:五子棋人机博弈游戏题目要求:实现五子棋游戏的人机博弈。要求:友好的人机图形化界面、方便的操作方式;自动判断输、赢或平;可选择黑白;可悔棋;可以基于人工智能方面的知识进行设计,如:启发式搜索、搜索函数的设置、_算法、知识的表示及知识库,推理机等。五子棋简介:五子棋是起源于中国古代的传统黑白棋种之一。顾名思义,只要连成五子即可获得胜利。听上去好像很简单,但是不用技巧好似很难获胜的,这其中就有“活三”,“冲三”等等专业名词,这些我会在后续的程序中进行介绍。五子棋不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。五子棋既有现代休闲的明显特征“短、平、快”,又有古典哲学的高深学问“阴阳易理”;它既有简单易学的特性,为人民群众所喜闻乐见。 通过问题的描述,初步分析可得出此软件应具有以下的功能:1. 友好的界面,方面的操作方式可以快速开始游戏,功能明确而且界面明朗2. 自动判断输赢计算机可以根据棋子的状态判断胜负情况3. 可选择黑白可以先手下棋和后手下棋4. 可悔棋具有悔棋功能5. 计算机AI计算机需要具有一定的AI,需要AI攻守兼备 数据流程图判断谁是先手玩家计算机AI:即算法数据流动很少,主要是在算法内部进行计算,实际进行交互的数据是没有的。 要求开始游戏 落子,33禁手 棋子坐标 玩家落子 是否再来一盘输赢判断 取最佳位置并落子(若不分胜负) 再来一盘 胜负已分2. 总体设计 开发背景软件工程综合实习,因为我对算法很有兴趣,就决定通过这个程序学习一下。 语言选择使用C#平台在设计人机界面时更人性化,画图工具也更为简洁易用。 开发环境及运行环境开发环境:操作系统名称Microsoft Windows 7 旗舰版版本6.1.7600 版本 7600处理器AMD Turion(tm) X2 Dual-Core Mobile RM-72,2100 Mhz, 物理内存(RAM)3.00 GB开发平台:Microsoft Visual Studio 2008 专业版 - 简体中文 Microsoft Visual C# 2008运行平台:Intel Pentium 2及以上处理器,32M以上内存,4G以上硬盘Microsoft Windows 9X/NT操作系统800*600或以上的屏幕分辨率Net.framework2.0及以上版本 具体功能设计主要函数:1. 画棋子2. 画棋盘3. 先手判断4. 胜负判断5. 计算机AI算法(权值赋值,权值计算,找最大权值)界面设计:1. 快速开始游戏2. 先手选择3. 悔棋,认输,电脑提示4. 棋子的坐标显示(计算电脑提示的附加功能)5. 帮助这几个模块的重点是计算机AI算法的设计。在参阅了很多资料以后,我发现解决五子棋问题的算法非常之多,遗传算法,剪枝算法等等,这些算法的特点是对后续步骤进行无数次的推演并一一评分,最后去评分最高的一种方案的第一步,在下完一子之后再进行算法计算,虽然AI非常聪明但是计算繁琐且计算时间其长无比。在网上发现的算法有更多的程序员是采用了权值计算的方法,具体来说就是根据每种情况每种可能对每个点都赋不同的权值,AI在判断应该进攻还是应该防守就是依靠权值的大小,权值最大的位置放棋子,采用这种方法虽然笨是笨了些,但是计算速度快,尤其是在棋盘比较小的时候(15*15棋盘),而且在对比中发现这种AI也很聪明。在速度和计算精度之间权衡之后,我准备选择计算权值的方法来做,如果时间仍有富裕的话再使用别的算法来计算并进行对比。二 详细设计与系统实现1. 类和类的方法设计 类的设计(后面的方法设计也遵从这个顺序逐个进行详细注释)棋盘类Chessboard棋盘类主要实现对棋盘棋子,以及电脑和人下棋的显示,对虚拟棋盘的定义,对下棋路径的堆栈的初始化,对棋局的初始化。棋子类 Stone棋子类主要实现对棋子的画图操作。计算机类Computer计算机类是本程序的核心模块,主要实现计算机对每个棋子每个位置的权值赋值,对每个棋盘位置的权值计算,求最大权值。规则类Rule规则类主要实现对胜负平局的判断,对黑棋禁手的判断,对每个方向上的连子数的计算,对棋局判断是依据连子数计算的。主函数类frmMain主函数主要是对界面上每个按键的功能进行实现,另实现对鼠标的move和click事件的定义,获取鼠标的坐标。 类的方法的具体实现1. Chessboard类中方法的实现一 Chessboard中的变量定义所谓的在棋盘上下棋,其实就是在相应坐标进行绘图,实际是不存在棋盘的,这里我定义一个15,15的二维数组来表示虚拟的棋盘进行下棋,其他见程序注释。public int, arrchessboard = new int 15,15; / /arrchessboard为棋盘情况数组,虚拟棋盘的定义,arrchessboardi,j=2表示此处无子arrchessboardi,j=0表示此处为黑子,arrchessboardi,j=1表示此处为白子private Graphics mg; /绘制的对象public Stone stone; /棋子对象public Computer computer; /电脑对象private bool stoneflag = true; /判断当前棋子是黑(true)是白(false)private bool mplayfirstflag = false; /判断先手玩家(是电脑(true)还人(false),先手下黑棋)private Stack mStarckHistory = new Stack();/历史记录堆栈二 Chessboard中对棋盘和棋子的绘制对棋子和棋盘的绘图要用到system.draw这个系统自带的画图类,我使用的方式是先读取文件流中的文件,然后在每次画图的时候就不用再次读取了,直接可以进行绘图,这样处理速度比较快。详细见注释。public void Draw()/从资源中获取,读取棋盘图像,就是在当前项目中读取文件System.Reflection.Assembly thisExe;thisExe = System.Reflection.Assembly.GetExecutingAssembly();System.IO.Stream file = thisExe.GetManifestResourceStream(FiveStones.chessboard.gif);/棋盘文件Image imgChessboard = System.Drawing.Image.FromStream(file); /棋盘图片大小*600像素,每个棋子的点的坐标,个棋子,个空,两边线留空file.Close();mg.DrawImage(imgChessboard,0,0,imgChessboard.Width,imgChessboard.Height);/绘制棋子for (int i=0;i15;i+)for(int j=0;j15;j+)if (arrchessboardi,j = 0)/对棋盘上的点进行判断后,根据虚拟数组的值来判断绘制哪一种棋子stone.DrawStone(i,j,true);/Stone里面具体的绘制方法if (arrchessboardi,j = 1)stone.DrawStone(i,j,false); 三 Chessboard中人下棋和电脑下棋就是获取下棋的坐标,然后在该坐标进行相应的绘图,然后把该点的虚拟棋盘置成2,表示已经下过棋了。public void PersonDownStone(int x,int y)if (x 600 & y 100)/如果下一百个子还不分胜负,就直接异常退出MessageBox.Show(异常!);Start();return;while(Rule.IsExist(m,n,arrchessboard);/当判断该点没有子的时候下子DownStone(m,n);四 Chessboard对棋局的初始化把初始化贴上来的目的是为了让每次下棋的流程更明显,构造对象啊,还有清空堆栈呀,这些看似很简单,但是其中的顺序是不可颠倒的,详细见注释。 private void Initialization()/棋盘初始化stoneflag = true; /置当前要走的棋为黑棋(黑棋先走)for(int i=0;i15;i+)for(int j=0;j15;j+)arrchessboardi,j = 2; /把棋盘所有位置置为空(未下子)mStarckHistory.Clear();/清空历史记录堆栈stone = new Stone(mg); /构造棋子对象private void Start()/这个才是初始化函数Initialization();computer = new Computer(mplayfirstflag); /构造电脑对象Draw();/画棋盘if (mplayfirstflag)/如果是电脑先手的话就电脑下棋,否则等待ComputerDownStone();五 Chessboard中每下一子都要进行的处理做法,更改虚拟棋盘的数值,对禁手进行判断,将棋子坐标压入堆栈,下棋完成后交换下棋。这个过程显示了下棋的步骤,在下棋之后,对虚拟棋盘也就是二维数组进行赋值,然后把该点压入堆栈,然后对黑棋是否禁手进行判断,这里用到了Rule传过来的值,详细见注释。private void DownStone(int m,int n)stone.DrawStone(m,n,stoneflag);/下棋if (stoneflag) /记录情况arrchessboardm,n = 0;/根据黑白标记对虚拟棋盘数组进行赋值elsearrchessboardm,n = 1;if (stoneflag) /记录历史记录压入堆栈/压入堆栈的是棋子颜色和坐标mStarckHistory.Push(黑:+m.ToString()+,+n.ToString();每下一子就压入堆栈elsemStarckHistory.Push(白:+m.ToString()+,+n.ToString();if (Rule.Result(m,n,arrchessboard) 6) /判断结果,这个要调用Rule中的方法switch(Rule.Result(m,n,arrchessboard) /禁手失败直接判黑棋负,重新开始case 1: MessageBox.Show(黑棋双三禁手失败!);由Rule.Rusult的返回值进行判断,这几种情况都要重新开始!break;case 2:MessageBox.Show(黑棋双四禁手失败!);break;case 3:MessageBox.Show(黑棋长连禁手失败!);break;case 4:if (stoneflag)MessageBox.Show(黑棋胜利!);elseMessageBox.Show(白棋胜利!);break;case 5:MessageBox.Show(平局!);break;Start();/重新开始!return;elsestoneflag = !stoneflag; /交换当前棋子颜色 2.Stone类中方法的实现 Stone类主要实现的就是对棋子的绘图,没什么好说的。public class Stone对棋子的绘制方法,需要从当前目录进行读取图片,再绘制private Graphics mg;privateImage imgBlackStone; /黑子图片从文件获取privateImage imgWhiteStone; /白子图片public Stone(Graphics g)System.Reflection.Assembly thisExe;thisExe = System.Reflection.Assembly.GetExecutingAssembly();System.IO.Stream wfile = thisExe.GetManifestResourceStream(FiveStones.whitestone.gif);/读取黑子,白子图片System.IO.Stream bfile = thisExe.GetManifestResourceStream(FiveStones.blackstone.gif);/从资源中获取 imgBlackStone = System.Drawing.Image.FromStream(bfile);imgWhiteStone = System.Drawing.Image.FromStream(wfile);bfile.Close();wfile.Close();mg = g;public void DrawStone(int m,int n,bool flag)/绘制棋子绘制棋子if (flag)/判断是黑棋(true)还是白棋(false)g.DrawImage(imgBlackStone,m*40,n*40,imgBlackStone.Width,imgBlackStone.Height);elseg.DrawImage(imgWhiteStone,m*40,n*40,imgWhiteStone.Width,imgWhiteStone.Height);3.Computer类中方法的实现一 每下一子都要进行的过程 Down方法这个方法说明了下子之后的整个计算过程,先重新定义一个虚拟棋盘,然后对该虚拟棋盘有子的位置的权值赋值为-1,就是肯定不会走的,然后调用Check方法对没有子的位置进行权值计算,然后使用Check返回的权值在MaxQZ里面计算权值的最大值。public void Down(int, arrchessboard) /基本思路:先计算每个点的权值,在权值最高的位置下棋int , qz = new int15,15; /权值数组for (int i=0;i15;i+)for(int j=0;j15;j+)if (arrchessboardi,j 2)qzi,j = -1;/当已有子时标注为-1elseqzi,j = Check(i,j,arrchessboard);/Check方法在下面介绍,是计算权值的方法MaxQZ(qz);/MaxQZ也在下面进行介绍,是计算最大权值的方法二 计算权值的方法Check返回权值给对手颜色的连子点赋权值对当前颜色的连子进行赋权值根据当前点调用Rule的方法计算连子上面的流程图写出了整体的过程,Check主要是对刚刚定义的权值数组进行赋值,先对己方进行赋值,然后对对手的进行赋值,然后判断是应该防守还是应该进攻。电脑Ai的攻击力取决于权值的赋值,详细见注释。private int Check(int m, int n, int, arrchessboard)赋权值的原则 /赋值的原则决定了AI是进攻强还是防守强,进攻强则在AI和人都有三字连起时,给自己的赋值更高一些,防守强则是给人的赋值更高一些int qz = 0; int w1 = 100000; /找自己的取胜点()int w2 = 50000; /找对手的取胜点()int w3 = 10000; /找自己的三个相连的点()赋权值int w4 = 5000; /找对手的三个相连的点()int w5 = 1000; /找自己的两个相连的点()int w6 = 500; /找对手的两个相连的点()int w7 = 100; /找自己的相连的点()int w8 = 50; /找对方的相连的点()int w9 = 999999; /找自己的失败点,无穷大,优先胜利int arrf = new int4;if (mflag) /如果电脑是黑子arrchessboardm,n = 0;/如果该位置下我方的子的时候,进行下面的权值计算,白黑子都要进行计算else/否则电脑是白子arrchessboardm,n = 1;/这里赋值的原因是因为不同色的值不一样 /分别计算四个方向上的连子数,调用Rule里面的四个方法arrf0 = Rule.Xnum(m,n,arrchessboard);/横向 arrf1 = Rule.Ynum(m,n,arrchessboard);/竖向arrf2 = Rule.YXnum(m,n,arrchessboard);/左上右下arrf3 = Rule.XYnum(m,n,arrchessboard);/右上左下if (m=7 & n=7)qz+=1;/中心点权值加,这主要是为了电脑先手时,优先走中间点for (int i=0;i0)判断是否是禁手点,调用Rule里面的方法qz += w9;if (mflag) /如果该位置下对方的子arrchessboardm,n = 1; /对方白子else/对方黑子arrchessboardm,n = 0;arrf0 = Rule.Xnum(m,n,arrchessboard);arrf1 = Rule.Ynum(m,n,arrchessboard);arrf2 = Rule.YXnum(m,n,arrchessboard);arrf3 = Rule.XYnum(m,n,arrchessboard);for (int i=0;i4;i+)if (Math.Abs(arrfi) = 5)qz += w2;if (arrfi = 4)计算你的对手的权值,然后赋值!qz += w4;if (arrfi = 3)qz += w6;if (arrfi = 2)qz += w8;arrchessboardm,n = 2;/计算结束后对该点设置成没有子return qz;/返回权值三 计算最大权值点比较,赋值,得出结果,没什么好说的。private void MaxQZ(int , qz)/计算最大权值/没什么好解释的。int max = 0;for (int i=0;i15;i+)for(int j=0;jmax)x = i;y = j;max = qzi,j;4.Rule类中的方法的实现一 计算每个方向上的连子数同色总体思路是在当前点分别向两边进行搜索,如果两边的点和当前点颜色一致则连子数加1,直到碰到和当前点不一样颜色的点。不同颜色的点有三种,分别是空白点,另一种颜色的点,棋盘边缘。对于空白点,则置成活棋并返回值,如果是另一种颜色的点则置成死棋并返回值,对于棋盘边缘也置成死棋并返回值。详细见注释。连子数加一对两边的点和当前点进行颜色的判断从当前点向两边进行搜索不同置成活棋,返回值空白点对该点判断不同色置成死棋,返回值棋盘边缘PS.一共有四个方向的连子数的计算,仅列出X轴的计算方法 public static int Xnum(int m, int n, int, arrchessboard)int flag = 0;/检查是否无子可下(当flag=2时表示无子可下) /为什么flag=2的时候就不能下子了呢? /是因为只有左右两边都没有棋子下的时候才结束计算权值,其他方向的检测和这个是一个原理的, /就是两头的两个方向都是对方的子了int num = 1;/连子个数int i = m+1;/正东方向检查(x+)while(i = 0) if (arrchessboardi,n = arrchessboardm,n) /前方的棋子与m,n点不是一样的棋子时跳出循环num+;i-;elsebreak;if (i = -1) /正西方向超出棋格flag+;else if(arrchessboardi,n != 2) /正西方向有别的子不可在下flag+;if (flag = 2)return -num;else/连子数为时有一边不能下就不是活三 不是活三的时候赋值降低 if (flag = 1 & num = 3 ) return -num;elsereturn num;二 胜负平局判断,禁手判断任意方向上连成五子即算胜利,在没有一个连成五子的情况下棋盘走满算平局,禁手判断是对当前点的四个方向计算上有三个以上连子就算禁手(仅黑子有禁手),禁手直接判负重新开始。详细见注释。胜利判断:private static bool IsWin(int arr)for (int i=0;i4;i+)当连子数为5的时候就胜利了,arrI是四个方向的连子数if (Math.Abs(arri) = 5)return true;return false; 平局判断:private static bool IsTie(int, arrchessboard)/当所有位置都有子时为平局当所有点都有子的时候即判断为平局for (int i=0;i15;i+)for (int j=0;j15;j+)if (arrchessboardi,j = 2)return false;return true; 负局判断:(要对禁手进行判断,比较难)public static int IsFail(int arr, int stoneflag)if (stoneflag = 1) /如果是白棋不验证因为白棋无禁手白棋没有禁手return 0;elseint num = 0;/活的子相连的个数for (int i=0;i 1)return 1;num = 0;/活的子相连的个数for (int i=0;i 1)return 2;for (int i=0;i 5)return 3;return 0;6. frmMain类中方法实现frmMain中的方法主要是实现窗口中的按钮,这里只对获取鼠标的坐标的功能,还有悔棋功能,电脑提示功能进行详解。一 获取鼠标的坐标为什么要说获取鼠标坐标的方法呢,主要是因为其中的强制转换还有求坐标的方法当时想了很久,个人感觉有用,所以就记下来了。private void frmMain_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)if (e.X 600 & e.Y 0; j-)/悔棋要进行两次修改 上次我方和AI方都要改 object obj = chessboard.StarckHistory.Peek();/获取栈顶元素 string sta=obj.ToString(); char st = sta.ToCharArray(); int x = Int32.Parse(st2.ToString(); int y = Int32.Parse(st4.ToString();/读出栈中的数据(x,y坐标) backstone(x,y);/在该位置花悔棋的图 chessboard.arrchessboardx, y = 2;/设置悔棋的点的棋子状态为,即没有棋子 chessboard.StarckHistory.Pop();/出栈 Array arr = chessboard.StarckHistory.ToArray(); this.lstHistory.DataSource = arr;/listbox的datasource为堆栈的数组表示 三 电脑提示的功能的实现(在要求外额外实现的功能)原本想要在这一步使用一个比较靠谱的搜索树算法向下搜索三步左右的,还是程序设计初期的问题,没有对程序有整体的把握,把很多东西都设计到了一起,后来再改的时候就很难了,所以也没有实现。现在实现的电脑提示的功能就是调用Computer类里面的方法对权值进行计算,得到最大权值之后在棋盘上进行绘制。private void aihelp() try puter.Aihelp(chessboard.arrchessboard); int a = puter.X;调用Chessboard类计算权值方法,得出最佳坐标 int b = puter.Y; helpline(a,b); catch (Exception ex) 在棋盘上画出来一个红色正方形 Console.WriteLine(ex); public void helpline(int m, int n) Graphics gr = this.CreateGraphics(); Pen pen = new Pen(Color.Red,2); gr.DrawRectangle(pen ,m*40+10,n*40+10,20,20);2. 算法描述一 本程序使用的算法本程序使用的比较简单的计算权值的算法,根据不同的点不同的情况不同的连子进行赋值,然后每次下子的时候都对棋盘上的所有点的权值进行计算,取权值最大点为最佳点落子。这种算法的优点是比较容易实现,不需要太复杂的数据结构,时间复杂度较好,计算机AI取胜的几率不大,但是围堵比较强。同时缺点也是很明显的,没有对后续步骤进行计算使得计算机AI只能看到眼前的利益而没有长远的眼光,对计算机AI来说这点是很致命的。给对手颜色的连子点赋权值计算最大权值的点定义为最佳点对当前颜色的连子进行赋权值根据当前点调用Rule的方法计算连子下面是本算法的流程:二 其他五子棋算法以及我的一点
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年体育休闲广场周边配套设施完善策略研究报告
- 2025年商业地产数字化运营模式创新客户体验优化路径研究报告
- 药品耗材仓库管理制度
- 药品销售环节管理制度
- 药店加盟进货管理制度
- 药店煎药日常管理制度
- 莲花味精绩效管理制度
- 论述负面清单管理制度
- 设备制造采购管理制度
- 设备寄存仓库管理制度
- 2024钓场租赁合同范本
- 2024年天津市河西区第四中学七下英语期末统考试题含答案
- 热工仪表检修(第二版)中级工题库
- DZ/T 0462.3-2023 矿产资源“三率”指标要求 第3部分:铁、锰、铬、钒、钛(正式版)
- 生理学习题含参考答案
- 2024年昆明巫家坝建设发展有限责任公司招聘笔试冲刺题(带答案解析)
- 2024-2030年中国内河水运行业市场现状调查及发展趋向研判报告
- 广东省深圳市福田区福田小学小学语文六年级小升初期末试题(含答案)
- 数智时代的商业变革智慧树知到期末考试答案章节答案2024年山东大学(威海)
- 2024年福建省宁德市中考一模《物理》试题(解析版)
- 2023年国开(中央电大)04114《会计学概论》题库及标准答案
评论
0/150
提交评论