第一篇: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 等许多许多的知识,还有关于五子棋算法的设计也是一部分。不管怎么说还是有学到知识的,没什么改动,但对现有的知识的掌握还是很可以的。
五、指导教师评议
成绩评定:
指导教师签名:
第二篇:五子棋JAVA语言课程设计报告
《Java语言程序设计》
课程设计报告
学 院: 信息科学技术学院 班 级: 软件技术2班 姓 名: 王更新 学 号: 1108900505 指导教师: 郭韶升 课设时间: 2014-03-17 至2014-03-26
二O一四 年 三月 二十六 日
目 录
一、设计要求…………………………………………....2
二、设计步骤…………………………………………....2 2.1程序流程图………………………….…………...2 2.2程序的功能分配……………………….………...3
三、设计正文…………………………………………....6 3.1创建棋盘类……………………………………….6 3.2判断输赢功能实现……………………………….9 3.3测试结果……………………………………….....9
四、心得体会…………………………………………...12
五、参考文献…………………………………………...12 附录(源代码)……………………………………….13
一、课程设计要求
设计一个15╳15围棋棋盘,由两玩家交替进行对战,并可以实现以下功能: 1.选择落子的先后顺序 2.重置棋盘 3.刷新重新开始 4.退出提示
并且规定退出者判为负,但退出过程中要有提示。以防不小心点错了。最后判断某一方是否为五子连珠。
实现一个简单的多用户五子棋的游戏程序,包括如下两个界面(1)选择对弈桌(执黑、执白)。
(2)在游戏界面,有开始,退出(游戏未结束、点退出自动判负);
二、设计步骤
2.1程序流程图
2.2 程序的功能分配
a.棋盘的绘制
public void draw_qipan(Graphics G)//画棋盘 15*15{
G.setColor(Color.lightGray);
G.fill3DRect(10,10,300,300,true);
G.setColor(Color.black);
for(int i=1;i<16;i++){
G.drawLine(20,20*i,300,20*i);
G.drawLine(20*i,20,20*i,300);
} } b.添加按钮
Button b1=new Button(“开始”);Button b2=new Button(“重置游戏”);Label lblWin=new Label(“ ”);Checkbox ckbHB[]=new Checkbox[3];Button exist = new Button(“退出”);public void init(){
ckbHB[0]=new Checkbox(“执白”,ckgHB,false);
ckbHB[1]=new Checkbox(“执黑”,ckgHB,false);
ckbHB[2]=new Checkbox(“观看”,ckgHB, false);}
c.鼠标棋子的触发事件
public void mouseClicked(MouseEvent e){
Graphics g=getGraphics();
int x1,y1;
x1=e.getX();
y1=e.getY();
if(e.getX()<20 || e.getX()>300 || e.getY()<20 || e.getY()>300){
return;
}
if(x1%20>10){
x1+=10;
}
if(y1%20>10){ y1+=10;
}
x1=x1/20*20;
y1=y1/20*20;
set_Qizi(x1,y1);
m*=(-1);}
d.按钮的触发事件
public void actionPerformed(ActionEvent e){
Graphics g=getGraphics();
if(e.getSource()==b1){
Game_start();
}
else{
Game_re();
}
if(e.getSource()==exist){
Game_re();
lblWin.setText(Get_qizi_color(color_Qizi)+“输了!”);
intGame_Start=0;
}
e.判断落子的位置及画出相应的黑白棋子 public void set_Qizi(int x,int y)//落子{
if(intGame_Start==0)//判断游戏未开始{
return;
}
if(intGame_Body[x/20][y/20]!=0){
return;
}
Graphics g=getGraphics();
if(color_Qizi==1)//判断黑子还是白子{
g.setColor(Color.black);
color_Qizi=0;
}
else{
g.setColor(Color.white);
color_Qizi=1;
}
g.fillOval(x-10,y-10,20,20);
intGame_Body[x/20][y/20]=color_Qizi+1;}
f.判断胜负
if(Game_win_1(x/20,y/20))//判断输赢1{
lblWin.setText(Get_qizi_color(color_Qizi)+“赢了!”);
intGame_Start=0;
}
if(Game_win_2(x/20,y/20))//判断输赢2{
lblWin.setText(Get_qizi_color(color_Qizi)+“赢了!”);
intGame_Start=0;} if(Game_win_3(x/20,y/20))//判断输赢3{ lblWin.setText(Get_qizi_color(color_Qizi)+“赢了!”);intGame_Start=0;} if(Game_win_4(x/20,y/20))//判断输赢4{ lblWin.setText(Get_qizi_color(color_Qizi)+“赢了!”);
intGame_Start=0;} }
三、设计正文
3.1创建棋盘类
Public class WcyChess extends Applet ActionListener,MouseListener,MouseMotionListener,ItemListener{ int color_Qizi=0;//旗子的颜色标识 0:白子 1:黑子
int intGame_Start=0;//游戏开始标志 0未开始 1游戏中
int intGame_Body[][]=new int[16][16];//设置棋盘棋子状态
int m=-1;Button b1=new Button(“开始”);Button b2=new Button(“重置游戏”);Label lblWin=new Label(“ ”);Checkbox ckbHB[]=new Checkbox[3];Button exist = new Button(“退出”);CheckboxGroup ckgHB=new CheckboxGroup();NetchatClient chat=new NetchatClient();public void init(){
setLayout(null);
addMouseListener(this);
add(b1);
b1.setBounds(330,50,80,30);
b1.addActionListener(this);
add(b2);
b2.setBounds(330,90,80,30);
b2.addActionListener(this);
ckbHB[0]=new Checkbox(“执白”,ckgHB,false);
ckbHB[0].setBounds(320,20,60,30);
ckbHB[1]=new Checkbox(“执黑”,ckgHB,false);
ckbHB[1].setBounds(380,20,60,30);
ckbHB[2]=new Checkbox(“观看”,ckgHB, false);
add(ckbHB[0]);
add(ckbHB[1]);
add(ckbHB[2]);
ckbHB[0].addItemListener(this);
ckbHB[1].addItemListener(this);
add(lblWin);
lblWin.setBounds(330,180,80,30);
lblWin.setBackground(Color.red);
lblWin.setText(“胜利者!”);//没有显示?
ckbHB[2].setBounds(440, 20,60, 30);
add(exist);
exist.setBounds(330,130,80,30);
implements
//
exist.addActionListener(this);add(chat);chat.setBounds(20, 500, 300, 300);chat.frame();chat.setVisible(true);Game_start_csh();setSize(500,600);setVisible(true);} public void itemStateChanged(ItemEvent e){ if(ckbHB[0].getState())//选择黑子还是白子{
color_Qizi=0;} else{
color_Qizi=1;} } public void mousePressed(MouseEvent e){} public void mouseClicked(MouseEvent e){ Graphics g=getGraphics();int x1,y1;x1=e.getX();y1=e.getY();if(e.getX()<20 || e.getX()>300 || e.getY()<20 || e.getY()>300){
return;} if(x1%20>10){
x1+=10;} if(y1%20>10){
y1+=10;} x1=x1/20*20;y1=y1/20*20;set_Qizi(x1,y1);m*=(-1);} public void actionPerformed(ActionEvent e){ Graphics g=getGraphics();if(e.getSource()==b1){
Game_start();} else {
Game_re();}
} if(e.getSource()==exist){
Game_re();
lblWin.setText(Get_qizi_color(color_Qizi)+“输了!”);
intGame_Start=0;} } public void mouseEntered(MouseEvent e){} public void mouseExited(MouseEvent e){} public void mouseReleased(MouseEvent e){} public void mouseDragged(MouseEvent e){} public void mouseMoved(MouseEvent e){} public void paint(Graphics g){ draw_qipan(g);
3.2判断输赢功能实现
if(Game_win_1(x/20,y/20)){ //判断输赢1
lblWin.setText(Get_qizi_color(color_Qizi)+“赢了!”);
intGame_Start=0;} if(Game_win_2(x/20,y/20)){ //判断输赢2
lblWin.setText(Get_qizi_color(color_Qizi)+“赢了!”);
intGame_Start=0;}
if(Game_win_3(x/20,y/20))//判断输赢3{
lblWin.setText(Get_qizi_color(color_Qizi)+“赢了!”);
intGame_Start=0;}
if(Game_win_4(x/20,y/20))//判断输赢4{
lblWin.setText(Get_qizi_color(color_Qizi)+“赢了!”);
intGame_Start=0;}
3.3 测试结果
a.进入游戏界面
游戏开始的界面有三个选择项,用户可以选择相应的角色,选择 完毕后点击开始进入游戏。
b.选择角色,开始下棋
首先达到五个棋子连在一块的赢了,并在红色区域显示谁赢了!c.下完后,重新开始
下完一盘后游戏停止,点击重新开始,界面回到初始界面,选择角色继续游戏.d.游戏中点退出,自动判输
在下棋的过程当中谁中途退出,即点击退出,系统自动判断谁输
四、课程设计心得体会
通过此次课程设计,将我本学期所学的JAVA知识得到巩固和应用,在设计的过程中我遇到了很到问题,不过在老师和同学们的帮助和自己的思考下还是很好的完成了。这此课程设计还让我懂得了写程序不能闭门造车,要努力拓宽知识面,开阔视野,拓展思维。它还让我学会了在网上查阅那些无限的资料。由于自己的分析设计和程序经验不足,该系统设计和实现过程中,还有许多没有完善的地方,比如用户界面设计不够美观,异常出错处理比较差等多方面问题,这些都有待进一步完善和提高。对于文中出现的不足和系统中出现的问题敬请老师指导。
五、参考文献
1.吴其庆编著.Java程序设计实例教程.北京:冶金工业出版社 2.柳西玲.许斌编著.Java语言应用开发基础.北京:清华大学出版社 3.丁振凡 Java 语言实用教程 :北京邮电大学出版社
附录(源代码)
import java.net.*;import java.io.*;import java.applet.*;import java.awt.*;import java.awt.event.*;import java.applet.Applet;import java.awt.Color;Public class wuziqi extends Applet implements ActionListener,MouseListener,MouseMotionListener,ItemListener{ int color_Qizi=0;//旗子的颜色标识 0:白子 1:黑子 int intGame_Start=0;//游戏开始标志 0未开始 1游戏中
int intGame_Body[][]=new int[16][16];//设置棋盘棋子状态
int m=-1;Button b1=new Button(“开始”);Button b2=new Button(“重新开始”);Label lblWin=new Label(“ ”);Checkbox ckbHB[]=new Checkbox[3];Button exist = new Button(“退出”);CheckboxGroup ckgHB=new CheckboxGroup();public void init(){
setLayout(null);
addMouseListener(this);
add(b1);
b1.setBounds(330,50,80,30);
b1.addActionListener(this);
add(b2);
b2.setBounds(330,90,80,30);
b2.addActionListener(this);
ckbHB[0]=new Checkbox(“执白”,ckgHB,false);
ckbHB[0].setBounds(320,20,60,30);
ckbHB[1]=new Checkbox(“执黑”,ckgHB,false);
ckbHB[1].setBounds(380,20,60,30);
ckbHB[2]=new Checkbox(“观看”,ckgHB, false);
add(ckbHB[0]);
add(ckbHB[1]);
add(ckbHB[2]);
ckbHB[0].addItemListener(this);
ckbHB[1].addItemListener(this);
add(lblWin);
lblWin.setBounds(330,180,80,30);
lblWin.setBackground(Color.red);
e.getY()<20 || e.getY()>300){
lblWin.setText(“胜利者!”);//没有显示?
ckbHB[2].setBounds(440, 20,60, 30);add(exist);
exist.setBounds(330,130,80,30);exist.addActionListener(this);Game_start_csh();setSize(500,600);setVisible(true);}
public void itemStateChanged(ItemEvent e){ if(ckbHB[0].getState())//选择黑子还是白子 {
color_Qizi=0;} else {
color_Qizi=1;} }
public void mousePressed(MouseEvent e){} public void mouseClicked(MouseEvent e){ Graphics g=getGraphics();int x1,y1;x1=e.getX();y1=e.getY();
if(e.getX()<20 || e.getX()>300 ||
return;}
if(x1%20>10){
x1+=10;}
if(y1%20>10){
y1+=10;}
x1=x1/20*20;y1=y1/20*20;set_Qizi(x1,y1);m*=(-1)}
public void actionPerformed(ActionEvent e){ Graphics g=getGraphics();if(e.getSource()==b1){
Game_start();
} else{
// 输了!“);
赢了!”);
Game_re();}
if(e.getSource()==exist){
Game_re();
color_Qizi=m;
lblWin.setText(Get_qizi_color(color_Qizi)+“
intGame_Start=0;
}
}
public void mouseEntered(MouseEvent e){} public void mouseExited(MouseEvent e){} public void mouseReleased(MouseEvent e){} public void mouseDragged(MouseEvent e){} public void mouseMoved(MouseEvent e){} public void paint(Graphics g){ draw_qipan(g);}
public void set_Qizi(int x,int y){ //落子
if(intGame_Start==0){//判断游戏未开始
return;}
if(intGame_Body[x/20][y/20]!=0){
return;}
Graphics g=getGraphics();
if(color_Qizi==1){//判断黑子还是白子
g.setColor(Color.black);
color_Qizi=0;} else{
g.setColor(Color.white);
color_Qizi=1;}
g.fillOval(x-10,y-10,20,20);
intGame_Body[x/20][y/20]=color_Qizi+1;if(Game_win_1(x/20,y/20)){ //判断输赢1 lblWin.setText(Get_qizi_color(color_Qizi)+”
intGame_Start=0;
了!“);
赢了!”);
赢了!“);
15*15
}
if(Game_win_2(x/20,y/20)){ //判断输赢2{
lblWin.setText(Get_qizi_color(color_Qizi)+”赢
intGame_Start=0;}
if(Game_win_3(x/20,y/20)){ //判断输赢3
lblWin.setText(Get_qizi_color(color_Qizi)+“
intGame_Start=0;}
if(Game_win_4(x/20,y/20)){ //判断输赢4
lblWin.setText(Get_qizi_color(color_Qizi)+”
intGame_Start=0;} }
public String Get_qizi_color(int x){
if(x==0){
return “黑子”;} else {
return “白子”;} }
public void draw_qipan(Graphics G){ //画棋盘 G.setColor(Color.lightGray);
G.fill3DRect(10,10,300,300,true);G.setColor(Color.black);for(int i=1;i<16;i++){
G.drawLine(20,20*i,300,20*i);
G.drawLine(20*i,20,20*i,300);} }
public void Game_start(){ //游戏开始
intGame_Start=1;
Game_btn_enable(false);
b2.setEnabled(true);} public void Game_start_csh(){//游戏开始初始化
intGame_Start=0;
Game_btn_enable(true);
b2.setEnabled(false);
ckbHB[0].setState(true);
for(int i=0;i<16;i++){
for(int j=0;j<16;j++){
intGame_Body[i][j]=0;
}
}
lblWin.setText(“");} public void Game_re(){ //重新开始游戏
repaint();
Game_start_csh();} public void Game_btn_enable(boolean e){ //设置组件状态
b1.setEnabled(e);
b2.setEnabled(e);
ckbHB[0].setEnabled(e);
ckbHB[1].setEnabled(e);} public boolean Game_win_1(int x,int y){ //横向判断输赢
int x1,y1,t=1;
x1=x;
y1=y;
for(int i=1;i<5;i++){
if(x1>15){
break;
}
if(intGame_Body[x1+i][y1]==intGame_Body[x][y]){
t+=1;
}
else{
break;
}
}
for(int i=1;i<5;i++){
if(x1<1){){
t+=1;
}
else{
break;
}
}
if(t>4){
return true;
}
else{
return false;
} } public boolean Game_win_2(int x,int y){ //纵向判断输赢
int x1,y1,t=1;
x1=x;
y1=y;
for(int i=1;i<5;i++){
if(x1>15){
break;
}
if(intGame_Body[x1][y1+i]==intGame_Body[x][y]){
t+=1;
}
else{
break;
}
}
for(int i=1;i<5;i++){
if(x1<1){
break;
}
if(intGame_Body[x1][y1-i]==intGame_Body[x][y]){
t+=1;
}
break;
}
if(intGame_Body[x1-i][y1]==intGame_Body[x][y]
else{
break;
}
}
if(t>4){
return true;
}
else{
return false;
} } public boolean Game_win_3(int x,int y){ //左斜判断输赢
int x1,y1,t=1;
x1=x;
y1=y;
for(int i=1;i<5;i++){
if(x1>15){
break;
}
if(intGame_Body[x1+i][y1-i]==intGame_Body[x][y]){
t+=1;
}
else{
break;
}
}
for(int i=1;i<5;i++){
if(x1<1){
break;
}
if(intGame_Body[x1-i][y1+i]==intGame_Body[x][y]){
t+=1;
}
else{
break;
}
}
if(t>4){
return true;
}
else{
return false;
} } public boolean Game_win_4(int x,int y){ //左斜判断输赢
int x1,y1,t=1;
x1=x;
y1=y;
for(int i=1;i<5;i++){
if(x1>15){
break;
}
if(intGame_Body[x1+i][y1+i]==intGame_Body[x][y]){
t+=1;
}
else{
break;
}
}
for(int i=1;i<5;i++){
if(x1<1){
break;
} if(intGame_Body[x1-i][y1-i]==intGame_Body[x][y]){
t+=1;
}
else{
break;
}
}
if(t>4){
return true;
}
else{
return false;
} } }
第三篇:五子棋游戏总体设计与实现
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 本章小结
本章主要内容是游戏的实现,包括主类的实现,如构造函数、事件处理等,游戏帮助和介绍表单类的实现,游戏设置类的实现,如棋盘、选手、难度等,旗子类的实现,如棋子行列位置、检查越界等,对战逻辑类的实现,如落子和悔棋、逻辑运算等的实现。
第四篇:java五子棋游戏_控制台_总结报告
总结
一、目的:
1、完成疯狂java讲义第四章作业
2、提升代码能力
3、熟悉java语言
二、环境:
Windows8.1系统、jdk1.8、记事本(需要把文件扩展名改成java)
三、遇到的问题:
1、错误需要为class、interface或enum的问题
这个问题,经调试发现是因为注释的时候使用了嵌套注释,即在跨行注释/* */里面添加了跨行注释
2、如何提取控制台输入的问题
这个问题,根据书上例子,采用bufferedreader解决,具体可以参见api文档.3、斜方向棋子的检测问题
这个问题,解决它所需要的算法,着实让我头疼了一下.因为我是以棋盘左边第一列为基准进行斜上方和斜下方的检测,以及以棋盘最后一列为基准进行斜上方和斜下方的检测.第一列的检测会好做很多,因为只需要两层嵌套for循环的i和j相加或相减就可以实现斜方向的递进.而以最后一列的,则需要让两层嵌套for循环i和j的初始值设定为棋盘大小,然后递减.这就导致无法直接用i和j相加或相减来实现递进.我的解决办法是引入额外的变量reduce(具体详见源码),从0开始递增,这样就可以用i和reduce的相加或相减来实现递进.四、所做的内容: 和大多数五子棋游戏代码一样,我也是采用一个二维数组board来作为棋盘.同时采用一个全局变量boardsize来指定这个二维数组的大小,类似于这样:board[boardsize][boardsize].然后使用水平、竖直、斜方向来检测游戏是否出现结果。
有棋盘初始化函数,对二维数组board[][]进行赋值.有棋盘打印函数实现棋盘的显示.一个棋子输入函数.一个胜负检测函数.一个信息输出函数.然后在main函数里面采用while循环实现游戏的流程.列举几个很有用的变量:
Board[][];//字符串型,作为棋盘的二维数组,是全局变量
Boardsize;//int型,控制棋盘大小,是全局变量
E_o_t;//布尔变量,用来判断main函数中的while循环是否结束.即实现游戏是否结束功能.W_steps,B_steps;//int型,用来记录白棋,黑棋连在一起的棋子的个数,它们中的任何一个值达到5,则代表相应的棋手赢了.Reduce;//int型,在胜负检测函数中斜方向的检测用到,前面用介绍.控制台用到的命令:
Javac;//用来编译记事本写的程序.Java;//用来执行编译过的程序
五、总结:
这次的作业,感觉对自己的代码能力有一定的提升,同时,对java编程有了更深的认识, 同时了解到在java编程中,几乎所有的全局变量和方法函数,需要被定义成static.也认识到java提供的一些方法函数功能十分强大,例如bufferedreader.六、源码:
importjava.io.InputStreamReader;importjava.io.BufferedReader;public class test2{ private static String[][] board;private static intboard_size=16;
private static boolean PLAYER=true;//棋手,默认白棋先下.false代表黑棋,true代表白棋 private static booleane_o_n=true;//作为循环(游戏)是否结束的依据,意思为end or not.public static void board_init(){ board=new String[board_size][board_size];for(inti=0;i for(int j=0;j board[i][j]=“+”; } } } public static void board_print(){ for(inti=0;i if(i==0){ for(intbou=0;bou if(bou==0) System.out.print(bou+“-------”); else if(bou>=1&&bou<=9) System.out.print(“0”+bou+“-”); else System.out.print(bou+“-”); } System.out.print(“n”); } for(int j=0;j if(j==0){ System.out.print(i+1+“t”+board[i][j]); } else System.out.print(“-”+board[i][j]); } } System.out.print(“n”);} for(intbou=0;bou if(bou==0) System.out.print(“--------”); else if(bou>=1&&bou<=9) System.out.print(“0”+bou+“-”); else System.out.print(bou+“-”); } System.out.print(“n”); //实现棋子输入并调换棋手 public static void qizi_input(inta,int b){ int x=a-1; int y=b-1; if(x>=0&&y if(true==PLAYER){ board[x][y]=“●”; PLAYER=false; } else{ } } else board[x][y]=“○”;PLAYER=true; System.out.println(“【棋子必须落在棋盘上且该位置没有已下的棋子!】”); } public static void WINNERis(){ //实现判断胜负方法并输出输赢信息 intB_steps=0;intW_steps=0;for(inti=0;i for(int j=0;j if(board[i][j]==“●”){ W_steps++; } else{ W_steps=0;} if(board[i][j]==“○”){ B_steps++;} else{ B_steps=0;} if(5==W_steps){ System.out.print(“【白棋赢了O(∩_∩)O!黑棋输了~(╯﹏╰)~】”);e_o_n=false;break;} if(5==B_steps){ System.out.print(“【黑棋赢了O(∩_∩)O!白棋输了~(╯﹏╰)~】”); e_o_n=false; break; } } W_steps=0;B_steps=0; } for(int j=0;j for(inti=0;i if(board[i][j]==“●”){ W_steps++;} else{ W_steps=0;} if(board[i][j]==“○”){ B_steps++;} else{ B_steps=0;} if(5==W_steps){ System.out.print(“【白棋赢了O(∩_∩)O!黑棋输了~(╯﹏╰)~】”);e_o_n=false;break;} “); ”); if(5==B_steps){ System.out.print(“【黑棋赢了O(∩_∩)O!白棋输了~(╯﹏╰)~】”); e_o_n=false; break; } } W_steps=0;B_steps=0; } for(inti=0;i for(int j=0;j if(i+j if(board[i+j][j]==“●”){ W_steps++;} else{ W_steps=0;} if(board[i+j][j]==“○”){ B_steps++;} else{ B_steps=0;} if(5==W_steps){ System.out.print(“【白棋赢了O(∩_∩)O!黑棋输了~(╯﹏╰)~】 e_o_n=false;break;} if(5==B_steps){ System.out.print(”【黑棋赢了O(∩_∩)O!白棋输了~(╯﹏╰)~】 e_o_n=false; break; } } else continue;} for(int j=0;j if(board[i-j][j]==“●”){ “); ”); W_steps++;} else{ W_steps=0;} if(board[i-j][j]==“○”){ B_steps++;} else{ B_steps=0;} if(5==W_steps){ System.out.print(“【白棋赢了O(∩_∩)O!黑棋输了~(╯﹏╰)~】 e_o_n=false;break;} if(5==B_steps){ System.out.print(”【黑棋赢了O(∩_∩)O!白棋输了~(╯﹏╰)~】 e_o_n=false; break; } } else continue;} W_steps=0;B_steps=0; } for(inti=board_size-2;i>0;i--){ //实现最右列的斜方向的判断 int reduce=0;for(int j=board_size-1;j>0;j--){ if(i-reduce>0){ if(board[i-reduce][j]==“●”){ W_steps++;} else{ W_steps=0;} if(board[i-reduce][j]==“○”){ B_steps++;} “); ”); “); ”); else{ B_steps=0;} if(5==W_steps){ System.out.print(“【白棋赢了O(∩_∩)O!黑棋输了~(╯﹏╰)~】 e_o_n=false;break;} if(5==B_steps){ System.out.print(”【黑棋赢了O(∩_∩)O!白棋输了~(╯﹏╰)~】 e_o_n=false; break; } reduce++;} else continue;} reduce=0;for(int j=board_size-1;j>0;j--){ if(board_size>i+reduce){ if(board[i+reduce][j]==“●”){ W_steps++; } else{ W_steps=0; } if(board[i+reduce][j]==“○”){ B_steps++; } else{ B_steps=0; } if(5==W_steps){ System.out.print(“【白棋赢了O(∩_∩)O!黑棋输了~(╯﹏╰)~】 e_o_n=false;break;} if(5==B_steps){ System.out.print(”【黑棋赢了O(∩_∩)O!白棋输了~(╯﹏╰)~】 e_o_n=false; break; } reduce++; } else continue; } W_steps=0; B_steps=0; } } public static void INFO_SHOW(){ //显示棋盘及必要信息:落子方重新开始退出游戏 System.out.println(“【输入格式为:‘1,1’或者‘88,99’】”); if(true==PLAYER) System.out.print(“【想重新开始吗?请输入暗号88,88】【想退出游戏吗?请输入暗号66,66】n【现在落子方是白棋:”); else System.out.print(“【想重新开始吗?请输入暗号88,88】【想退出游戏吗?请输入暗号66,66】n【现在落子方是黑棋:”);} public static void main(String[] args)throws java.io.IOException { /** **实现整个逻辑流程的实现,** **黑白两方的步数统计 **胜负信息输出*/ test2 WUZIQI= new test2();//创建对象 System.out.print(“【控制台五子棋,超高逼格版】n【默认白棋先下,你无法改变,这就是命!】n【请务必根据指示操作】n”); WUZIQI.board_init(); WUZIQI.board_print(); //实现电脑控制台的输入读取 BufferedReader P_INPUT= new BufferedReader(new InputStreamReader(System.in)); String str_input= null; //循环体实现游戏框架 while(e_o_n){ INFO_SHOW(); } } str_input=P_INPUT.readLine();String[] posStrArr=str_input.split(“,”);intxPos=Integer.parseInt(posStrArr[0]);intyPos=Integer.parseInt(posStrArr[1]);if(88==xPos&&88==yPos){ WUZIQI.board_init();continue;} if(66==xPos&&66==yPos){ e_o_n=false;continue;} qizi_input(xPos,yPos);WUZIQI.board_print();WINNERis();System.out.println(“n【游戏结束,再见哦,亲!】”); } 《JAVA程序设计》 实习报告 实习题目 学生姓名 学生学号 学生姓名 学生学号 学生姓名 学生学号 所在专业 所在班级 指导教师 实习时间 成绩: 老师评语: 五子棋 计算机网络技术 11/6/27—11/7/1 五子棋 下面是五子棋的部分截图: 这里实现了服务器:数据的保存及转发; 联网对战:桌位的选择、悔棋、认输、和棋; 聊天模块:文本聊天、语音聊天; 练习模式:难度的划分、悔棋。 这些功能是如何实现的呢?下面来一步步分解。服务器 1、服务器与客户端是用socket来连接的。连接成功后,客户端会把客户的登陆的信息(用户名、性别、头像)发往服务器。服务器是通过链表来记录每个用户的信息。 class Node{ String username=null;//用户昵称 String tableNum=null;//桌 号及座位号,格式是:桌号:座位号 int score;//分数 Socket Socket=null;//套接字 ObjectOutputStream output=null;//输出流 ObjectInputStream input=null;//输入流 Node next=null;//保存链表中下一节点的指针 } 2、下面是服务器通过链表记录的客户对像流来转发数据给相应的客户端。代码还是简单明了的。如: if(type2.equalsIgnoreCase(“重新开局”)) { } String isResart=(String) tobody.output.writeObject(“下棋操作”);tobody.output.flush(); tobody.output.writeObject(“重新开局”);tobody.output.flush(); tobody.output.writeObject(isResart);tobody.output.flush();node.input.readObject();//System.out.println(“isResart:”+isResart); 3、由于这是一个可以有十六个玩家进来的游戏,那么怎样确定哪个玩家与哪个玩家在同一张桌子上下棋呢?我这里用到的链表记录的String tableNum=null;//桌 号及座位号,格式是:桌号:座位号。 如第一张桌第一个坐位与第二个坐位的记录是:0:0;0:1。以此类推。1:0,1:1;2:0,2:1…… 服务器的根据桌号与坐位号来转发数据的。用IF语句判断。获得对手的对像流来发送数据。 //获取发送对象 String table=node.tableNum.substring(0, String String tableNum=null; if(Integer.parseInt(seat)==0) tobody=userInfoList.findtable(tableNum); tableNum=table+“:”+1;tableNum=table+“:”+0;else node.tableNum.indexOf(“:”));seat=node.tableNum.substring(node.tableNum.indexOf(“:”)+1); 客户端 1、棋盘里的棋子是用一个整型二维数组来记录的。GramP[x][y],x代表横的格数,并是具体坐标;y代表竖的格数,并是具体坐标;x* 28、y*28就是具体坐标。0代表没有棋子,1代表白棋,2代表黑棋。 2、判断输赢的方法很简单,每下一个棋子,都要判断一次。在当前棋子的0、45、90、135度方向上判断是否有五个同样的棋子相连。这里用到了y=kx+b函数来计算。要分开黑棋与白棋的判断,定义一个入口参数,增加代码的复用性,输与赢会用到重画方法,所以也定义了Graphics g入口参数。代码如下: public void isWin(int chessID,Graphics g) { //横向判断 for(int k=0;k<19;k++){ } whiteScore=0; //竖向判断 for(int h=0;h<19;h++){ if(GramP[x][h]==chessID){ { } whiteScore=0;++whiteScore;}else if(GramP[k][y]==chessID){ }else { } //如果大于五子连珠,就为赢 if(whiteScore>=5){ } win_tip(chessID,g);break;whiteScore=0;++whiteScore; } if(whiteScore>=5){ } win_tip(chessID,g);break;whiteScore=0;//135向判断 int b1;b1=y-x;if(b1>=0){ { for(int a=-b1,b=0;a<19;a++,b++){ if(GramP[a][b]==chessID){ { ++whiteScore;for(int a=0,b=b1;b<19;a++,b++){ } whiteScore=0; if(GramP[a][b]==chessID){ { } if(whiteScore>=5){ } win_tip(chessID,g);break;whiteScore=0;++whiteScore; }else }else }else } } } if(whiteScore>=5){ } win_tip(chessID,g);break;whiteScore=0;whiteScore=0;//45向判断 int b2;b2=x+y;if(b2<=18){ { for(int c=18,d=b2-18;d<19;c--,d++){ if(GramP[c][d]==chessID){ ++whiteScore;for(int c=b2,d=0;c>=0;c--,d++){ } whiteScore=0;if(GramP[c][d]==chessID){ }else { } if(whiteScore>=5){ } win_tip(chessID,g);break; whiteScore=0;++whiteScore;}else } } } }else { } if(whiteScore>=5){ } win_tip(chessID,g);break; whiteScore=0;whiteScore=0;//平局 int count=0;for(int i=0;i<19;i++){ } if(count==180){ } win_tip(3,g);for(int j=0;j<19;j++){ } if(GramP[i][j]==chessID){ } count++; 3、悔棋分为悔一步还是悔两步。由一个布尔变量来判断,如果下完棋再悔棋,只悔一个棋。如果没下棋,就悔两个棋。由一维的字符串数组ReGame[]来记录下棋的先后顺序。格式中: ReGame[R++]=x+“:”+y;下面是悔两个棋子的代码。 public void regretGrame2() for(int i=0;i<361;i++){ if(ReGame[i]==null){ } } { } //System.out.println(ReGame[i-1]);//System.out.println(ReGame[i-2]);String X1=ReGame[i-1].substring(0, String String X2=ReGame[i-2].substring(0, String GramP[Integer.parseInt(X1)][Integer.parseInt(Y1)]=0;GramP[Integer.parseInt(X2)][Integer.parseInt(Y2)]=0;ReGame[i-1]=null;ReGame[i-2]=null;R-=2;break;ReGame[i-1].indexOf(“:”));Y1=ReGame[i-1].substring(ReGame[i-1].indexOf(“:”)+1);ReGame[i-2].indexOf(“:”));Y2=ReGame[i-2].substring(ReGame[i-2].indexOf(“:”)+1);repaint();悔一个棋子的,类似。 这只是悔棋函数,只能应用于本用户进行悔棋操,与电脑下棋的悔棋,就直接调用这个函数即可。 但是在联网模式中,通过对像流向服务器发送悔棋标识,再由服务器转发给对手,如果对手同意的吧,对手就会调用悔棋函数,进行自身棋盘的悔棋,同时会向服务器返回一个yes1或yes2标识,发起方收到了,也会调用悔棋函数进行悔棋操作。如果对方不同意,则会返回一个no标识,发起方只会提示玩家,而不进行悔棋操作。 认输及和棋的步骤类似,不再累述。下面是悔棋操作的部分主要代码: 发起请求悔棋: //请求悔棋 public void isRegretGrame(){ if(R>=2&&!isEnd)//只有两个棋子以上才可以悔棋,否则数组会越界.分胜负时也不能悔棋 { { if(flag)//下棋前,悔棋 { try { } oos.writeObject(“下棋操作”);oos.flush();oos.writeObject(“悔棋”);oos.flush();oos.writeObject(“isRegret2”);oos.flush(); e.printStackTrace();} catch(IOException e){ }else //下棋后,悔棋 { } try { } oos.writeObject(“下棋操作”);oos.flush();oos.writeObject(“悔棋”);oos.flush();oos.writeObject(“isRegret1”);oos.flush();e.printStackTrace();} catch(IOException e){ }else JOptionPane.showMessageDialog(this, “不能执行悔棋操作”, “警告”, JOptionPane.WARNING_MESSAGE);} } 服务器转发悔棋请求: 这只是服务转发的悔棋部分的数据。 String type=(String)node.input.readObject();//读取信息类型 { if(type2.equalsIgnoreCase(“悔棋”)) { String isRegret=(String)if(type.equalsIgnoreCase(“下棋操作”))node.input.readObject(); } } tobody.output.writeObject(“下棋操作”);tobody.output.flush(); tobody.output.writeObject(“悔棋”);tobody.output.flush(); tobody.output.writeObject(isRegret);tobody.output.flush();收接悔棋请求:下面代码是在客户端收接数据的线程里的。 String type=(String)ois.readObject();if(type.equalsIgnoreCase(“下棋操作”)){ if(type2.equalsIgnoreCase(“悔棋”)) {){ JOptionPane.showMessageDialog(this, “对方不同意悔棋 String isRegret=(String)ois.readObject();if(”yes2“.equalsIgnoreCase(isRegret)){ } else if(”yes1“.equalsIgnoreCase(isRegret)){ regretGrame1(); regretGrame2(); }else if(”no1“.equalsIgnoreCase(isRegret)||”no2“.equalsIgnoreCase(isRegret)”, “提示”,JOptionPane.WARNING_MESSAGE); } else if(“isRegret2”.equalsIgnoreCase(isRegret)){ int result = JOptionPane.showConfirmDialog(this, “对方请求悔棋,是否同意?”, “提示”, JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE); if(result == JOptionPane.YES_OPTION){ oos.writeObject(“下棋操作”);oos.flush(); oos.writeObject(“悔棋”); } oos.flush(); oos.writeObject(“yes2”);oos.flush();regretGrame2(); }else if(result==JOptionPane.NO_OPTION){ //System.out.println(“对方不同意悔棋”); oos.writeObject(“下棋操作”);oos.flush(); oos.writeObject(“悔棋”);oos.flush(); oos.writeObject(“no2”);oos.flush();} else if(“isRegret1”.equalsIgnoreCase(isRegret)){ int result = JOptionPane.showConfirmDialog(this, “对方请求悔棋,是否同意?”, “提示”, JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE); } if(result == JOptionPane.YES_OPTION){ oos.writeObject(“下棋操作”);oos.flush(); oos.writeObject(“悔棋”);oos.flush(); oos.writeObject(“yes1”);oos.flush(); regretGrame1(); } 聊天模块 1、文字聊天,也是通过服务器转发数据的,客户端就接收与显示。在这里不再详说了。 2、重点是语音聊天,这里的语音连接,首先通过服务器转发发起方的语音标识,对方收到后,如果选择“是”,那它就会通过服务器转发IP地址给发起方,并同时起动serversocket监听。发起方收到对方同意语音连接的标识与IP地址后,就可以与对方连接了,语音链路就建起了。断开的思路也是差不多的。练习模式 1、电脑下棋的算法: 通过遍历棋盘,计算权值,哪个位置的权值最高,就在哪个位置下棋。权值的大小预定为: //黑白白空 50 //空白白空 100 //黑白白白空 500 //空白白白空 1000 //黑白白白白空 5000 //空白白白白空 10000 //白白白白白 100000 首先假定下棋点,再计算权值之和的大小。 权值之和=0度方向的带胜权值和堵敌的权值之和+45度方向的带胜权值和堵敌的权值之和+90度方向的带胜权值和堵敌的权值之和+135度方向的带胜权值和堵敌的权值之和.下面代码,假定落子点,再把四个方向上的的权值加起来。 //记录当前假定的落子点 private int getQuan(int i,int j) { } //水平权值 private int getQuan0(int i, int j){ int samechessNumS=0;//相同棋子的个数 int samechessNumF=0;int blankNumS=0;// 空子的个数 int blankNumF=0;int q=0;//求当前位置的权值 q+=getQuan0(i,j);//得到水平方向上的权值,下面类似 q+=getQuan90(i,j);q+=getQuan135(i,j);q+=getQuan45(i,j); return q; 下面是只是求水平权值的代码,通过一个二维二元数组来左右求索棋子的个数。 } int q=0,qS=0,qF=0;int [][]ij0=new int[2][2];//计算权值用的 ij0[0][0]=ij0[0][1]=i;ij0[1][0]=ij0[1][1]=j;samechessNumS=getsamechessNum0(ij0,back);//得到黑子数目 if(ij0[0][0]>=0) //得到速胜权值 ij0[0][0]=ij0[0][1]=i;ij0[1][0]=ij0[1][1]=j;samechessNumF=getsamechessNum0(ij0,white);//得到白子数目 if(ij0[0][0]>=0) if(curchess[ij0[0][0]][ij0[1][0]]==Chess)blankNumF++;if(curchess[ij0[0][0]][ij0[1][0]]==Chess)blankNumS++;if(ij0[0][1]<19)if(curchess[ij0[0][1]][ij0[1][1]]==Chess)blankNumS++;qS=getQuanpart(samechessNumS,blankNumS);if(ij0[0][1]<19)if(curchess[ij0[0][1]][ij0[1][1]]==Chess)blankNumF++;qF=getQuanpart(samechessNumF,blankNumF);//得到堵敌权值 q=qS+qF;return q;//得到水平方向的同子数目 private int getsamechessNum0(int[][] qij, int chessID){ int num=1;//存储相同棋子数目,当前点满足条件 qij[0][0]--;//向左探索我们只探索临近的4个点,注意不要出边界 while(qij[0][0]>=0&&num<5){ } qij[0][1]++;//向右求索 while(qij[0][1]<19&&num<5)if(curchess[qij[0][0]][qij[1][0]]!=chessID)break;num++;qij[0][0]--; } { } return num;if(curchess[qij[0][1]][qij[1][1]]!=chessID)break;num++;qij[0][1]++;//求得某一方向上的一半权值 private int getQuanpart(int sameChessNum, int blankNum){ } if(sameChessNum==2&&blankNum==1)return q2o;else if(sameChessNum==2&&blankNum==2)return q2;else if(sameChessNum==3&&blankNum==1)return q3o;else if(sameChessNum==3&&blankNum==2)return q3;else if(sameChessNum==4&&blankNum==1)return q4o;else if(sameChessNum==4&&blankNum==2)return q4;else if(sameChessNum==5)return q5;else return 0; 2、划分难度等级 我这里,是通过改变它的预定权值的大小,而达到改变难度的。 3、悔棋,比对战模式(即联网对战)的悔棋还简单。只需用到悔两个棋子的悔棋函数即可。第五篇:五子棋实习报告