第一篇:五子棋游戏总体设计与实现
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 本章小结
本章主要内容是游戏的实现,包括主类的实现,如构造函数、事件处理等,游戏帮助和介绍表单类的实现,游戏设置类的实现,如棋盘、选手、难度等,旗子类的实现,如棋子行列位置、检查越界等,对战逻辑类的实现,如落子和悔棋、逻辑运算等的实现。
第二篇:QT基于linux的五子棋游戏设计与实现
课题名称:基于linux的五子棋游戏设计与实现
专业:计算机科学与技术(计算机工程方向)
开发工具及语言:,ubuntu12.04,QT
运行环境:linux下的QT
论文字数:1w左右
是否需要PPT:是
是否需要安装说明:是
所在城市:武汉市
所在学校:华中农业大学楚天学院
功能需求分析
系统的基本功能需求分析如下:
(1)游戏进入界面的菜单选择,有自我对战、人机对战、网络对战和退出 游戏四个选项;
(2)进入游戏之后,显示一个十三行十三列的五子棋的棋盘。棋盘旁边显 示一个菜单,菜单选项有棋局重现、继续上步、上级菜单和退出游戏,在界面上可以在棋盘落子操作和菜单操作之间进行切换,用键盘的按键来控制,棋局重现功能是在某方胜利之后才能手动操作一步步查看并回顾双方下棋的过程;继续上步可以切换回棋盘操作;上级菜单功能可以使五子棋游戏退出当前的游戏模块(自我对战、人机对战、网络对战其中的一种),回到游戏开始界面时候的菜单,进行重新选择;退出游戏是退出整个游戏界面;
(3)棋盘上显示光标,可以对光标进行移动操作,也可以在棋盘和菜单来 回切换的时候重绘和擦除;
(4)在上面棋盘将光标移动到上面对应的位置,可以落子,棋盘上将在光 标显示处出现相应的棋子,并且棋子在横纵交点处;
(5)自我对战的过程中有悔棋的功能;
(6)游戏的过程中会有提示信息,如该哪一方落子,棋盘旁边显示相应按 键对应的操作列表;
(7)可以自动判断胜负,胜利一方形成一列的五个或5个以上的棋子闪 烁数次,显示是黑方或者白方已经胜利的字样,并且停止落子的功能;
(8)能够实现三种游戏模式,自我对战、人机对战和网络对战。
非功能需求分析
非功能需求如下:
(1)在程序运行的过程中程序不能崩溃,更不能使系统出现问题,造成 灾难性的后果;
(2)希望在此项目的基础上不做改动或做很少的改动就能在其他的系统 或设备上运行;
(3)界面清晰容易看懂,方便玩家操作;
(4)游戏运行速度不能太慢,要反应及时,以免影响玩家的兴趣。
(5)程序代码必须每行都有详细注释。以上是要登记的内容。这个是例子。自己修改相关信息。一定要写的详细,开发以文档为依据。注意请把文件名换成自己的作品名,以防技术开发错误
注意事项:
第三篇:区域游戏五子棋
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)小结
表扬与批评,出示活动中拍摄的照片进行点评,提出新要求。
第四篇:Java五子棋实现报告
一、实验目的
(1)使用Java编写五子棋程序
(2)掌握编写过程的一些类和类成员的使用,并且了解五子棋制作过程的一些步骤和了解一些算法。
二、实验环境
在电子楼2楼,装有My Eclipse 的计算机上进行
三、实验内容
编写一个五子棋程序。程序主要实现以下功能:
1.实现五子棋界面,要求人性化界面简洁美观; 2.实现黑白色轮流下棋功能,能提示下棋方; 3.实现连成五子自动判断功能; 4.实现时间设置功能,认输功能;
核心代码如下:
1.我的第一步是设计界面。在这个过程的要使用到以下的步骤:
1.使用MyEclipse 创建一个Project关于这个工程,加入两个类,分别是ChessFrame和Chess,而ChessFrame是这个工程中最重要的一个部分。创建过程中要继承JFrame类,并且要继承Runnable 和 MouseListener 这两个接口,分别是用来监听鼠标的移动和时间的变化。2.在给这个JFrame设置大小和颜色等一些东西。这里最主要的是使用了两个函数,是以前没见过的:
1.这个是用来设置默认的窗口关闭事件的
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);2.这两个是用来获得屏幕的大小的
Toolkit.getDefaultToolkit().getScreenSize().height;Toolkit.getDefaultToolkit().getScreenSize().width;
3.把本地的背景图片加到这个窗口中,作为这个窗口的背景图:
使用的到的类有BufferedImage和 ImageIO这两个类,这两个类是专门用来处理这种功能的。主要的代码如下:
BufferedImage bg = null;bg = ImageIO.read(new File(“e:/background.jpg”));g.drawImage(bg,0,0,this);这样这个图片就加到了这个窗口的背景去了。
这里有一个改进就是双缓冲技术,可以防止闪屏。这个技术就是在界面和内存都有一幅图,我们的改动不是直接画界面,而是内存中先画好然后把内存中直接显示出来,那样就没有了一前一后的,那就没有了闪屏的事情发生了。
4.就是画棋盘和写一些游戏信息:
这步比较简单,也没什么可以说的,用到的一些画线的函数,和写String的一些函数。
以上做完以后就可以出现以下的界面:
1.我的第二步就是增加对mouse的点击和移动的处理,这样以后就可以用来下棋。在这个过程的要使用到以下的步骤: 1.增加对mouse的监视,然后重写它的一些函数:
1.我们在ChessFrame的构造函数中加入了addMouseListener()函数,然后重写关于这个的四个函数,我们这这里不重写所有的函数,就改写一个MousePress函数就可以了。改写的代码如下:
public void mousePress(MouseEvent arg0){
this.x = arg0.getX();this.y = arg0.getY();if(this.canplay)
} this.repaint();现在要处理的就是加上棋子了,我在这个做了一下小改动可以更加准确的定位下棋的位置:
if(x >= 10 && x <= 374 && y >= 72 && y <= 450){
int sx1 =(this.x72)/ 20;int yx1 =(this.x72)% 20;if(yx1 >= 10){ } if(yy2 >= 10){ } sy2++;sx1++;就是这个,我们通过监控鼠标的就可以得到点击的X,Y坐标,我在这里通过对它求余,假如余数大于10(就是一个格子的一半)那就给+1,不然不变。后面的画棋子是很简单的一个过程,使用的是现成的函数(drawoval)
2.这部要做的就是记录棋子和五子连的判断:
1.我们通过一个数组int给保存棋子,如果是0就是没子,1表示是黑子,2表示白子。在每次重绘的时候遍历这个数组显示,这样就可以保存棋子了。2.判断五子连起来然后获胜的算法: 这个算法是鉴戒例子上的:
private boolean isline(int x, int y, int xchange, int ychange, int color){
int tempx = xchange;int tempy = ychange;int count = 1;while(x + xchange >= 0 && y + ychange >= 0
&& color == chess1[x + xchange][y + ychange]){ count++;if(xchange!= 0){ } if(ychange!= 0){ if(ychange < 0){ xchange++;
}
}
}
} ychange--;ychange++;} else { xchange = tempx;ychange = tempy;while(xychange >= 0
} if(count >= 5){
} return true;return false;} else { && color == chess1[xychange]){ count++;if(xchange!= 0){ } if(ychange!= 0){
} if(ychange < 0){
} ychange--;ychange++;} else { xchange++;中心思想就是要判断就要判断8个方向,其中有的只是相反的方向,我们使用关于X,Y的相对的变化来判断,并且使用count来计数,如果到了5个就可以判断胜利啦。
1.我的第三步就是时间的变化和一些键的设置
1.关于时间的变化主要是在于线程的使用,这里我们这个JFrame它继承了Runnable 这个接口,不过我们要重写Run函数,这个run函数的代码如下: public void run(){
if(this.second > 0){
while(true){
this.repaint();if(this.isblack){
this.ss1--;
if(this.ss1 == 0){
JOptionPane
.showMessageDialog(this, “黑方超时~~~~¡¤游戏结束”);
this.message1=“0:0:0”;
{
“白方超时~~~~¡¤¡¤游戏结束”);this.message2=“0:0:0”;this.canplay = false;
{
{ }
this.ss2--;
if(this.ss2 == 0){
this.message1 = this.ss
1/ 3600 + “ : ”
+(this.ss1 / 60this.ss1 / 60 *
this.ss1=-1;
this.canplay = false;
}else if(this.ss1>0)3600 * 60)60this.ss2 / 3600 + “ : ”
+(this.ss2this.ss2 / 3600 * 60 * 60);
this.repaint();}else { }
try {
}
Thread.sleep(1000);e.printStackTrace();} catch(InterruptedException e){ 这个函数是用来事时间的变化,所以每操作以后就让线程sleep(1000)就可以了,那样就是一秒钟。这样就可以倒计时了。2.现在我们要点击一个按钮要它有响应。
这里我们其实就没用到什么button,那为什么会有反应呢,因为我们通过鼠标的点击范围来确定要响应什么函数,这就是这里面的秘密.在public void mouseClicked(MouseEvent arg0)函数里有下面这些if的判断
if(x1 >= 404 && x1 <= 473 && y1 >= 74 && y1 <= 103)if(x1 >= 404 && x1 <= 473 && y1 >= 127 && y1 <= 155)if(x1 >= 404 && x1 <= 473 && y1 >= 179 && y1 <= 208)if(x1 >= 404 && x1 <= 473 && y1 >= 286 && y1 <= 316)if(x1 >= 404 && x1 <= 473 && y1 >= 338 && y1 <= 367)if(x1 >= 404 && x1 <= 473 && y1 >= 390 && y1 <= 419)这就是为了确定鼠标的范围,然后相对调用函数。
其他还有就是一些Debug处理,在程序已经处理了,结果的还是蛮可以处理的,不过只能是人人对战。
四、实验心得与小结
这次试验总的来说没有想像中那么难,还有视屏的帮助,感觉起还是很容易动手的,不过由于自己没上心,没有做比较大的改动,最主要的人机的对战没做出来是满遗憾的,不过通过这个试验,让我学习了不少的知识,比如双缓冲,mouselistener 等许多许多的知识,还有关于五子棋算法的设计也是一部分。不管怎么说还是有学到知识的,没什么改动,但对现有的知识的掌握还是很可以的。
五、指导教师评议
成绩评定:
指导教师签名:
第五篇:五子棋游戏软件工程课程设计
软件工程设计
专 业:班 级:姓 名:学 号:指导老师:
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++)
//打印棋盘
{