中国象棋人人对战.docx
《中国象棋人人对战.docx》由会员分享,可在线阅读,更多相关《中国象棋人人对战.docx(91页珍藏版)》请在冰豆网上搜索。
![中国象棋人人对战.docx](https://file1.bdocx.com/fileroot1/2022-11/22/b4a61e0d-c3fa-407e-982d-af994ce083e1/b4a61e0d-c3fa-407e-982d-af994ce083e11.gif)
中国象棋人人对战
中国象棋----人人对战设计
学号:
系别:
姓名:
班级:
成员:
中国象棋--人人对战设计
1、问题定义
中国象棋在单击游戏可执行文件进入游戏,游戏系统初始化游戏界面,进入游戏系统后,用户可能单击棋子,再点击相应棋子坐标或棋子,实现棋子移动、吃棋子功能。
实现人机对弈。
用户在对弈中,可以实现、新游戏、退出游戏功能。
系统的用例图如下所示:
图1系统用例图
2、可行性研究
用户进入系统,进入游戏,把自己的电脑设为主机实现人机对弈。
从功能上基本能满足用户的需求。
性能稳定可靠。
3、需求分析
3.1象棋棋子走法规则和功能分析
(1)中国象棋是双方在有着9调竖线和10条横线的棋盘上对弈,竖线和横线的交叉称为棋点或对弈点,每个棋子都是在棋点上行走,而不是在方格中行走。
(2)河界将棋盘分成两等份,每一边都有一块有9个点组成的九宫,棋子“将”,“帅”和“士”只能在九宫内移动,并且“将”和“帅”每一步只可以水平或垂直移动一个棋点;“士”只能在九宫内移动,并且它每一步只可以沿着对角线移动一个棋点;“象”必须一次沿着对角线方向走两个棋点,但它不能过河也不能跳过或穿越障碍,即“象”不能别眼,“马”没一步只可以水平或垂直移动两个棋点,但必须按对角线向左或向右移动。
中国象棋的“马”不能跳过障碍,即马不能别腿。
“车”可以水平或垂直方向移动入一个无障碍的点。
“炮”移动起来和车类似,但它必须跳过一个棋子来吃掉对方的一个棋子。
“兵”每步只能向前移动一个棋子过河以后,它便增加了向左右移动的能力,并不允许向后移动。
3.2系统数据流图
(1)0层数据流图
图20层数据流图
(2)1层数据流图
图31层数据流图
(3)2层数据流图
图42层数据流图
3.3数据字典设计
1.外部实体定义表
编号
名称
内部名
输入数据流
输出数据流
备注
W01
玩家
W02
系统
2.数据流定义表
编号
数据流名
内部名
组成
备注
D01
按钮信息
ae
E01||E02||E03
D02
标签信息
me
E04||E05
D03
重来按钮
anew
E01
D04
梅棋按钮
E02+E06+E07+E08
D05
退出按钮
exit
E03
D06
棋盘信息
E04+E06+E07+E08+E10
D07
单击棋子信息
E05+E06+E07+E08+E09+E10
D08
棋子信息
E05+E06+E07+E08+E10
D09
初始化信息
E01+E02+E03+E04+E05
3.数据元素定义表
编号
数据元素名
内部名
类型
备注
E01
重新开始
anew
JButton
E02
悔棋
repeat
JButton
E03
退出
exit
JButton
E04
棋盘
image
JLabel
E05
棋子
play
JLabel
E06
索引号
man
int
(2)
E07
横坐标
Ex
int
(2)
E08
纵坐标
Ey
int
(2)
E09
单击棋子
chessmanclik
boolean
E10
控制玩家走棋
chessmanclick
int
(2)
4.加工定义
编号
名称
内部名
输入数据
输出数据
加工逻辑
P1.1
判断按钮事件
actionperformed
D01
D03、D04、D05
P1.2
重来
restart
D03
P1.3
悔棋
back
D04
P1.4
退出
over
D05
P1.5
判断鼠标事件
mouseclicked
D02
D06、D07
P1.6
闪烁
run
D07
P1.7
初始化界面
chessmainframe
D09
D08
P1.8
添加棋子
drawchessman
D08
P2.1
棋子移动规则
D06
P2.2
吃棋子规则
D07、D08
3.4状态转换图
下图图5状态转换图:
4、总体设计
4.1总体流程图和中国象棋功能模块
中国象棋游戏需要实现的基本功能应包括以下几个方面:
(1)提供棋盘和棋子;
(2)设定棋子的走棋规则;(3)可以悔棋、重来、退出;(4)判断胜负。
根据对中国象棋游戏的功能分析,设计得到中国象棋游戏的总流程图如图6所示:
图6总体流程图
4.2各部分功能流程图
4.2.1开始游戏
该功能为本游戏的最核心的部分,它实现了中国象棋游戏的最主要的操作,是其他功能的基础。
开始游戏流程图如图7所示:
图7开始游戏流程图
5、详细设计
5.1结构图设计
图8系统总体结构图
5.2棋盘、棋子绘制的算法设计
本中国象棋有限的棋盘和棋子采用的都是图片,采用图片比较简单,不用绘制那么多条线,用图片来代替棋盘和棋子。
建立坐标系,只需使用函数调用图片文件,把象棋图片有序的排列,再使用排列棋子的函数把棋子有序排列。
其中,棋盘距页面左边距离为24,上面为56,棋盘一格为57,棋子直径为55,棋子间的距离为2,例如从上面开始,黑棋子“车”的坐标为(24,56),黑马为(81,56),红“车”的坐标(24,596),依此类推就可以计算各棋子的坐标,这样算法较易实现。
5.3棋种走棋规则的算法设计
5.3.1“车”的走棋规则的算法设计
“车”,它只能走直线,且中间不能有任何棋子,设计时分为两种情况来考虑,一种是纵向行走;一种是横向行走。
用if语句来判断实现,例如车纵向行走,首先,用if来判断棋子是否纵向行走,接着再用另一判断语句if来判断中间有没别的棋子。
横向行走同理。
如果棋子车符合以上的走棋规则,则可以走动,否则棋子强制放回原处。
现在假设车的棋点坐标为(i,j),i为横坐标,j为纵坐标,再设x,y为棋盘内任意值。
算法设计流程图如图9所示:
图9“车”的走棋规则算法设计流程图
5.3.2“马”的走棋规则的算法设计
“马”,它只能走“日”字格,而且马腿不能被其它的棋子压到。
设计时可
两种情况来考虑,一种是横向走两个棋点,纵向走一个棋点;一种是纵向走两个棋点,横向走一个棋点。
用if语句来判断。
首先,用if来判断棋子是否横向走两个棋点,纵向走一个棋点,接着再用判断语句if来判断马腿是否被其它棋子压着。
纵向走“日”同理。
如果棋子马符合以上的走棋规则,则可以走动,否则棋子强制放回原处。
现在假设马的棋点坐标为(a,b),a为横坐标,b为纵坐标,再设x,y为棋盘内任意值。
算法设计流程图如图10所示:
图10“马”的走棋规则算法设计流程图
5.3.3“卒”的走棋规则的算法设计
“卒”,它的行走规则分两种情况。
一种是棋子没过河界,另一种是棋子过了河界。
用if语句来判断,首先,用if语句来设定棋子没过河界,接着设定棋子在没过河界的情况下只能向前行走一个棋点;然后用if语句来设定棋子过了河界,紧接着设定棋子在过了河界的情况下只能向前、向左、向右行走一个棋点。
如果棋子卒符合以上的走棋规则,则可以走动,否则棋子强制放回原处。
现在假设卒的棋点坐标为(i,j),i为横坐标,j为纵坐标,再设x,y为棋盘内任意值。
算法设计流程图如图11所示:
图11“卒”的走棋规则算法设计流程图
5.3.4“将”的走棋规则的算法设计
“将”,它只能在“九宫”中行走,而且每次只能横着或者纵着行走一棋点。
直接用if语句来判断,首先,用if来判断棋子是否是在“九宫”里行走,接着判断棋子是否是横向或纵向只走一个棋点。
如果棋子将符合以上的走棋规则,则可以走动,否则棋子强制放回原处。
现在假设将的棋点坐标为(i,j),i为横坐标,j为纵坐标,再设x,y为棋盘内任意值。
算法设计流程图如图12所示:
图12“将”的走棋规则算法设计流程图
5.3.5“炮”的走棋规则的算法设计
“炮”,它只能走直线,且中间有且只能有一个棋子。
假设现在坐标为(i,j),则算法设计流程图如图13所示:
图13“炮”的走棋规则算法设计流程图
5.3.6“象”的走棋规则的算法设计
“象”,它只能走“田”字格,而且不能过河,象腿不能被其它的棋子压到。
这样只有一种情况考虑,那就是纵向走两个棋点,横向也走两个棋点。
用if语句来判断,首先,用if来判断棋子是否走"田"字格,而且不能过河,接着再用判断语句if来判断象腿是否被其它棋子压着。
如果棋子象走动符合以上的走棋规则,则可以走动,否则棋子强制放回原处。
现在假设象的棋点坐标为(i,j),i为横坐标,j为纵坐标,再设x,y为棋盘内任意值。
算法设计流程图如图14所示:
图14“象”的走棋规则算法设计流程图
5.3.7“士”的走棋规则的算法设计
“士”,它只能在“九宫”中行走,而且每次只能斜着行走一格。
这样只有一种情况来考虑,即纵向走一个棋点,横向走一个棋点。
if语句来判断,如果棋子士符合以上的走棋规则,则可以走动,否则棋子强制放回原处。
现在假设士的棋点坐标为(i,j),i为横坐标,j为纵坐标,再设x,y为棋盘内任意值。
算法设计流程图如图15所示:
图15“士”的走棋规则算法设计流程图
6、编码
见附页。
7、运行结果测试与分析
下图是进入游戏主界面后的游戏界面。
图16游戏主界面
7.1测试进入主界面后工具栏的各功能
进入游戏主界面,在主界面的工具栏中,分别有“悔棋”、”退出”“新游戏”功能按钮。
可以点击“退出”结束游戏系统。
在游戏过程中点击“悔棋”实现棋子返回上一步的位置。
在游戏过程中点击“新游戏”结束当前的游戏,开始新的游戏。
7.2对“车”、“马”、“象”、“士”、“卒”、“炮”、“将”走法的测试
“车”的测试,拖动“车”使其隔棋子或按斜角线走动,结果“车”不能被移动,拖动其按直线在界面范围内上下左右移动,结果可以移动,但中间隔了棋子,其不能被移动。
“马”的测试,拖动“马”使其按上下左右方向在主界面中移动,结果不可能移动“马”。
按向左或右走一格,再向上或下走二格时,其中上下左右没有棋子挡着时,可以移动,按向左或右走二格,再向上或下走二格时,其中上下左右没有棋子挡着时,可以移动,中间有棋子时,则移动不了。
“象”、“相”的测试,在主界面范围内,移动象、相向左或右走二格再向上或下行两格(“田”字格),如果在“田”字中间的十字上有棋子,则象或相,移动不了。
相反则可以移。
拖动“象”、“相”按其它任意方向或方式走,棋子无法移动。
“士”、“仕”的测试,拖动“士”、“仕”“九宫”中斜向走一格,结果可以移动,相反,使其按上下左右移动则不可动,向“九宫”外走则棋子不动。
“炮”的测试,拖动“炮”纵、横行,若在纵、横行中,前方有一个棋子,在这个棋子前方有对方的棋子,则可以行走,吃掉对方的棋子。
若纵、横方向没有棋子挡住,则可以纵、横走。
拖动“炮”斜着走,则其不可移动。
“将”的测试,拖其在“九宫”中行走,当其不在“九宫”中行走时,将会停在原处,不能移动。
在“九宫”中其可以纵、横、斜着行走。
“卒”、“兵”的测试,当其没有过河时,拖其向后、左、右行时,则其停在原处,不能移动,拖其向前行时,其可以移动。
当其过的楚河汉界后,可以向前左、右行,当拖其向后行时,棋子无法向后移动。
通过对软件各功能的测试发现,该软件各功能都能实现,性能可靠!
附件:
源代码(以上的设计思想是根据下面的代码分析的)
importjava.awt.*;
importjava.awt.event.*;
importjavax.swing.*;
importjava.util.*;
importjava.io.*;
publicclassChess{
publicstaticvoidmain(Stringargs[]){
newChessMainFrame("中国象棋:
");
}
}
classChessMainFrameextendsJFrameimplementsActionListener,MouseListener,Runnable{
//玩家
JLabelplay[]=newJLabel[32];
//棋盘
JLabelimage;
//窗格
Containercon;
//工具栏
JToolBarjmain;
//重新开始
JButtonanew;
//悔棋
JButtonrepent;
//退出
JButtonexit;
//当前信息
JLabeltext;
//保存当前操作
VectorVar;
//规则类对象(使于调用方法)
ChessRulerule;
/**
**单击棋子
**chessManClick=true闪烁棋子并给线程响应
**chessManClick=false吃棋子停止闪烁并给线程响应
*/
booleanchessManClick;
/**
**控制玩家走棋
**chessPlayClick=1黑棋走棋
**chessPlayClick=2红棋走棋默认红棋
**chessPlayClick=3双方都不能走棋
*/
intchessPlayClick=2;
//控制棋子闪烁的线程
Threadtmain;
//把第一次的单击棋子给线程响应
staticintMan,i;
ChessMainFrame(){
newChessMainFrame("中国象棋");
}
/**
**构造函数
**初始化图形用户界面
*/
ChessMainFrame(StringTitle){
//获行客格引用
con=this.getContentPane();
con.setLayout(null);
//实例化规则类
rule=newChessRule();
Var=newVector();
//创建工具栏
jmain=newJToolBar();
text=newJLabel("欢迎使用象棋对弈系统");
//当鼠标放上显示信息
text.setToolTipText("信息提示");
anew=newJButton("新游戏");
anew.setToolTipText("重新开始新的一局");
exit=newJButton("退出");
exit.setToolTipText("退出象棋程序程序");
repent=newJButton("悔棋");
repent.setToolTipText("返回到上次走棋的位置");
//把组件添加到工具栏
jmain.setLayout(newGridLayout(0,4));
jmain.add(anew);
jmain.add(repent);
jmain.add(exit);
jmain.add(text);
jmain.setBounds(0,0,558,30);
con.add(jmain);
//添加棋子标签
drawChessMan();
//注册按扭监听
anew.addActionListener(this);
repent.addActionListener(this);
exit.addActionListener(this);
//注册棋子移动监听
for(inti=0;i<32;i++){
con.add(play[i]);
play[i].addMouseListener(this);
}
//添加棋盘标签
con.add(image=newJLabel(newImageIcon("image\\Main.GIF")));
image.setBounds(0,30,558,620);
image.addMouseListener(this);
//注册窗体关闭监听
this.addWindowListener(
newWindowAdapter(){
publicvoidwindowClosing(WindowEventwe){
System.exit(0);
}
}
);
//窗体居中
DimensionscreenSize=Toolkit.getDefaultToolkit().getScreenSize();
DimensionframeSize=this.getSize();
if(frameSize.height>screenSize.height){
frameSize.height=screenSize.height;
}
if(frameSize.width>screenSize.width){
frameSize.width=screenSize.width;
}
this.setLocation((screenSize.width-frameSize.width)/2-280,(screenSize.height-frameSize.height)/2-350);
}
/**
**添加棋子方法
*/
publicvoiddrawChessMan(){
//流程控制
inti,k;
//图标
Iconin;
//黑色棋子
//车
in=newImageIcon("image\\黑车.GIF");
for(i=0,k=24;i<2;i++,k+=456){
play[i]=newJLabel(in);
play[i].setBounds(k,56,55,55);
play[i].setName("车1");
}
//马
in=newImageIcon("image\\黑马.GIF");
for(i=4,k=81;i<6;i++,k+=342){
play[i]=newJLabel(in);
play[i].setBounds(k,56,55,55);
play[i].setName("马1");
}
//相
in=newImageIcon("image\\黑象.GIF");
for(i=8,k=138;i<10;i++,k+=228){
play[i]=newJLabel(in);
play[i].setBounds(k,56,55,55);
play[i].setName("象1");
}
//士
in=newImageIcon("image\\黑士.GIF");
for(i=12,k=195;i<14;i++,k+=114){
play[i]=newJLabel(in);
play[i].setBounds(k,56,55,55);
play[i].setName("士1");
}
//卒
in=newImageIcon("image\\黑卒.GIF");
for(i=16,k=24;i<21;i++,k+=114){
play[i]=newJLabel(in);
play[i].setBounds(k,227,55,55);
play[i].setName("卒1"+i);
}
//炮
in=newImageIcon("image\\黑炮.GIF");
for(i=26,k=81;i<28;i++,k+=342){
play[i]=newJLabel(in);
play[i].setBounds(k,170,55,55);
play[i].setName("炮1"+i);
}
//将
in=newImageIcon("image\\黑将.GIF");
play[30]=newJLabel(in);
play[30].setBounds(252,56,55,55);
play[30].setName("将1");
//红色棋子
//车
in=newImageIcon("image\\红车.GIF");
for(i=2,k=24;i<4;i++,k+=456){
play[i]=newJLabel(in);
play[i].setBounds(k,569,55,55);
play[i].setName("车2");
}
//马
in=newImageIcon("image\\红马.GIF");
for(i=6,k=81;i<8;i++,k+=342){
play[i]=newJLabel(in);
play[i].setBounds(k,569,55,55);
play[i].setName("马2");
}
//相
in=newImageIcon("image\\红象.GIF");
for(i=10,k=138;i<12;i++,k+=228){
play[i]=newJLabel(in);
play[i].setBounds(k,569,55,55);
play[i].setName("象2");
}
//士
in=newImageIcon("image\\红士.GIF");
for(i=14,k=195;i<16;i++,k+=114){
play[i]=newJLabel(in);
pl