第一篇:五子棋游戏项目报告
-《软件技术基础》项目报告
《软件技术基础》课程项目报告
项目名称:用VC++实现的五子棋游戏 专业班级: G11009
项目成员:崔光浩 程德武 付强 付钰
李洪润 尚振兴 沈婷玉 佟承雨 周彤姣
指导老师: 殷黎
完成时间: 2011/10/31
-《软件技术基础》项目报告
目录
摘要
一、需求分析.............................................................................................................1.1 开发背景................................................................................................................1.2 项目目标................................................................................................................1.3 运行环境................................................................................................................1.4 游戏说明................................................................................................................1.5 项目任务书............................................................................................................二、技术路线.......................................................................................................................2.1 总体方案................................................................................................................2.2 详细设计................................................................................................................三、工程进度.......................................................................................................................3.1 前期准备部分(1-3)天.......................................................................................3.2中期实现功能部分(4-7)天................................................................................3.3后期总结完善部分(8-10)天..............................................................................四、测试报告.....................................................................................................................4.1 第5天:测试棋谱..............................................................................................4.2 第6天:基本功能测试......................................................................................4.3 第7天:悔棋功能..............................................................................................4.4第8天:测试其他的附加功能...........................................................................4.5第9、10天:总体测试.......................................................................................五、个人小结.....................................................................................................................六、主要算法.....................................................................................................................1判断胜负..................................................................................................................-《软件技术基础》项目报告
2鼠标模拟..................................................................................................................摘要
五子棋是起源于中国古代的传统黑白棋种之一。现代五子棋日文称之为“連珠”,英译为“Renju”,英文称之为“Gobang”或“FIR”(Five in a Row的缩写),亦有“连五子”、“五子连”、“串珠”、“五目”、“五目碰”、“五格”等多种称谓。
五子棋不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。五子棋既有现代休闲的明显特征“短、平、快”,又有古典哲学的高深学问“阴阳易理”;它既有简单易学的特性,为人民群众所喜闻乐见,又有深奥的技巧和高水平的国际性比赛;它的棋文化源渊流长,具有东方的神秘和西方的直观;既有“场”的概念,亦有“点”的连接。它是中西文化的交流点,是古今哲理的结晶。
-《软件技术基础》项目报告
一、需求分析
1.1 开发背景
五子棋是一种两人对弈的纯策略型棋类游戏,是起源于中国古代的传统黑白棋种之一。发展于日本,流行于欧美。五子棋容易上手,老少皆宜,而且趣味横生,引人入胜;不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。传统五子棋的棋子分为黑白两色,采用围棋棋盘,棋子放置于棋盘线交叉点上。两人对局,各执一色,轮流下一子,先将横、竖或斜线的5个同色棋子连成不间断的一排者为胜。
棋类游戏规则简单,对外部要求不高,人们可以随时随地进行对弈。但是,真正能够精通棋类游戏的人却不是很多,主要是棋类游戏具有变化莫测的特点,人们经常得在棋局上深思熟虑才能找到克敌制胜的办法。因此,各种棋类游戏都具有开发智力的效能。在休闲中使自己得到真正的长进,这或许就是其倍受人们青睐的原因所在!
1.2 项目目标
我们将主要通过VC++语言,运用面向对象的程序设计方法,开发此款五子棋游戏。力争使程序短小精悍,简洁明了;游戏界面优美,容易操作;功能丰富,趣味性强。现在将我们对项目期望实现的目标一一介绍: a.能供两人对弈。
b.可以实现经典棋局的回放。c.可以悔棋。
D.能实现棋局步数的排名。e.操作方便,容易上手。
1.3 运行环境
本游戏短小精悍,而且对电脑配置的要求均不高,目前几乎所有的PC机均可运行该游戏。但是为了能让大家更好地体验该款游戏,我们给出如下的最低配置:
-《软件技术基础》项目报告
最低配置:CPU1GHz 内存 32M 硬盘 4G Windows 95 Microsoft Visual C++ 6.0 同时结合我们开发该游戏的环境,我们强烈推荐用户使用如下的配置:
最佳配置:CPU2GHz及以上 内存256M及以上 硬盘80G及以上 Windows XP及以上 Microsoft Visual C++ 6.0
1.4 游戏说明
(1)游戏流程:
启动游戏后,显示主菜单。里面包括开始游戏、读取游戏、排行榜、关于游戏、游戏帮助、退出。读取游戏中包含经典棋局的回放和未下完的棋局。排行榜中显示的是棋局步数的排名。(2)游戏规则:
落子:对阵双方交替落子,任何一方不能多下一步,也不能在已有棋子的地方继续落子,否则会有错误提示。
赢棋:任何一方先出现在棋盘的横、纵或斜线上形成连续的五子,则该方获胜。排行榜:可以判断赢者是否可以进入排行榜。
(3)特别提示:
双人对弈模式下,悔棋的过程为:首先由玩家向对方发送悔棋请求(悔棋消息),然后由对方决定是否允许玩家悔棋,在玩家得到对方的响应消息(允许或者拒绝)之后,才进行悔棋与否的操作。
1.5 项目任务书
(1)班级:G11009(2)组长:崔光浩
(3)成员:尚振兴、李洪润、沈婷玉、程德武、付强、周彤娇、佟承雨、付钰(4)项目名称: 五子棋
-《软件技术基础》项目报告
(5)项目背景:五子棋是起源于中国古代的传统黑白棋种之一。五子棋不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。五子棋既有现代休闲的明显特征“短、平、快”,又有古典哲学的高深学问“阴阳易理”。
(6)项目分工:程德武:显示棋盘、显示帮助、游戏版权、显示在线帮助文档。
李洪润:排行榜全部。
付 强:下棋、经典棋局的回放。
沈婷玉:构造函数、初始化所有数据、析构函数。
尚振兴:负责文档规划。
周彤姣:文件的保存和读取。
付 钰:技术支持。
(7)项目进度:1-3天:前期准备,各类资料收集,流程图,算法等同时完成。4-7天:实现基本功能和附加功能。8-10天:最后测试,最后优化。
(各类文档的设计与编写穿插于始终)
-《软件技术基础》项目报告
二、技术路线
2.1 总体方案
游戏的简单流程如下图:
开始开始游戏 读取游戏排行榜帮助否关于退出 设定用户信息 下棋判断是否赢是悔棋鼠标模拟进排行榜否 是否保存保存是认输
2.2 详细设计
a.实现玩家的类Player。其中实现各个成员变量的set和get方法,以及构造和析构函数。
b.实现五子棋的类Gobang。其中实现各个功能的函数如下: 1.开始游戏 :开始、下棋、悔棋、认输、保存 void startGame();2.显示帮助文档 void showHelp();3.显示版权 void showEdition();4.显示棋盘 void showChessBoard();5.显示在线在帮助文档 void showOnlineHelp();
-《软件技术基础》项目报告
6.显示菜单 void showMenu();7.播放历史棋局 void movieGoBang();8.读取排行榜 void setWinnerHome();9.显示排行榜 void showWinnerHome();10.修改排行榜 void editWinnerHome(Player &player);11.保存历史记录、保存经典、继续 int saveHD(char *arr);12.读取历史记录、读取经典、继续 int loadHD(char *arr);13.鼠标模拟 1.void monitor();2.bool agree(int a);14.悔棋 void repent();15.判断五子连线 bool fun();16.显示已保存文档、有经典文档和继续文档 int showSave(int choice);
-《软件技术基础》项目报告
三、工程进度
本次作业历时十天时间,总的说起来可以分为三个部分:
3.1 前期准备部分(第1-3天)
主要完成方案的讨论、资料的收集、流程图、算法等前期工作,编写报告中需求分析的一部分和总体方案的一部分及项目任务书。
第1天:选定题名,进行方案的讨论。收集资料,写出需求分析中的开发背景部分。第2-3天:商定算法,将软件总体分块,写出项目任务书。
3.2中期实现功能部分(第4-7天)
主要完成预先设想的基本功能和附加功能,完成项目文档中的技术路线和需求分析的剩余部分,完成调试报告中的单功能调适。
第4天:开始软件编写,完成棋盘的设计部分。完成下棋部分程序的编写,测试棋盘设计部分。完成悔棋部分程序的编写,测试下棋部分程序。
第5-6天:完成两人对弈部分程序的编写,测试基本功能,测试悔棋部分。
第7天:完成附加功能,测试对弈部分情况。完善各项功能,测试附加功能。
3.3后期总结完善部分(第8-10天)
总体功能的调试改进,完成项目文档。
第8天:功能调试,优化软件。第9-10天:其它报告剩余部分。
0-《软件技术基础》项目报告
四、测试报告
4.1 第4天:测试棋谱
测试人:程德武
测试内容:通过VC++语言,我们编写了基于对话框的游戏界面。我们将测试它的最基本面貌,希望其是符合我们要求的界面模式!
测试过程:运行程序以后,弹出了棋局的对话框,整体棋局呈现白色,棋局右边和上边都有一些空出的区域,这是我们为将来实现其他附加功能预留的地方。但是测试过程中我们始终发现一个问题,棋格的位图没有按照我们的设想正确放置,出现了跃出棋盘的怪现象!
问题解决:通过反复推敲程序相关部分,我们觉得可能是算法有疏漏,于是修改了一下算法。我们将每个棋格的位图封装了起来,将其位置作为成员数据。再运行程序,问题就不再出现了。反复运行程序再也没有出现异常情况!
4.2 第5天:基本功能测试
测试人:佟承雨
测试内容:程序的基本框架已经编好了,希望能按我们的预期目标能实现供两人对弈功能!
测试过程:将程序编译、链接、运行后,弹出棋局的对话框,然后开始下棋,我们一步一步观察了每步落子后棋局的变化过程,均与我们预期的变化过程一样,我们非常欣喜,这说明我们设计下棋程序时的算法准确无误!
1-《软件技术基础》项目报告
4.3 第6天:悔棋功能
测试人:沈婷玉
测试内容: 测试悔棋功能能否正常实现。
测试过程:我们测试了悔棋功能,反复的测试,此功能运行良好,能够一步一步悔棋,直到无子可悔,而且通过记录观察,每步的悔棋过程均准确无误!
4.4第7天:测试其他的附加功能
测试人:李洪润
测试内容:我们对排行榜,经典棋局回放功能进行了测试
测试过程:我们开始游戏后,正常下棋取得胜利后,程序默认将胜方步数与排行榜中已存在的玩儿家步数进行比较,满足条件则进入排行榜,否则不进入。如果是前五次玩的话默认都进入排行榜。关于经典棋局,进入游戏后,载入经典棋局,每按一次回车,回放一步,经测试无异常。
4.5第8-10天:总体测试
测试人:崔广浩
测试内容:我们将在总体上对程序的运行效果和运行环境进行测试,以完善所有功能,达到软件的最优化!
测试过程:
首先我们测试了软件对运行环境的要求,我们先在Windows xp操作系统中运行了一遍,结果并无异常情况出现;随后我们在CPU只有1GHz频率的硬件系统中运行,也并未发现任何问题!我们基本上可以得出结论,我们的软件在一般的软、硬件环境下都能正常稳定地运行,对机子的配置基本没有什么要求,适合于广大的电脑拥有者使用!
2-《软件技术基础》项目报告
五、个人小结
通过本次五子棋程序的设计,我想我学到了很多东西。我主要是负责大报告的设计和编写,同时也编写一部分程序。编程的确是非常辛苦,主要是第一次利用VC++编写程序。我的VC++学的不是很好,编程时遇到了很多的困难,好在我们班的崔光浩同学不辞辛苦的帮助我调试程序,我们参考了很多的资料,像我们《软件基础》大作业中的优秀作品,网上的有关VC++的一些实用的编程技巧,还有一些经典的算法。善于利用已有的资源,是我在本次大作业中学到得很宝贵的经验,对于网络,我们懂得了不只要用它来实现低级的聊天、看电影、打游戏等功能,我们还要实现获取有用的信息、学习别人先进的方法、查阅相关的电子资料等功能,充分发挥它的作用。
我们这次的作品,虽然只是一个比较简单游戏的实现,但是通过这次合作,我也有很大的收获。虽然是一个小组,但每个人有不同的看问题的方法,我们在做这个软件的时候,大家也曾有过意见的分歧,我们也曾因为预期的功能没有实现而互相指责,也曾为有一点小小的进步而欣喜若狂。一路风风雨雨,我们毕竟是基本完成了预期的功能,努力没有白费,心里特别的充实,这就是创造的快乐,也是合作的快乐。我还编写了大作业的文档,由于自身能力的有限,我虽然竭尽全力,但总的感觉还是不能让我满意,不过,我也从中学到了一些东西:
总的说来,这次作业中我锻炼了自己的能力,也培养了团队合作的精神,感谢我的队友!感谢老师!感谢生活!
——尚振兴
在本软件的开发中,还是有不少地方是不太满意的,首先我通过单纯的VC++语言来实现功能。虽然VC++的强大功能足以应付这种软件的开发要求了,但是由于控件的缺乏,语法的繁琐,在实现很多功能的实现中花费了不少力气。但是由于知识水平的缺乏,无法使用Delphi,flash等更简便的手段来实现功能,希望以后可以弥补这一点。其次,缺乏完成大工程的经验,没有建立一个有效可行的工作计划。在工作中时而通宵奋战,时而停顿不前,既浪费了宝贵的时间,也耗费了大量精力,实在得不偿失。
但值得注意的是,在软件的开发中,我也学到了很多书本上学不到的经验。首先,我使用了别人开发的思想,虽然开始很不习惯,但是上手之后就深深的体会到模块化开发和面向对象语言的方便与高效。其次,这次开发中我使用了很多以前没接触过的函数。除了上网学习资料外。熟练的使用老师提供的参考资料,相信对我以后的工作会有很大的益处。
3-《软件技术基础》项目报告
我觉得通过这个小项目很好地考察了每个学生的知识水平,每个人都发挥了个人最佳的状态。虽然这种形式比普通的卷面考试要难,但是却能够充分调动每个人的积极性去学习自己尚未接触的知识和运用自己已经学过的知识。实验中,我们小组成员之间配合默契,共同商讨问题,使我们在碰到一个一个的问题后,能快速找到相关的答案。难能可贵的是,在软件制作最紧张的时候,大家都义无反顾地放弃了一点休息时间,和团队一起坚持奋斗!所以通过这次实验的合作,我们小组成员之间更加增进了了解,增进了团结!
——崔光浩
六、主要算法
以下时详细算法中提到的主要函数,其他函数在程序中。
1判断胜负
五子棋的胜负,在于判断棋盘上是否有一个点,从这个点开始的右、下、右下、左下四个方向是否有连续的五个同色棋子出现,判断胜负方向如下图
bool Gobang::fun(int a, int b)//判断是否五子连棋 {
int arr[8][2]={{-1,-1},{1,1},{-1,0},{1,0},{-1,1},{1,-1},{0,1},{0,-1}};int i;int sum=0;for(i=0;i<8;i+=2)
4-《软件技术基础》项目报告
{
sum=1;int A = a+arr[i][0];int B = b+arr[i][1];while(A>=0 && A<=N && B>=0 && B<=N && chessBoard[A][B]==chessBoard[a][b])
{
} A = a+arr[i+1][0];B = b+arr[i+1][1];while(A>=0 && A<=N && B>=0 && B<=N && A += arr[i][0];B += arr[i][1];sum++;chessBoard[A][B]==chessBoard[a][b])
}
} return false;{
} if(sum>=5)return true;A += arr[i+1][0];B += arr[i+1][1];sum++;
5-《软件技术基础》项目报告
2鼠标模拟
void Gobang::monitor(){
char ch = getch();switch(ch){
case 'w': case 'W': getMonitor = 0;break;case 'a': case 'A': getMonitor = 1;break;case 's': case 'S': getMonitor = 2;break;case 'd': case 'D': getMonitor = 3;break;case 'j': case 'J': getMonitor = 4;
6-《软件技术基础》项目报告
}
} break;case 'r': case 'R': getMonitor = 5;break;case 'p': case 'P': getMonitor = 6;break;case 'Q': case 'q': getMonitor = 7;break;default: break;void Gobang::startGame(){
int chose = 1;while(chose){ showChessBoard();monitor();
7-《软件技术基础》项目报告
if(getMonitor==0 && chessBoardMark[0]-1>=0)chessBoardMark[0]--;if(getMonitor==1 && chessBoardMark[1]-1>=0)chessBoardMark[1]--;if(getMonitor==2 && chessBoardMark[0]+1 case 4: //下棋 if(playGoBang(chessBoardMark[0], chessBoardMark[1])==1) if(fun()==true){ system(“cls”); printf(“nnnnn You Win!!nnnnnnnnnn”); remind(); if(historyStep%2==0)else editWinnerHome(player2);editWinnerHome(player1); showWinnerHome();remind(); 8-《软件技术基础》项目报告 } } } } break;case 5: //悔棋 repent();break;case 6: //保存 showSave(1);break;case 7: //退出 chose = 0;break;default: break; 10:10-10:40 区域游戏 一、活动目标: 1、新增区域中幼儿能迅速接受理解新游戏。 2、大胆选择自己喜欢的游戏材料和游戏内容,自主愉快地游戏。 3、能与同伴合作游戏,积极交流自己的想法。 二、活动准备: 1、经验准备:知道各区域的游戏玩法。 2、物质准备:(1)各区游戏材料如:穿编游戏、飞行棋、小画板等。 (2)新增游戏区域材料如:五子棋 3、区域内容: (1)公共区域:大舞台、美发屋等。(2)班级区域: (3)美食区(关东煮):肉串、涮炉等。 美食区(面包店):面包、披萨等。 美食区(咖啡店):咖啡机、桌椅等。 动手区(制作区):剪刀、双面胶等。 动手区(编织区):编制篮等。 益智区(好玩的磁铁):磁铁、迷宫板等。 益智区(解锁):锁、钥匙等。 阅读区:书籍,桌椅等。 三、活动过程: (一)介绍玩法,激发兴趣。 教师:今天我们的益智区有了新的棋类游戏——五子 棋。 五子棋是中国民间的一种棋类小游戏,十分地简单,谁先横排、竖排、斜排列出5个棋子就算获胜。 (在电脑上下载五子棋的小游戏进行演示,并讲解。) (二)提出要求,注意安全。 师: 游戏前老师有几点要求提醒大家。 1、动手区里做粘贴画时要注意不要把豆子撒在地上,更不能放进鼻子耳朵里。 2、建构区的小朋友在堆摆易拉罐的时候请轻拿轻放。 3、益智区里初学五子棋的小朋友遇到问题主动找老师。 4、要和其他小朋友文明交往、合作,学会谦让。 5、垃圾放在垃圾桶,不可以随地乱丢。 小朋友们坐坐好,坐的好的小朋友先插卡进区。 (三)自主进区,观察记录 1、了解幼儿入区的情况,是否全部入区,情绪如何。 2、关注各区域活动情况,教师适当加入。 3、仔细观察并记录,给予有困难的幼儿帮助。 4、提醒幼儿遵守游戏规则,学会谦让合作。 (四)重点指导手工区——五子棋 (五)结束活动,观察记录。整理和收拾 督促幼儿收拾整理,做到轻、快、齐,教师协助收拾整理。 (六)游戏评价 (1)讲解与展示 幼儿自己介绍自己的作品,感受成功后的快乐。 (2)交流与发现 让幼儿交流今天的活动,活动中开心的事情和遇到的问题。 (3)小结 表扬与批评,出示活动中拍摄的照片进行点评,提出新要求。 软件工程设计 专 业:班 级:姓 名:学 号:指导老师: I 目录 第一章 需求分析.......................................................1 1.1 总体分析..........................................................1 1.2 初始化............................................................1 1.3 主循环控制模块....................................................1 1.4 玩家下子..........................................................1 1.5 盘面分析填写棋型表................................................2 1.6 对方下子..........................................................2 1.7 胜负判断..........................................................2 第二章 功能描述.......................................................3 2.1 功能模块图........................................................3 2.2 功能说明..........................................................3 第三章 系统设计.......................................................4 3.1 流程图............................................................4 3.2 流程图说明........................................................5 第四章 运行结果.......................................................6 第五章 总结...........................................................7 附录一 源代码.........................................................8 II 软件工程设计 五子棋游戏 第一章 需求分析 1.1 总体分析 软件需求分析是软件开发周期的第一个阶段,也是关系到软件开发成败的关键一步。对于任何一个软件而言,需求分析工作都是至关重要的一步。只有通过软件需求分析,才能把软件的功能和性能由总体的概念性描述转化为具体的规格说明,进而建立软件开发的基础。实践表明,需求分析工作进行得好坏,在很大程度上决定了软件开发的成败。 软件需求分析的任务是:让用户和开发者共同明确将要开发的是一个什么样的软件。具体而言,就是通过对问题及其环境的理解、分析和综合,建立逻辑模型,完成新软件的逻辑方案设计。 基于本游戏,首先得为整个棋盘建立一张表格用以记录棋子信息,我们使用一个15*15的二维数组Table[15][15](15*15是五子棋棋盘的大小),数组的每一个元素对应棋盘上的一个交叉点,用‘0’表示空位、‘1’代表己方的子、‘2’代表对方的子;这张表也是今后分析的基础。在此之后还要为两个玩家双方各建立一张棋型表Computer[15][15][4]和Player[15][15][4],用来存放棋型数据。 1.2 初始化 首先,建立盘面数组Table[15][15]、对战双方的棋型表Computer[15][15][4]和Player[15][15][4]并将它们清零以备使用;然后初始化显示器、键盘、鼠等输入输出设备并在屏幕上画出棋盘(棋盘可以不显示)。 1.3 主循环控制模块 控制下棋顺序,当轮到某方下子时,负责将程序转到相应的模块中去,主要担当一个调度者的角色。 1.4 玩家下子 当轮到玩家下时,您通过键盘或鼠标在棋盘上落子,程序会根据该点的位置,在Table[15][15]数组的相应地方记录‘2’,以表明该子是玩家下的。 软件工程设计 1.5 盘面分析填写棋型表 您在下五子棋时,一定会先根据棋盘上的情况,找出当前最重要的一些点位,如“活三”、“冲四”等;然后再在其中选择落子点。先来分析己方的棋型,我们从棋盘左上角出发,向右逐行搜索,当遇到一个空白点时,以它为中心向左挨个查找,如果遇到己方的子则记录然后继续,如果遇到对方的子、空白点或边界就停止查找。左边完成后再向右进行同样的操作;最后把左右两边的记录合并起来,得到的数据就是该点横向上的棋型,然后把棋型的编号填入到Computer[x][y][n]中就行了(x、y代表坐标,n=0、1、2、3分别代表横、竖、左斜、右斜四个方向)。而其他三个方向的棋型也可用同样的方法得到,当搜索完整张棋盘后,己方棋型表也就填写完毕了。然后再用同样的方法填写对方棋型表。 注意:所有棋型的编号都要事先 定义好,越重要的号数越大! 1.6 对方下子 有了上面填写的两张棋型表,就是遍历棋型表Computer[15][15][4]和Player[15][15][4]找出其中数值最大的一点,在该点下子即可。但这种算法的弱点非常明显,只顾眼前利益,不能顾全大局,这就和许多五子棋初学者一样犯了“目光短浅”的毛病。如果在这儿下子将会形成对手不得不防守的棋型(例如:‘冲四’、‘活三’);那么下一步对手就会照您的思路下子来防守您,如此一来便完成了第一步的预测。这时再调用模块4对预测后的棋进行盘面分析,如果出现了‘四三’、‘双三’或‘双四’等制胜点,那么己方就可以获胜了(当然对黑棋而言‘双三’、‘双四’是禁手,另当别论);否则照同样的方法向下分析,就可预测出第二步、第三步„„ 等一等,要是盘面上没有对手必须防的棋型,哪该怎么办呢?进攻不成的话就得考虑防守了,将自己和对手调换一下位置,然后用上面的方法来预测对手的棋,这样既可以防住对手巧妙的攻击,又能待机发动反击,何乐而不为呢! 1.7 胜负判断 务须多言,某方形成五子连即获胜;若黑棋走出‘双三’、‘双四’或长连即以禁手判负。 软件工程设计 第二章 功能描述 2.1 功能模块图 五子棋游戏判断棋盘是否已满判断是否出错并提示判断那方获胜交替循环双方下棋 图2.1 功能模块图 2.2 功能说明 该五子棋程序基本上实现了五子棋的游戏功能,有双方下棋的界面及最终判定结果的界面。同时该游戏采用二维坐标实现,明了易懂,方便玩家在游戏过程中的基本操作,使游戏更加简便。在细节方面,该系统提供实时存储功能,随时记录为完成的游戏,使用户可以很好的处理意外中断的情况。该游戏基本实现了游戏的一些要求和特征。在游戏的源程序及文档方面,我们也严格遵守软件工程思想,立足实验要求,确定任务,需求分析,设计和编码,每个步骤力求清晰易懂。原代码注释详尽,各功能模块功能分明,可移植性强。当然该系统也有很多不足的地方,第一次进行独立的课程设计,也有很多细节方面是考虑到的,这款游戏也是在不断的调试和修改中产生和完善的。希望老师能够指出不足,帮助我不断提高。 软件工程设计 第三章 系统设计 3.1 流程图 开始棋盘已满是输出平局否“0”方选位置判断该位置是否有棋有另找位置无“0”方落子否判断“0”方是否获胜是输出“0”方获胜否棋盘已满是输出平局结束否“x”方选位置判断该位置是否有棋有另找位置无“x”方落子判断“x”方是否获胜是输出“x”方获胜 图3.1 流程图 软件工程设计 3.2 流程图说明 本程序定义了各种操作函数、各种状态判定宏,思想明确,思路清晰。各个判断选择了不同路径,因此继续进行或输出结果。程序中,“循环”的利用非常直接和清晰,双方交替下棋,因此循环往复。最终决出胜负或最终平局。分析时,也考虑了许多种情况,针对各个情况均作出了相对措施和解决方案。 程序采用循环进行双方交替下棋,并进行了很多判断。首先判断棋盘是否已满,若棋盘已满,则输出平局,结束游戏;若棋盘未满,则继续进行。然后判断“0”方是否胜出,若“0”方获胜,则输出“0”方获胜,结束游戏;若“0”方没有获胜,则继续进行。再判断“x”方是否获胜,若“x”方获胜,则输出“x”方获胜,结束游戏;若“x”方没有获胜,则继续进行。回到“首先”的判断。如此循环„„ 软件工程设计 第四章 运行结果 图4.1 运行结果初始图 图4.2 游戏过程图 图4.3 软件工程设计 图4.4 图4.5 软件工程设计 图4.6 图4.7 软件工程设计 图4.8 游戏进行图 图4.9 “0”方获胜图 软件工程设计 附录一 源代码 #include using namespace std; int Hsheng(char a[][15]); //判断o子是否获胜的函数 int Bsheng(char a[][15]); //判断x子是否获胜的函数 int he(char a[][15]); //判断是否平局(也就是棋盘下满了)的函数 void qipan(char a[15][15]) //执行输出棋盘命令 { cout<<“本游戏采用二维数组实现,棋盘为15X15的二维直角坐标系,均从1到15,祝二位游戏愉快.”;for(int i=0;i<15;i++) //打印棋盘 { for(int j=0;j<15;j++)cout< } } int main(){ char a[15][15]; int x,y; for(int i=0;i<15;i++) for(int j=0;j<15;j++) a[i][j]=' ';qipan(a); while(1)//用循环语句执行o,x交替下子,这些while语句看起来似乎是个死循环~实际上都会经过break结束 { int a1=1; while(1) { for(;a1;) { cout<<“请输入o子下的位置:”; //输入o子的位置 cin>>x>>y;if(a[x][y]=='o'||a[x][y]=='x') //判断是否已有子 {cout<<“已有子请重下”<<“,”;continue;} else if(x>=15||y>=15){cout<<“输入错误请重输”<<“,”;continue;} else { a[x][y]='o';a1=0;} } break;} 软件工程设计 qipan(a); //下好o子后将棋盘显示 if(Hsheng(a)) //判断o子是否已经获胜 {cout<<“o子获胜”< while(1) //下x子 { cout<<“请输入x子下的位置:”; cin>>x>>y; if(a[x][y]=='o'||a[x][y]=='x'||x>=15||y>=15) { for(;a[x][y]=='o'||a[x][y]=='x';) { cout<<“已有子请重下”; cout<<“请输入x子下的位置:”; cin>>x>>y;continue;} for(;x>=15||y>=15||x;) { cout<<“输入错误请重输”<<“,”; //判断输入棋子位置是否正确 cout<<“请输入x子下的位置:”; cin>>x>>y;continue;} a[x][y]='x';break; } else {a[x][y]='x';break;} } qipan(a); //再一次输出棋盘 if(Bsheng(a)) //判断x子是否已经获胜 {cout<<“x子获胜”< if(he(a)) //判断是否平局 {cout<<“平局”< } return 0; } int Hsheng(char a[][15]){ int i,j; //判断横着的5个是否都相等 for(i=0;i<15;i++) for(j=0;j<15;j++) if(a[i][j]=='o'&&a[i][j+1]=='o'&&a[i][j+2]=='o'&&a[i][j+3]=='o'&&a[i][j+4]=='o') return 1; for(j=0;j<15;j++) //判断竖着的5个是否都相等 for(i=0;i<15;i++) if(a[i][j]=='o'&&a[i+1][j]=='o'&&a[i+2][j]=='o'&&a[i+3][j]=='o'&&a[i+4][j]=='o') 软件工程设计 return 1; for(i=0;i<15;i++) //判断左斜5个 for(j=0;j<15;j++) if(a[i][j]=='o'&&a[i+1][j+1]=='o'&&a[i+2][j+2]=='o'&&a[i+3][j+3]=='o'&&a[i+4][j+4]=='o') return 1; for(i=0;i<15;i++) //右斜5个 for(j=14;j>3;j--) if(a[i][j]=='H'&&a[i+1][j-1]=='o'&&a[i+2][j-2]=='o'&&a[i+3][j-3]=='o'&&a[i+4][j-4]=='o') return 1; return 0; } int Bsheng(char a[][15]) //同o,只是改字符 { int i,j; for(i=0;i<15;i++) for(j=0;j<15;j++) if(a[i][j]=='x'&&a[i][j+1]=='x'&&a[i][j+2]=='x'&&a[i][j+3]=='x'&&a[i][j+4]=='x') return 1; for(j=0;j<15;j++) for(i=0;i<15;i++) if(a[i][j]=='x'&&a[i+1][j]=='x'&&a[i+2][j]=='x'&&a[i+3][j]=='x'&&a[i+4][j]=='x') return 1; for(i=0;i<15;i++) for(j=0;j<15;j++) if(a[i][j]=='x'&&a[i+1][j+1]=='x'&&a[i+2][j+2]=='x'&&a[i+3][j+3]=='x'&&a[i+4][j+4]=='x') return 1; for(i=0;i<15;i++) for(j=14;j>3;j--) if(a[i][j]=='x'&&a[i+1][j-1]=='x'&&a[i+2][j-2]=='x'&&a[i+3][j-3]=='x'&&a[i+4][j-4]=='x') return 1; return 0; } int he(char a[][15]) { for(int i=0;i<15;i++) for(int j=0;j<15;j++) { if(a[i][j]==' ') //当棋盘全部子都不是' '时才能return 1,即棋盘已下满 return 0; } return 1; } 网络092刘砺锋 设计一个简单的五子棋游戏 一、设计目标与内容 1.了解Windows编程的基础知识,掌握MFC应用程序的基本知识;2.基本掌握面向对象程序设计的基本思路和方法; 3.掌握用VC++开发应用程序的的一般步骤和方法; 4.能够利用所学的基本知识, 设计一个简单的五子棋游戏,具有以下功能:①数据结构的设计;五子棋棋盘的绘制。②两人下棋时,两人下棋算法的设计。③两人下棋时,判断任一方获胜的算法的设计。 二、设计要求 1.用VC++进行编码,实现应用程序的功能。注重编码质量,代码要有适当的注释; 提交设计报告一份(课程设计任务书、目录、主要的数据结构、设计的基本思路、设计的步骤及主要代码、心得体会、参考文献)。总体设计 运行时效果如下: 网络092刘砺锋 图3-1 这个程序只能进行两个人之间的对弈,不能进行人机对弈,由于时间和个人能力的原因所以人机对弈的算法就没有写出。同时程序中也存在着很多漏洞,但基本的功能都已经实现,还有待继续改进。 详细设计 新建工程game_wzq 网络092刘砺锋 选择单文档应用程序,在Step 4 of 6中先中Windows Sockets复选框。如下图: 图3-2 资源编辑 黑白位图Bitmap以表示棋盘上面的棋子: IDB_BLACK DB_WHITE 黑白鼠标Cursor以替换当前鼠标: IDC_CURSOR1 黑棋子 网络092刘砺锋 IDC_CURSOR2 白棋子 黑白图标Icon以显示在状态栏供以提示 IDI_BLACK IDI_WHITE 菜单以供操作: 开始: ID_START 保存: ID_SAVE 打开: ID_OPEN 如下图所示: 图3-3 变量函数 首先,为了实现状态栏的应用,我们必须更改它的变量: 网络092刘砺锋 在MainFrm.h文件里面,把CStatusBar m_wndStatusBar 为public 接着是在game_wzqView.h文件里面添加变量函数: //两个鼠标 HCURSOR hcursorwhite;HCURSOR hcursorblack;//棋盘数组 int wzq[19][19];// colorwhite TRUE时白棋下,否则黑棋下 bool colorwhite;//棋子位图 CBitmap m_bmblack;CBitmap m_bmwhite;//保存文件 void Save();//检查是否结束 void over(CPoint point);//鼠标操作 afx_msg void OnLButtonUp(UINT nFlags, CPoint point);//鼠标图形更换 afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); 网络092刘砺锋 //菜单的开始 afx_msg void OnStart();//菜单的保存 afx_msg void OnSave();//菜单的打开 afx_msg void OnOpen(); 具体实现 1、由于我们的游戏的棋盘大小是一定的,不能改变大小的,是应该符合要求的。在如下函数添加设置窗口大小的语句: BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs){ if(!CFrameWnd::PreCreateWindow(cs)) return FALSE;// TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs cs.dwExStyle=cs.dwExStyle|WS_EX_TOPMOST;cs.style=WS_SYSMENU|WS_OVERLAPPED|WS_MINIMIZEBOX;//设置窗口大小:400*340 cs.cx=450;cs.cy=500; 网络092刘砺锋 return TRUE;} 2、初始化变量: 在构造函数里添加初始代码: CGame_wzqView::CGame_wzqView(){ //Load鼠标图像和棋子位图 hcursorblack=AfxGetApp()->LoadCursor(IDC_CURSOR1); hcursorwhite=AfxGetApp()->LoadCursor(IDC_CURSOR2);m_bmwhite.LoadBitmap(IDB_WHITE);m_bmblack.LoadBitmap(IDB_BLACK);//清理棋盘 //数组值为0表示没有棋子 for(int i=0;i<19;i++)for(int j=0;j<19;j++)wzq[i][j]=0;//白棋先下 colorwhite=true;} 网络092刘砺锋 3、画棋盘: 在OnDraw(CDC* pDC)函数中画棋盘,由于在游戏过程中有可能重画棋盘,而那时棋盘上面有棋子,所以,我们在这个函数里面必须有画棋子的语句。 我们用数组的做为1表示白棋,-1表示黑棋。void CGame_wzqView::OnDraw(CDC* pDC){ CGame_wzqDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);//画背景 CBrush mybrush1;mybrush1.CreateSolidBrush(RGB(192,192,192));CRect myrect1(0,0,1200,800);pDC->FillRect(myrect1,&mybrush1);//画棋盘框线 CPen mypen;CPen*myoldPen; 网络092刘砺锋 mypen.CreatePen(PS_SOLID,1,RGB(0,0,0));myoldPen=pDC->SelectObject(&mypen);for(int i=0;i<19;i++){ pDC->MoveTo(40,40+i*20);pDC->LineTo(400,40+i*20);pDC->MoveTo(40+i*20,40);pDC->LineTo(40+i*20,400);} //重画时显示存在的棋子 CDC Dc;if(Dc.CreateCompatibleDC(pDC)==FALSE)AfxMessageBox(“Can't create DC”);for(int n=0;n<19;n++) for(int m=0;m<19;m++) if(wzq[n][m]==1) { //显示白棋 Dc.SelectObject(m_bmwhite); pDC->BitBlt(n*20+32,m*20+32,160,160,&Dc,0,0,SRCCOPY); 网络092刘砺锋 } else if(wzq[n][m]==-1) { //显示黑棋 Dc.SelectObject(m_bmblack); pDC->BitBlt(n*20+32,m*20+32,160,160,&Dc,0,0,SRCCOPY); } } 4、设置鼠标: 棋盘画好了,接下来就是下棋了。但鼠标并没有像我们上面说的那样变成白棋,加函数如下: BOOL CGame_wzqView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message){ if(nHitTest==HTCLIENT){ //白棋下,显示白棋鼠标 if(colorwhite) { //调用主框架里面的状态栏 网络092刘砺锋 CMainFrame *pFrm=(CMainFrame*)AfxGetApp()->m_pMainWnd; CStatusBar*pStatus=&pFrm->m_wndStatusBar; if(pStatus) { pStatus->GetStatusBarCtrl().SetIcon(0,AfxGetApp()->LoadIcon(IDI_WHITE)); pStatus->SetPaneText(0,“白棋下”); } SetCursor(hcursorwhite); } //显示黑棋鼠标 else { SetCursor(hcursorblack); CMainFrame*pFrm=(CMainFrame*)AfxGetApp()->m_pMainWnd; CStatusBar*pStatus=&pFrm->m_wndStatusBar; if(pStatus) { 网络092刘砺锋 //显示图像 pStatus->GetStatusBarCtrl().SetIcon(0,AfxGetApp()->LoadIcon(IDI_BLACK)); //显示文字 pStatus->SetPaneText(0,“黑棋下”); } } return 1;} return CView::OnSetCursor(pWnd, nHitTest, message);} 5、下棋操作: 这就涉及到OnLButtonDown(UINT nFlags, CPoint point)和OnLButtonUp(UINT nFlags, CPoint point)两个函数了。要用哪一个或用两个?用Down函数时是在鼠标按下时放下棋子,可是,要是我们按下后意识到按错了怎么办;那就改用Up函数,表示当鼠标键松开时放下棋子。OK!添加函数如下: void CGame_wzqView::OnLButtonUp(UINT nFlags, CPoint 网络092刘砺锋 point){ CView::OnLButtonUp(nFlags, point);CDC *pDC=GetDC();CDC Dc;if(Dc.CreateCompatibleDC(pDC)==FALSE) AfxMessageBox(“Can't create DC”);//是否在棋盘内 if(point.x>30&&point.x<410&&point.y>30&&point.y<410){ int px=(point.x-30)/20; int py=(point.y-30)/20; //是否已经有棋子 if(colorwhite&&wzq[px][py]==0) { Dc.SelectObject(m_bmwhite); pDC->BitBlt(px*20+32,py*20+32,160,160,&Dc,0,0,SRCCOPY); //表示存在白棋 wzq[px][py]=1; //检查是否结束 网络092刘砺锋 over(point); //换黑棋下 colorwhite=false; } else if(wzq[px][py]==0) { Dc.SelectObject(m_bmblack); pDC->BitBlt(px*20+32,py*20+32,160,160,&Dc,0,0,SRCCOPY); wzq[px][py]=-1; over(point); colorwhite=true; } } } 由上面可以看出,当鼠标键松开时判断,如果那个位置没有棋子,则放下,并把棋盘数组赋相应的值:1或- 16、是否结束: 网络092刘砺锋 接着是用一个over()函数判断是否结束,是则结束并重新开始;否则,接着把鼠标变成对方棋子,表示对方下棋。那over()函数又是怎样的呢? 此函数是利用刚下棋的位置为中心,检查它各个方向上的连续五个棋子是否同色,是则结束并重新开始。 然而,我们又是怎样判断一个方向上的五个棋子的同色的?这就涉及地为什么我要把五子棋数组赋值为1和-1的问题。因为这样有一个好处:利用连续五个棋子的值相加,如果它们的值的绝对值等于5,则说明是同色。当然,这只是这样赋值的一点作用,真正的作用将在后面介绍。添加如下: void CGame_wzqView::over(CPoint point){ //获取鼠标指向数组位置,即中心位置 int x=(point.x-30)/20;int y=(point.y-30)/20;//计算开始判断的坐标 xx,yy int xx,yy;if(x<4)xx=0;else xx=x-4;if(y<4) 网络092刘砺锋 yy=0;else yy=y-4;int i,j,a;//横向判断 for(i=xx;i<15;i++){ a=0;for(j=i;j { a=a+wzq[j][y];//五个都是白棋 if(a==5){ AfxMessageBox(“白棋胜!”);//重新开始 OnStart(); return; } //五个都是黑棋 if(a==-5){ 网络092刘砺锋 AfxMessageBox(“黑棋胜!”);OnStart(); return;} } } //竖向判断 for(i=yy;i<15;i++){ a=0;for(j=i;j return;} if(a==-5) 网络092刘砺锋 { AfxMessageBox(“黑棋胜!”);OnStart(); return;} } } //向右下角 //判断起点位置 if(x yy=y-x;} else { if(yy==0) xx=x-y;} //参数over=1时退出循环 int over=0;do 网络092刘砺锋 { a=0; for(i=0;i<5;i++) { if((xx+i)<19||(yy+i)<19) { a=a+wzq[xx+i][yy+i]; if(a==5) { AfxMessageBox(“白棋胜!”); OnStart(); return; } if(a==-5) { AfxMessageBox(“黑棋胜!”); OnStart(); return; } } //到了边界 else 网络092刘砺锋 over=1; } xx+=1; yy+=1;} while(over==0);//向左下角 if(y>(18-x)){ if(x>13) { yy=y-(18-x); xx=18; } else { yy=y-4; xx=x+4; } } else { 网络092刘砺锋 if(y<5) { xx=x+y; yy=0; } else { yy=y-4; xx=x+4; } } over=0;do { a=0; for(i=0;i<5;i++) { if((xx-i)>=0||(yy+i)<19) { a=a+wzq[xx-i][yy+i]; if(a==5) { 网络092刘砺锋 AfxMessageBox(“白棋胜!”); OnStart(); return; } if(a==-5) { AfxMessageBox(“黑棋胜!”); OnStart(); return; } } //到了边界 else over=1; } xx-=1; yy+=1;} while(over==0);} 网络092刘砺锋 文件保存和读取 1、保存文件函数是一个菜单选项。它的作用就是保存当前游戏的状态。首先,我们应该为我们自己的文件定义一个后缀名:.wzq;接着是打开保存文件的公共对话框,如果确定,则表示保存,那么就先获取文件名,然后按照一定的顺序保存各个点的数组的值,最后保存当前是哪种颜色下棋。void CGame_wzqView::OnSave(){ //设置保存的文件,后缀名wzq CFileDialog dlg(FALSE,“wzq”,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,“(*.WZQ)|*.wzq|All Files|*.*||”,this);//如果公共类对话框为确定 if(dlg.DoModal()==IDOK)//获取文件名 dlg.GetFileName();//否则,退出 else return;//字符串变量 CString str;int i,j; 网络092刘砺锋 CStdioFile file;//如果有问题,退出 if(file.Open(dlg.GetFileName(),CFile::modeCreate|CFile::modeWrite|CFile::typeText)==0){ AfxMessageBox(“save error!”); return;} //循环把棋盘数组的值写进文件 for(i=0;i<19;i++) for(j=0;j<19;j++) { if(wzq[i][j]==-1) file.WriteString(“-1n”); if(wzq[i][j]==0) file.WriteString(“0n”); if(wzq[i][j]==1) file.WriteString(“1n”); } //保存当前下棋颜色 if(colorwhite==true) file.WriteString(“1n”); 网络092刘砺锋 else file.WriteString(“0n”); //关闭文件 file.Close();} 2、读文件就是把我们以前保存的文件打开,读取当前打开文件的内容,并给数组赋值使和文件内容相同,然后可以继续进行游戏。 void CGame_wzqView::OnOpen(){ CFileDialog dlg(TRUE,“wzq”,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,“(*.WZQ)|*.wzq|All Files|*.*||”,this);if(dlg.DoModal()==IDOK) dlg.GetFileName();else return;CString str;int i,j,m;CStdioFile file;if(file.Open(dlg.GetFileName(),CFile::modeRead)==0) 网络092刘砺锋 { AfxMessageBox(“open error!”); return;} CArchive ar(&file,CArchive::load);for(i=0;i<19;i++) for(j=0;j<19;j++) { ar.ReadString(str); sscanf(str,“%d”,&m); if(m==-1) wzq[i][j]=-1; if(m==0) wzq[i][j]=0; if(m==1) wzq[i][j]=1; } ar.ReadString(str); sscanf(str,“%d”,&m); if(m==1) colorwhite=true; else 网络092刘砺锋 colorwhite=false; file.Close(); ar.Close(); Invalidate(false);} OK,现在我们的程序已经完成了,可以两个人进行对弈了。 4.系统总体设计与实现 4.1 总体设计分析 总体设计是软件开发过程中的另一个重要阶段,在这一阶段中将根据需求分析中提出的逻辑模型,科学合理地进行物理模型的设计。这个阶段的主要目标是将反映用户信息需求的逻辑方案转换成物理方案,并为下一阶段提供必要的技术资料。 4.1.1 总体设计原则 (1)整体性:软件是作为统一整体而存在的。因此,在总体设计中要从整个软件的角度进行考虑。 (2)灵活性:为保持软件长久的生命力,要求该手机游戏软件具有很强的环境适应性。为此,游戏软件应具有较好的开放性和结构的可变性。 (3)可靠性:可靠性是指软件抵御外界干扰的能力及受外界干扰时的恢复能力。 (4)经济性:经济性是指在满足游戏软件需求的前提下,尽可能地减小游戏软件的开销。 4.1.2 软件模块总体设计 软件中各模块之间的关系通常利用层次图来表示。它是一种一系列多层次的用树形结构的矩形框描绘数据的层次结构框图。一个单独的矩形框作为树形结构的顶层,各个数据的子集由下面的各层矩形框代表,最底层的各个矩形框代表组成这个数据的实际数据元素(不能再分割的元素),它代表完整的数据结构。这模式非常适合于需求分析阶段的需要,层次方框图对数据结构描绘随着结构精细化也越来越详细。反复细化沿着图中每条路径,从对顶层信息的分类开始,直到确定了数据结构的全部细节为止。 开始游戏重新游戏游戏选项悔棋认输五子棋游戏背景音乐退出游戏先后手设置游戏设置棋盘底纹设置棋盘大小设置游戏帮助帮助关于 图4-1 游戏功能结构 本研究中将游戏软件分为三大模块,如图4-1所示,包括:游戏选项、游戏设置和帮助。按照在调研中搜集的资料对每个模块的功能进行编排制作。依据上述功能的分析,本研究中,将游戏软件在三大模块的基础上又对每一大模块又分为几个子模块: 游戏选项包括六个模块:开始游戏、重新游戏、悔棋、认输、背景音乐和退出游戏。 游戏设置包括三个模块:先后手设置、棋盘底纹颜色设置和棋盘大小设置。 帮助包括两个模块:游戏帮助和关于。 4.2 游戏设计 4.2.1 游戏前的准备 本游戏在开发之前需要做一些前期准备工作,尤其是对于精通五子棋游戏的Java 游戏开发者来说。通常情况下,一款运用起来比较熟练地 J2ME 开发工具 是必不可少的。本游戏使用的是J2ME的简化开发工具 Sun Java(TM)Wireless Toolkit 2.5.2 for CLDC,他需先将Java虚拟机安装调试好之后才能使用。WTK 2.5.2 不带有文本编辑功能,所以需要另寻搭配使用。本游戏采用 Ultra Edit 进行编辑。本游戏需要几张后缀名为.png格式的卡通图,除了一张用作五子棋游戏的 Logo 外,其余的都将在游戏中使用。4.2.2 游戏界面和事件驱动设计 游戏的界面设计采取传统游戏界面风格,如图4-2所示。游戏设计中采用传统界面游戏风格,首先启动游戏,然后进入游戏开始界面,界面中放置“设置”、“开局”、“帮助”、“关于”四个选项供玩家选择。其中“设置”选项主要是对游戏的相关功能进行设置,如游戏难度设置。另外还有“悔棋”、“重玩”等项目的设置。除此之外还包括查看游戏帮助、游戏介绍等。 图4-2 游戏界面设计 所谓事件驱动,简单地说就是你点什么按钮(即产生什么事件),电脑执行什么操作(即调用什么函数)。当然事件不仅限于用户的操作。我们知道,事件是事件驱动的核心自然是。从事件角度说,一个事件收集器、一个事件发送器和一个事 件处理器组成了事件驱动程序的基本结构。事件收集器专门负责收集包括来自硬件的(如时钟事件等)、来自用户的(如键盘、鼠标事件等)及来自软件的(如应用程序本身、操作系统等)的所有事件。将收集器收集到的事件分发到目标对象中则由事件发送器负责完成。具体的事件响应工作则由事件处理器完成,它需要运用虚函数机制(函数名取为类似于 Handle Msg 的一个名字),它往往要到实现阶段才完全确定。事件处理器对于框架的使用者来说是他们唯一能够看到的。棋类游戏通常具备两个重要特性,首先是对战双方轮流落子,其次是落子间隔通常是不确定的,尤其是对战后期,可能每一步棋都要经过深思熟虑,无论是人还是计算机,都无法对时间间隔有事先的预期。基于以上两个特性,本游戏摒弃了大多数游戏采用的线程或定时器驱动游戏的方法,而采用了事件驱动的方法,即玩家的键盘或触摸笔触发游戏的下一个动作。事件驱动大大减少了不必要的工作量,只有玩家发出消息时,计算机才启动运算,而在玩家思考期间,计算机不做任何运算和重绘操作。4.2.3 游戏的类设计 五子棋游戏属于二维棋类游戏,因此可以定义一个 Chesses 类来表示棋子,用一个 Chess 类型的二维数组来包含棋盘上的所有棋子,对于该棋子玩家的区分使用Chesses 的 boolean 型的变量 is Player1 来区分。可以考虑直接生成数组的每一个对象而不是在数组建立后,而是把每一个棋子对象(Chesses)放在游戏的进行中生成,这主要是考虑到移动设备的资源有限,尽可能减少系统资源占用。这样在游戏进行时,可以避免还没有下的棋子在一开始就占用了系统内存,玩家每下一步棋,在数组相应位置生成该棋子的对象。 对于游戏中的每一类的设计,首先就是一个 MIDlet 类,Gobang 类继承自MIDlet 类,通过方法 start App,pause App,destroy App 来通知游戏的开始,暂停和销毁结束,用于连接设备的应用程序管理器(Application Manager)。 本游戏共由7个类组成,它们各自的功能如下: (1)Gobang MIDlet类 负责程序的启动和屏幕之间的切换; (2)Gobang Canvas 类 玩家的对战平台,他继承于 Canvas 类;(3)Setting 类 用于创建游戏的各项设置参数表单; (4)Gobang Logic 类 游戏的逻辑类,负责胜负判断和计算机落子; (5)Dot 类 棋子类,包含了棋子的位置信息;(6)Help 类 游戏的帮助类,包含五子棋的一些常识信息和五子棋教学内容;(7)About类 游戏的关于类,包含游戏的版本、版权等信息。各个类之间的关系如图4-3所示: 图4-3游戏类设计 4.2.4 游戏的流程设计 对于棋盘界面的更新,游戏进行绘制棋子时是按照棋子的二维数组来完成的,玩家下棋后,设置is Player1 值,程序修改数组相应位置,然后重新绘制(repaint)。为了使游戏的操作尽可能的简便,本文设计上不在游戏进入时设计菜 单,玩家可以直接开始对战,而是在开始游戏的过程中设置重新开始和退出的按钮。即一键开始,运行即玩,重来或退出都使用一键操作。游戏流程的设计依据主要是游戏的界面设计和游戏的类的设计。游戏启动时,Gobang MIDlet 对象先显示游戏的主屏幕,在屏幕下方一侧是出软键(软键指描述抽象客户端设备如何显示),另一侧是用软件构成的菜单,菜单元素主要有“开局”、“游戏设置”、“游戏帮助”、“关于”选项。当玩家选择“游戏设置”软键时,则显示游戏参数设置表单;当玩家选择“开局”软键时,则显示游戏对战主界面;当玩家选择“游戏帮助”软键时,则显示游戏帮助表单;当玩家选择“关于”软键时,则显示游戏关于表单。玩家进入游戏参数设置表单,当玩家按下“确定”软键时,则确认当前游戏参数,返回游戏主屏幕;当玩家按下“取消”软键时,则放弃此次对游戏的修改,直接返回游戏主屏幕。玩家进入游戏对战画布,对战中画布有两个软键,当玩家按下“返回主菜单”软键时,则退出游戏到达游戏主菜单;当玩家按下“悔棋”软键时,则进行悔棋操作;当游戏结束时,“悔棋”软键被换成了“重玩”软键。玩家进入游戏介绍表单,当玩家按下“确定”软键时,返回游戏主屏幕。4.2.5 游戏算法的设计 1、五子棋的获胜组合 有哪些获胜组合是在一场五子棋的游戏中计算机必须要知道的,因此,获胜组合的总数必须要求得。在本文中我们假定当前的棋盘为15*15: (1)每一列的获胜组合是11,共15列,计算水平方向的获胜组合数,所以水平方向的获胜组合数为:11*15=165。 (2)每一行的获胜组合是11,共15列,则可计算垂直方向的获胜组合总数,垂直方向的获胜组合数为:11*15=165。 (3)同理,可计算正对角线方向的获胜组合总数,正对角线上的获胜组合总数为11+(10+9+8+7+6+5+4+3+2+1)*2=121。 (4)计算反对角线上的获胜组合总数。计算反对角线方向的获胜组合总数可计算为11+(10+9+8+7+6+5+4+3+2+1)*2=121。这样可计算得所有的获胜组合数为:165+165+121+121=572。 2、设计获胜棋型 通过上面的计算,一个15*15的屋子棋盘在此已经计算出了会有572中获胜方式,因此,我们就可以利用数组建立一些常规棋型,棋型的主要作用是: (1)判断是否有任何一方获胜; (2)根据当前格局判断最可能的落子方式。 然而在现实中,高手留给我们的经验就是把握前奏,如“冲四”、“活三”,除了“连五”以外,这些也是同向胜利的捷径。 3、攻击与防守 获胜棋型的算法是中性的,不区分计算机和玩家,这就涉及到攻击和防守何者优先的问题。而许多高手都认为五子棋的根本是“防守”,“攻击”是灵魂。进攻是取胜的手段,是防守的延续和发展。许多经验和研究表明,一个棋手只要掌握了全面的、基本的防守原理和技巧,就能和比自己棋力高一个等级的进攻型选手对抗,起码能立于不败之地。对手进过越偏激,则防守的效果越好。没有进攻的防守就像只开花不结果,没有实际意义,顽强的防守是反攻的前奏,没有进攻的延续,防守也失去了价值。而这缺一不可。根据以上原理,计算机在接受最佳的攻击位置之前,还要计算当前玩家的最佳攻击位置。如果玩家存在最佳攻击位置,那么计算机就将下一步的棋子摆在玩家的最佳攻击位置上以阻止玩家的进攻,否则计算机便将棋子下在自己的最佳攻击位置上进行攻击。 4、用到的典型算法(1)坐标变换算法 游戏的实质其实是对所下棋子的位置进行操作和判断,因此将己方、对方以及棋盘上空点的位置坐标存储在相应的List中。我对所下棋子的坐标进行了处理,因为我所采用的棋盘为15*15,所以棋子横坐标为0到14的整数,纵坐标也为0到14的整数。因此,每次在棋盘上下子之后,计算机在存储该点的坐标时,便要对坐标进行加工。假设左上角点为firstPoint,它的实际坐标为(x1,y1),而我是将它作为(0,0)存储的,其它的坐标,其它点都是以该点为标准进行变换的,假设棋盘上每个格子的宽度为w,某实际点为(x2,y2),变换后的坐标为(x,y),x=(x2-x1)/w,y=(y2-y1)/w。 (2)胜负判断算法 胜负判断的规则很简单,就是判断游戏双方的棋子在同一条水平线、同一条竖线或是同一条斜线上谁先出现5个连续的棋子,谁先达到这样的目标,谁就获得胜利。在本设计中,是在每次下完一个子后进行判断,看己方是否达到了胜利的标准,若胜利游戏便结束;否则,游戏继续。 (3)人工智能算法 人工智能算法的主体思想分为以下三个步骤: 第一步:根据双方的当前的形势循环地假设性的分别给自己和对方下一子(在某个范围内下子),并判断此棋子能带来的形势上的变化,如能不能冲4,能不能形成我方或敌方双3等。 第二步:根据上一步结果,组合每一步棋子所带来的所有结果(如某一步棋子可能形成我方1个活3,1个冲4(我叫它半活4)等),包括敌方和我方的。 第三步:根据用户给的规则对上一步结果进行排序,并选子(有进攻形、防守形规则)。 5、典型类的具体设计(1)应用程序类 Gobang 类用于连接设备的应用程序管理器(Application Manager),Gobang类继承自 MIDlet 类,通过 Gobang 类的方法 start App,pause App,destroy App 来通知游戏的开始,暂停和销毁结束。源代码如下: package com.occo.j2me.game.gobang;import javax.microedition.lcdui.Display; import javax.microedition.midlet.MIDlet;public class Gobang extends MIDlet //定义游戏界面的 Canvas 类 Gobang Canvas 的对象 Gobang public { Gobang Canvas gobang;Gobang(){ super(); gobang=new Gobang Canvas(this);//生成 Gobang Canvas 类的对象 gobang } protected void start App(){ Display.get Display(this).set Current(gobang); } protected void pause App(){ } protected void destroy App(boolean arg0){ }} //在屏幕上绘出游戏见面 gobang(2)游戏界面类 Gobang Canvas 类继承自 Canvas,游戏的核心类是 Gobang Canvas 类,此类将完成游戏的绘图、互动、控制、逻辑、等所有功能,此类的框架代码如下: Package com.occo.j2me.game.gobang;import javax.microedition.lcdui.Displayable;import javax.microedition.lcdui.Command;import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Command Listener;public Gobang Canvas(Gobang gobang){ this.gobang=gobang; } protected void paint(Graphics g){ } import javax.microedition.lcdui.Graphics;public class Gobang Canvas extends Canvas implements Command Listener{protected Gobang gobang; public Gobang Canvas(){ } }(3)棋子类 整个棋盘是一个 Chesses 类型的二维数组,棋盘上的每一个棋子都对应着一个Chesses 的对象,此类定义了一个棋子,源代码如下: package com.occo.j2me.game.gobang;public Chesses(){ } public class Chesses {boolean is Player1; public Chesses(boolean is Player1){ this.is Player1=is Player1; }} 4.3 游戏实现 4.3.1 主类的实现 YpkWuZiQiActivity类是五子棋游戏的主类,同时也是五子棋游戏的入口,它继承自Activity类。进入程序后,首先调用init()方法,init()方法通过调用setContentView(R.layout.welcomeview)显示登录该游戏的第一个界面。welcomeview.xml是一个布局文件,里面存储了界面信息。该界面中有四个Button,分别为welButton1、welButton12、welButton3、welButton4,点击每个Button都会触发一个事件,其中点击welButton1和welButton2还会给它的成员变量FIGHTINGMODE赋值,因为在人人对战和人机对战是写在同一个ChessBoard类中的,所以需要通过FIGHTINGMODE的值来区分是人人对战还是人机对战。 点击welButton1时,FIGHTINGMODE=1,然后会调用initTwo()方法,该方法通过调用setContentView(R.layout.chess)方法,来显示对战的界面。chess.xml文件存储了对战界面的信息。在chess.xml文件中调用了ChessBoard类,该类中主要定义了棋盘的信息,下文会对该类做具体的介绍的。在对战界面中也有四个Button,分别是b1、b2、b3、b4。 首先来介绍一下b2,该Button的功能是返回主页,调用init()方法就可以实现。b3的功能是重新开始,这个也只需要调用initTwo()方法。b3的功能是退出,调用了系统方法:System.exit(1)。下面重点介绍一下b1,该Button的功能是悔棋。该Button设定的点击事件详细内容如下: b1.setOnClickListener(new OnClickListener(){ public void onClick(View v){ ChessBoard chess =(ChessBoard)findViewById(R.id.chess);Point temp = null;if(chess.whoRun == 1){ if(chess.firstPlayer.getMyPoints().size()>=1 &&chess.secondPlayer!=null){ temp=chess.secondPlayer.getMyPoints().get(chess.secondPlayer.getMyPoints().size()-1); chess.secondPlayer.getMyPoints().remove(temp);chess.freePoints.add(temp);temp=chess.firstPlayer.getMyPoints().get(chess.firstPlayer.getMyPoints().size()-1);chess.firstPlayer.getMyPoints().remove(temp);chess.freePoints.add(temp);chess.freshCanvas(); } } if(chess.whoRun == 2){ if(chess.firstPlayer.getMyPoints().size()>=1 && chess.secondPlayer!=null){ temp=chess.firstPlayer.getMyPoints().get(chess.firstPlayer.getMyPoints().size()-1);chess.firstPlayer.getMyPoints().remove(temp);chess.freePoints.add(temp);temp=chess.secondPlayer.getMyPoints().get(chess.secondPlayer.getMyPoints().size()-1);chess.secondPlayer.getMyPoints().remove(temp);chess.freePoints.add(temp);chess.freshCanvas(); } })首先获取ChessBoard对象,该对象继承自View,详细的定义了棋盘信息,主要负责显示棋盘的内容。接下来判断一下触发悔棋事件的是哪一个玩家,再判断是否符合悔棋的条件,这个条件很简单,就是棋盘上至少要有两个棋子。之后便进行悔棋操作,分别将两个玩家最后下的棋子取出,程序实现就是将两个ArrayList的最后一个元素remove出来,再分别放到记录棋盘中没有棋子的点的} } 集合中,最后更新一下画布,主要是调用ChessBoard的invalidate()方法。通过以上步骤之后,呈现在我们面前的便是悔完棋的画面了。 点击welButton2时,FIGHTINGMODE=2,之后的步骤便会点击welButton1是相同的了,不同的是,由于对战模式的改变,从人人对战变成了人机对战。 点击welButton 3时,通 过 initThree() 方 法 调 用setContentView(R.layout.netchess)方法实现网络对战。详细的对战实现细节将会在下文一一介绍。在这个界面中只保留了两个Button:b2和b4。这两个Button所实现的功能和上面的b2和b4是相同的。 最后,welButton4比较简单。它所实现的功能为退出应用程序,调用System.exit(1)方法。4.3.2 游戏设置类的实现 游戏设置表单用来对游戏参数进行设置,包括棋盘大小、先手选择、智能级别。表单中使用了 Gauge 和 Choice Group 两种高级用户界面组件。 1、棋盘尺寸选择 标准的五子棋棋盘为 15*15,但为了满足不同玩家的需求,这里提供了大小为10*10 到 20*20 的棋盘,用户可以通过 Gauge 组件改变。棋盘的最小值为 10,而Gauge 组件的最小值为 0,所以当前的 Gauge 值需要角上 10 才是当前棋盘大小。创建 Gauge 组件的代码如下: form = new Form(“ 游戏设置”);// 创建参数设置表单并添加标签 gauge Size = new Gauge(“棋盘规格: ” + board Size + “ X ” + board Size, true, 10, board Size-10);//棋盘规格 form.append(gauge Size); 图4-4 棋盘尺寸的设计 在Gauge交互模式下可以为Gauge对象所在的表单对象绑定一个Item State Listener 事件监听器,并在监听器上捕捉 Gauge 对象的事件,当 Gauge 的值发生变化时就会触发事件。这里将根据 Gauge 的当前值改变标签,显示当前的棋盘大小。其代码如下: public void item State Changed(Item item){ if(item == gauge Size)//当 Gauge 组件发生变化时 { int bs = gauge Size.get Value()+ 10;//获取当前的 Gauge 值并计算棋盘大小(加10) gauge Size.set Label(“棋盘规格: ” + bs + “ X ” + bs);//改变 Gauge 组件的标签 } } 2、难度选择 游戏的难易程度根据计算机的智能级别来控制,创建及添加选项的方法和复选框一样,所不同的是在创建 Choice Group 对象时,类型设置为 1(单选)。对于单选框,set Selected Index 只能用来指定某个选项被选中,因此,布尔值 selected 的值必然为 true,否则便没有意义。 游戏共有 3 个难度级别,分别是:拜师学艺、棋行天下、谁与争锋(此游戏中并未作出区分),初始情况下为拜师学艺,该选项的索引值为 0。创建难度选择单选框的代码如下: level = 1;//默认情况下的难度级别 choicelevel = new Choice Group(“电脑智能级别:”, 1);//创建难度级别选项组 choicelevel.append(“拜师学艺”, null);//难度 1 choicelevel.append(“棋行天下”, null);//难度 2 choicelevel.append(“谁与争锋”, null);//难度 3 choicelevel.set Selected Index(level-1 , true);//设置默认情况为难度 1,索引值为0 form.append(choicelevel);//将选项组添加到主表单中 游戏设置选项表单还有两个 Command 对象,分别用于玩家却热和取消,所以表单需要监听软键事件和组件事件: public class Setting implements Command Listener, Item State Listener 3、棋手选择 选择先手和难度等级用 Choice Group 组件来实现。Choice Group 组件用来构造选择框,其构造函数如下: Choice Group(String label, int choice Type)选择先手的选项框为选择组件,属性为复选框,标签名为空。创建好选择组件后,逐条添加选项元素。添加选项的方法如下: int append(String string Part, Image image Part)该方法追加一个选项元素到选择组中,追加的选项为选择组中的最后一个元素,选择组的大小加 1。 对于多选类型的 Choice Group,还可以设置个别选项的选择状态。设置初始选择状态的方法如下: void set Selected Index(int element Num, Boolean selected)这里创建一个只有一个选项元素的多选框用于玩家设置是否计算机先行,在默认情况下为true,创建完成多选框后将其添加到主表单中,代码如下: Computer First = true;//在默认情况下为计算机先行 choice First = new Choice Group(null, 2);//创建复选框 choice First.append(“电脑先手”, null);//添加选项元素 choice First.set Selected Index(0, Computer First);//设置多选框的默认状态 form.append(choice First);//将多选框添加到主表单中 4.3.3 棋子类的实现 1、棋子的行列位置 此五子棋游戏是一个二维棋类游戏,所以定了了一个 Dot 类来表示棋子。由于移动设备的局限性,所以程序不在下每一步棋时生成一个对象,而是在游戏进行时,玩家或者计算机没下一步棋,在数组相应位置生成该棋子的对象,而将已经下过的棋子保存到数组中随时检索,这样可以避免过多棋子对象占用系统内存。Dot 类的 UML 图如图 4-5 所示: 图4-5棋子行列设计 Dot 类主要有两个变量 row 和 col,分别表示行和列: public int row;//行 public int col;//列 2、检查越位 棋子的位置并非是任意的,玩家和计算机每走一步棋之前都要线检查该位置的合法性,即棋子是否在棋盘上,否则判为无效落子。检查是否越界的代码如下: public boolean is In Board(int board Size)//判断棋子是否越界(超出棋盘){ return row >= 0 && row < board Size && col >= 0 && col < board Size;} 3、修改棋子位置 在创建好 Dot 对象后,Dot 类提供了两种方法更改棋子位置,包括设置行列位置和从已有棋子中复制参数。 public void set Row Col(int r, int c)//设置棋子位置 { row = r;col = c; } public void copy From(Dot d)//复制已有的棋子 { row = d.row; col = d.col; } 4.3.4 对战逻辑类的实现 1、建立数据结构 本程序以数组保存当前盘面的情况,每个位置可能有三种状态:空、玩家的落子、计算机的落子,分别用 0、1、2 来表示。代码如下: public static int PLAYER_NONE = 0;//该位置为空 public static int PLAYER_COMPUTER = 1;//该位置有电脑的落子 public static int PLAYER_HUMAN = 2;//该位置有玩家的落子 棋盘在初始情况下为空,即棋子上没有任何棋子,在Gobang Logic类的构造函数中对棋盘进行初始化: table = new int[board Size][board Size];//创建棋盘数组 for(int r = 0;r < board Size;r++){ for(int c = 0;c < board Size;c++) table[r][c] = 0;//初始化盘面为空 } 除了记录棋盘上每个位置的落子状态外,程序还将对每种状态的位置个数进行统计,以对算法进行简化。对三种状态的统计存储在整型数组中,该数组为全局变量。 private int player Counter[]; 在 Gobang Logic 类的构造函数中对三种状态的计数进行初始化,即棋盘上都是空、计算机的落子或玩家的落子状态的个数为 0,在数据结构上,把空也当做某一特殊玩家。 初始化代码如下: player Counter = new int[3];//落子状态计数器 player Counter[0] = board Size * board Size;//整个棋盘都是空的状态 player Counter[1] = 0;//电脑落子0 player Counter[2] = 0;//玩家落子0 2、落子和悔棋 这里使用了一个 Dot 类棋子对象来记录最后一步棋的位置,当玩家下了一步棋后需要将上一步重新绘制,以消除旗子上的引导框。另外,还是用了堆栈来存储最近的几步落子,以便玩家悔棋。 private Dot last Dot;//棋子对象,存储最后一步落子 private Stack steps;//棋子对象的堆栈 最后一步棋子和棋子堆栈在 Gobang Logic 类的构造函数中进行初始化; last Dot = new Dot(board Size);//创建棋子对象用来存储最后一步棋,初始化 位置为棋盘中央steps = new Stack();//堆栈对象,用来存储最近的几部棋在棋盘上落子的代码如下: private void go At(int row, int col, int player)//电脑或人在 row、col 位置上走 { int last Row = last Dot.row;//记录上一步的行坐标 int last Col = last Dot.col;//记录上一步的列坐标 table[row][col] = player;//当前位置填充玩家代码 last Dot.set Row Col(row, col);//将这一部设置为“最后一步” game Canvas.repaint At(last Row, last Col);//重新绘制上一步(将引导框去掉) game Canvas.repaint At(row, col);//绘制当前这步 switch(player)//统计双方落子数量 { case 1: player Counter[1]++;//电脑的步数 break; case 2: player Counter[2]++;//玩家的步数 break; } player Counter[0]--;//空白的个数 if(steps.size()> 10)//堆栈数量超过上限(10) steps.remove Element At(0);//清除栈底 steps.push(new Dot(row, col));//将当前这步棋子压入堆栈 } Stack(堆栈类)从 Vector 集成而来,它使用 push()方法进入堆栈,需要时使用 pop()方法从堆栈的顶部将其取出。悔棋动作由玩家做出,从数据结构来看,是同时后退两步(将最后两步棋位置的落子状态设置为空)。 Stack 类的 peek()方法将获取栈顶对象,但不移。悔棋代码如下: : public boolean undo()//悔棋 { if(steps.size()>= 3) { Dot d = new Dot();//创建棋子对象 d.copy From((Dot)steps.pop());//从堆栈弹出的棋子中复制行列位置坐标 table[d.row][d.col] = 0;//将该位置设置为空 game Canvas.repaint At(d.row, d.col);//在棋盘上重新绘制该位置 d.copy From((Dot)steps.pop());//从堆栈弹出的棋子中复制行列位置坐标 table[d.row][d.col] = 0;//将该位置设置为空 game Canvas.repaint At(d.row, d.col);//在棋盘上重新绘制该位置 d.copy From((Dot)steps.peek());//获取栈顶对象,作为最后一步棋存储 last Dot.copy From(d); game Canvas.repaint At(d.row, d.col);//重新绘制最后一步(添加引导框)return true;//悔棋成功 } else { return false; //悔棋失败 } } 4.4 本章小结 本章主要内容是游戏的实现,包括主类的实现,如构造函数、事件处理等,游戏帮助和介绍表单类的实现,游戏设置类的实现,如棋盘、选手、难度等,旗子类的实现,如棋子行列位置、检查越界等,对战逻辑类的实现,如落子和悔棋、逻辑运算等的实现。第二篇:区域游戏五子棋
第三篇:五子棋游戏软件工程课程设计
第四篇:MFC课程设计报告-一个简单的五子棋游戏(本站推荐)
第五篇:五子棋游戏总体设计与实现