最新井字棋课程设计报告.docx

上传人:b****5 文档编号:6945787 上传时间:2023-01-13 格式:DOCX 页数:13 大小:33.69KB
下载 相关 举报
最新井字棋课程设计报告.docx_第1页
第1页 / 共13页
最新井字棋课程设计报告.docx_第2页
第2页 / 共13页
最新井字棋课程设计报告.docx_第3页
第3页 / 共13页
最新井字棋课程设计报告.docx_第4页
第4页 / 共13页
最新井字棋课程设计报告.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

最新井字棋课程设计报告.docx

《最新井字棋课程设计报告.docx》由会员分享,可在线阅读,更多相关《最新井字棋课程设计报告.docx(13页珍藏版)》请在冰豆网上搜索。

最新井字棋课程设计报告.docx

最新井字棋课程设计报告

 

井字棋课程设计报告

软件工程

课程设计报告

题目:

井字棋游戏

班级:

2013软件工程

学号:

20131032131753001

姓名:

黄加俊

二○一四年十二月一日

课程设计题目说明书

课程设计题目:

井字棋游戏

设计要求:

“井字棋”游戏(又叫“三子棋”),或是一字棋,是一款十分经典的益智小游戏,想必很多玩家都有玩过。

“井字棋”的棋盘很简单,是一个3×3的格子,很像中国文字中的“井”字,所以得名“井字棋”。

“井字棋”游戏的规则与“五子棋”十分类似,“五子棋”的规则是一方首先五子连成一线就胜利;“井字棋”是一方首先三子连成一线就胜利。

要求:

屏幕输出棋盘和棋子(可用特殊符号代替),

实现:

用户与电脑下棋

难点:

判断输赢的算法及简单的人工智能实现

工作量:

(根据项目实际情况选择,在所作的工作后打√)

具体工作量分为几个部分:

1.可行性研究分析和可行性研究报告的撰写工作。

2.软件需求的调查和软件需求说明书的撰写;√

3.软件的概要设计和概要设计说明书的撰写;√

4.软件的详细设计和详细设计说明书的撰写;√

5.软件的实现工作,包括代码的实现和实现过程中的具体要求工作;√

6.测试的准备工作和测试计划报告的撰写;√

7.整个软件试运行、软件测试、测试报告的撰写和用户手册的撰写工作;

8.项目文档和代码的规范化整合;√

10.整个项目的总结和课程设计总结报告的撰写。

工作计划安排:

11月26日:

确定研究课题,进行可行性研究。

11月26日:

做好内容安排。

11月26日——11月28日:

完成概要设计、完成详细设计。

11月27日——11月28日:

完成代码的编写。

11月28日:

进行测试和维护。

11月28日:

对整个设计进行补充和检查。

 

第一章可行性研究

1.1引言

1.1.1可行性研究目的

在课程设计项目中,井字棋游戏设计作为初学者的我们来说,是个比较适合和有研究意义的题目。

“井字棋”游戏(又叫“三子棋”),或是一字棋,是一款十分经典的益智小游戏,想必很多玩家都有玩过。

“井字棋”的棋盘很简单,是一个3×3的格子,很像中国文字中的“井”字,所以得名“井字棋”。

“井字棋”游戏的规则与“五子棋”十分类似,“五子棋”的规则是一方首先五子连成一线就胜利;“井字棋”是一方首先三子连成一线就胜利。

虽然这只是个很简单的小游戏,但作为初学者的我们认识项目设计的技巧与结构及其概念的理解,封装性、继承派生、多肽的理解及实现,是比较好的课题。

对我们以后的大型程序的设计奠定了基础。

所以作为我们这次的课程设计项目来说,我们认为是个很好的、有可研究性的设计项目。

1.1.2背景(说明井字棋设计背景,开发目的等)

对于21世纪的人们来说,游戏日益成为我们生活中必不可少的休闲娱乐工具。

为了满足人们的需要,现在越来越多的人们把游戏作为一种商品对待,就比如中国,像盛大、网易、滕讯等大型的游戏开发公司更把游戏的研究看作是一棵摇钱树,所以游戏程序设计人员在未来是不可多得的人才。

对于学软件工程的我们来说,一个优秀的程序员也许是我们学习的优秀目标,所以在出始阶段我们就注重项目设计的理念,而且喜欢游戏的我们更希望自己在将来能够做出一个自己很满意且适合市场的游戏来,所以我们这次以这个为题目就是想熟悉游戏编程的最基础的设计思想和实现手段的了解,为我们以后打下基础。

虽然井字棋是个很简单的小游戏,基本上人们都不玩了,但是作为一种我们的设计项目,我们都觉得是个很好的且适合的项目。

1.2可行性研究的前提

1.2.1要求(说明井字棋的预期要求)

功能:

屏幕输出棋盘和棋子(可用特殊符号代替);

实现:

用户与电脑下棋(可选)功能和修改。

难点:

判断输赢的算法及简单的人工智能实现。

1.2.2目标

首先:

能做出棋盘的基本样式。

最后:

能实现玩家与电脑的对弈,最好能做到电脑的智能化。

1.2.3评价尺度

第一:

实现电脑的智能化;

第二:

做到界面美观易懂;

第三:

达到娱乐的最低水平。

第二章需求分析

2.1任务概述

该软件的设计主要是实现简单的三字棋,能做到玩家与玩家之间的对弈或者玩家与电脑之间的对弈,可考虑怎样实现电脑的智能化。

其次,从程序的设计过程中理解实现程序的方法和理念,学会怎么样做到面向对象设计,理解面向对象的概念及结构的封装性和实用性,能为以后的设计奠定一些良好的基础。

2.2对性能的规定

此节说明软件的性能要求:

精度:

本程序中按照系统给出的提示,输入数字,实现程序的功能。

应该注意,输入的一定只能是数字,若输入字母或其他,则出错。

时间特性:

由于本程序并不是很庞大,故响应时间短,显示结果迅速。

故障处理要求:

只有在非法输入是,出现死循环,此时应该退出程序,重新输入。

运行环境规定运行的软件环境:

windows7、windowsXP、

运行该软件所需要的硬设备:

PC机一台。

第三章概要设计

3.1总体设计

3.1.1基本设计概念和处理流程

人机对弈的难点在于当人走一步棋之后,计算机如何走下一步,即计算机如何找出最合适的位置去走棋。

这就需要一定的算法,或者叫做计算机的AI。

对于井字棋、五子棋等两方较量的游戏来说,Minimax算法(极小极大算法)是最基本也是最常用的。

算法的原理不在这里解释了,我们直接看该算法在井字棋中的应用。

井字棋中,假设使用“X”的是人,使用“O”的是计算机。

“X”方先走,设定X方的最大利益为正无穷(程序使用常量+INFINITY表示),O方的最大利益为负无穷(程序中使用-INFINITY表示),即X方和O方走的每步棋都要力图使自己的利益最大化,而使对方的利益最小化。

这样我们称X方为MAX(因为他总是追求更大的值),O方为MIN(它总是追求更小的值),各自都为争取自己的最大获益而努力。

现在举例说明,比如图4所示的棋局树:

图1棋局形成的树

X方先走,有三种选择,如图4中第二层所示。

假设X方选择最左边的走法,那么O方接下来将有5种走法,O方会选择最小化的走法,即值为-1的走法,因为它的最大利益是负无穷;同理,X方的另外两种走法会分别得到O方的最小值1和-2。

这样,对于X方来说,三种走法会导致O方最小化值分别为-1、1、-2,X方的最佳策略则是选择其中最大的,即第二层中间的走法,因为它的最大利益是正无穷,这就是极小极大算法的体现——X方的选择总是极大化,O方的选择总是极小化。

对于其中那些值的是如何计算的,我们举例说明,比如对于第三层最左边的棋局,在这种状态下,如果把棋局空白处都填上X,则X共有6中3连子情况,即获胜情况;如果把空白处都填上O,则O共有5种3连子情况,所以结果是二者相减等于1。

在具体走起过程中,MAX面对MIN最大获利中的最小值时,会选择其中最大的,比如图4第二层小括号内的值都是第三层中能使MIN最大获利的最小值,这时候MAX选择其中最大的,这对MAX最为有利,所以MAX方选择图4第二层中间的走法最好。

同样道理,MIN也会一样,选择对自己最有利的,即MAX有可能获得的最大值。

这时候,MIN在走棋时会考虑MAX方占据哪个位置对MAX最有利,然后MIN把这个位置先占了。

有点难理解,其实就是抢先把对对手有利的位置抢占了。

简单说,X方或者MAX方的走棋时由人来控制的,我们不仔细说了。

对于O方或者MIN方,它走棋时要考虑哪个位置对X方最有利,然后把该位置占据,即O的最佳走棋就是X的最佳走棋。

所以O在走棋之前,先站在X的角度寻找最佳走棋位置。

后文中minimax方法就是站在X角度来考虑极小极大算法,找到X的最佳走棋位置,然后由O方来占据该位置。

2、极小极大算法

整个算法包括如下几个部分:

首先要有一个评估方法gameState,对每走一步棋后的棋局进行评估,估值为WIN常量说明X方,即MAX方获胜;估值为LOSE则O方,即MIN方获胜;估值DRAW为平局;估值为INPROGRESS,说明棋未走完;估值为DOUBLE_LINK,说明棋局中有两连子情况

然后用一个minimax方法寻找在当前棋局状态下X方的最佳位置,X方的最佳位置就是当X走该位置后,O方所有走法中最小值里的最大值,比如图4中第二层X的位置选择。

当找到该位置后,由O方来抢先占据该位置。

最后用两个递归方法min和max来遍历所有的棋局。

min方法负责找出O方的最小值,比如图1第二层最左边的棋局会导致5中O方的走法,min方法就是找出这5种走法中的最小值。

同理,max方法负责找出X方的最大值,比如图1第二层三种棋局中的中间棋局。

3.1.2功能需求与程序的关系

1.计算机为一方,人为一方,交替下棋,谁先连成一条直线谁胜;允许人选择先下还是后下。

2.界面要求:

初始状态——显示棋盘,并显示玩家的操作键;游戏进行状态——动态显示棋盘不同玩家的棋子用不同符号显示,屏幕上显示当前玩家号,结束时显示赢家号。

3.提示计算机自动下棋的规则:

计算机下时,应考虑所有空位,并按行、列、对角线计算每个空位的分值,若在某行(列、对角线)上,(设计算机画X,人画O)

已有XX加50分

已有OO加25分

已有X空加10分

已有O空加8分

都是空加4分然后选分值最高的位置画X。

3.2系统出错处理设计

(1)违规输入字符,程序可能会出现死循环或者直接结束程序。

(2)规则里面所定义的若有错误输入,则会根据程序的提示重新输入。

3.3性能

1.程序耗费电脑内存和CPU开销很小。

2.玩家与电脑对战时AL的智能很高。

3.可以选择电脑难度,适合各种水平的玩家。

4.游戏界面比较美观,亲近,方便大众接受。

3.4程序设计:

//按钮的监听事件

privateclassJBClickimplementsActionListener{

//当单击按钮时

publicvoidactionPerformed(ActionEvente){

for(inti=0;i<9;i++){

if(e.getSource()==jb[i]){jb[i].setText("X");//被单击的按钮走“X”

jb[i].setEnabled(false);//置为不可用

}

}

intgamestate=gameState(jb);//获取棋盘状态

//如果棋局未结束,则计算机走下一步

if(!

(gamestate==WIN||gamestate==LOSE||gamestate==DRAW)){

intnextpos=getNextMove(jb);//获取下一步走棋位置

jb[nextpos].setText("O");//走棋“O”

jb[nextpos].setEnabled(false);

gamestate=gameState(jb);//获取最新的棋盘状态

}

//输出棋局胜负

switch(gamestate){

caseWIN:

JOptionPane.showMessageDialog(null,"X方获胜","提示",JOptionPane.DEFAULT_OPTION);

break;

caseLOSE:

JOptionPane.showMessageDialog(null,"O方获胜","提示",JOptionPane.DEFAULT_OPTION);

break;

caseDRAW:

JOptionPane.showMessageDialog(null,"平局","提示",JOptionPane.DEFAULT_OPTION);

break;

}

//如果结束,则提示

if(gamestate==WIN||gamestate==LOSE||gamestate==DRAW){

intover=JOptionPane

.showConfirmDialog(null,"是否再来一局?

","提示",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE);

if(over==JOptionPane.YES_OPTION){//再来一局for(inti=0;i<9;i++){

jb[i].setText("");

jb[i].setEnabled(true);

}

}else{

System.exit(0);//退出游戏

}

}

}

}

然后,获取棋局状态的方法加入寻找两连子的代码,如下:

//获取棋盘当前状态

publicintgameState(JButton[]jb){

intresult=INPROGRESS;

booleanisFull=true;

//判断棋盘是否已满

for(intpos=0;pos<9;pos++){

charchess=jb[pos].getText().charAt(0);

if(empty==chess){

isFull=false;

}

}

//寻找三连子情况

for(int[]status:

WIN_STATUS){//遍历8中棋局获胜状态

//得到某个获胜棋局状态的第一个索引的字符

charchess=jb[status[0]].getText().charAt(0);

//如果为空,说明此处未下棋子,跳出循环,找下一个状态

if(chess==empty){

continue;

}

inti;

for(i=1;i

if(jb[status[i]].getText().charAt(0)!

=chess){//不与第一个索引字符一致

break;//表明未三子连线,跳出

}

}

if(i==status.length){//三子连线

result=chess=='X'?

WIN:

LOSE;

break;

}

}

//寻找两连子情况

if(result!

=WIN&result!

=LOSE){

if(isFull){

result=DRAW;//不输不赢且棋盘满则为平

}else{

int[]finds=newint[2];//存放X或O的两连子情况

for(int[]status:

WIN_STATUS){

charchess=empty;

booleanhasEmpty=false;

intcount=0;//计数

for(inti=0;i

if(jb[status[i]].getText().charAt(0)==empty){

hasEmpty=true;//该处没有棋子

}else{

if(chess==empty){//有棋子

chess=jb[status[i]].getText().charAt(0);

}

if(jb[status[i]].getText().charAt(0)==chess){

count++;//且棋子相同则加1

}

}

}

if(hasEmpty&&count>1){

if(chess=='X'){

finds[0]++;

}else{

finds[1]++;

}

}

}

//两连子情况

if(finds[1]>0){//O的两连子

result=-DOUBLE_LINK;

}elseif(finds[0]>0){//X的两连子

result=DOUBLE_LINK;

}

}

}

returnresult;//记录了胜负平或者两连子情况

}

O方走棋时,要得到走棋位置,我们用一个方法来获取该位置,如下:

publicintgetNextMove(JButton[]board){

intnextPos=minimax(board,3);

returnnextPos;

}

上面方法中调用了极小极大算法minimax,如下:

//以'X'的角度来考虑的极小极大算法

publicintminimax(JButton[]board,intdepth){

int[]bestMoves=newint[9];//存放最佳走棋位置

intindex=0;

intbestValue=-INFINITY;

//搜索所有空位,试探填上X,然后选其中最小值的

for(intpos=0;pos<9;pos++){

if(board[pos].getText().charAt(0)==empty){

board[pos].setText("X");

intvalue=min(board,depth);//得到最小值

if(value>bestValue){//选择最小值里最大的

bestValue=value;

index=0;

bestMoves[index]=pos;

}elseif(value==bestValue){

index++;

bestMoves[index]=pos;

}

board[pos].setText("");

}

}

returnbestMoves[index];

}

最后,两个递归方法min和max如下:

//对于'O',估值越小对其越有利

publicintmin(JButton[]board,intdepth){

intevalValue=gameState(board);

booleanisGameOver=(evalValue==WIN||evalValue==LOSE||evalValue==DRAW);

if(depth==0||isGameOver){

returnevalValue;

}

intbestValue=INFINITY;

for(intpos=0;pos<9;pos++){

if(board[pos].getText().charAt(0)==empty){

board[pos].setText("O");

//选择最小值

bestValue=Math.min(bestValue,max(board,depth-1));

board[pos].setText("");

}

}

returnevalValue;

}

//对于'X',估值越大对其越有利

publicintmax(JButton[]board,intdepth){

intevalValue=gameState(board);

booleanisGameOver=(evalValue==WIN||evalValue==LOSE||evalValue==DRAW);

if(depth==0||isGameOver){

returnevalValue;

}

intbestValue=-INFINITY;

for(intpos=0;pos<9;pos++){

if(board[pos].getText().charAt(0)==empty){

board[pos].setText("X");

//选择最大值

bestValue=Math.max(bestValue,min(board,depth-1))board[pos].setText("");

}

}

returnevalValue;

}

 

第五章测试分析

本程序的功能非常明显:

#字棋。

本程序提供1种对战模式:

玩家VS电脑。

玩家和电脑对战时选择难度和谁先手,玩家很容易赢简单的电脑,但是赢中等的电脑很困难,至于和困难的电脑对战几乎赢不了。

程序目前之发现一处BUG,那就是当玩家输入非数字字符时程序会结束或者陷入死循环。

通过测试,发现以下一些不足的地方:

1.电脑不够完全智能,只能按照指定的步骤来进行选择。

2.如果玩家不小心输入错误,那么程序直接结束或者陷入死循环。

第六章用户手册

使用软件的方法及注意事项

1、本程序在输入的时候只能输入0~9数字,请不要输入其他字符,不然会造成死循环或者程序直接结束。

2、本程序在输入后请回车以确定。

第七章总结

在本程序中的井字棋程序使用了极大极小值算法,这种算法的思想是“考虑双方对弈若干步之后,从可能的走法中选一步相对较好的走法来走”,并且“在有限的搜索深度范围内进行求解”。

最大最小值算法的核心是将搜索树的层分为MAX层和MIN层,MAX层和MIN层交替相邻(即,一个节点如果在MAX层,则其子女节点在MIN层;如果在MIN层,则其子女节点中的最大者,在MIN层的节点的评估函数值取其子女节点中的最小者。

 此外,需要定义一个评估函数来计算叶节点的评估函数值,要注意将某方获胜的状态节点的评估函数值设为计算机能表示的最大数(无穷大)或最小数(无穷小)以表明在该状态下有一方获胜。

 最后,还要“在有限的搜索深度范围内进行求解”,如果搜索深度太大,则在状态数较多的情况下会使时间耗费或空间耗费达到无法忍受的程度。

本设计中的程序的博弈算法采用的是极大极小值算法,如果采用α-β剪枝算法,则可以在一定程度上减少博弈树的节点数。

假设一棵树的深度为d,且每个非叶节点的分支系数为b,则在最佳情况下,α-β剪枝算法生成深度为d的叶节点数大约相当于极大极小值算法所生成的深度为d/2的博弈树的节点数。

也就是说,为了得到最佳的一步,α-β剪枝算法只需要检测O(b^d/2 )个节点,而不是极大极小值算法的O(b^d )。

从另一个角度看,在相同的代价下,α-β剪枝算法向前看走的步数是极大极小值算法向前看走的。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > IT计算机 > 互联网

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1