南京中医药大学 《Java 程序设计》课程设计
2020-2021 学年 二 学期
日期: 2021 年 5 月 30 日
人工智能与信息技术学院
项目名称: 五子棋
南京中医药大学
2
目录
一、概述 …4
1.1 背景…4
1.2 开发工具…4
1.3 功能图…4 二、需求分析…4
三、 游戏设计思路…6
3.1 总体设计…6
3.2 功能设计…6
3.2.1 人人模式…6
3.2.3 人机模式…7
3.3 游戏包设计 …9
3.4 界面棋盘设计… 10
3.5 算法设计… 10
四、 游戏实现… 11
4.1 ChessFrame 主要功能实现… 11
4.2 游戏主窗体实现… 11
4.3 主菜单实现… 12
4.4 具体实现步骤与关键代码… 13
4.4.1 首先创建一个 JFrame 窗体, 取名 J.java。… 13
4.4.2 创建下棋面板 为绘制棋盘做准备, 创建一个 JPanel 面板, 取名
为 Panel.java,… 13
4.4.3 绘制棋盘… 14
4.4.5 下棋功能的实现 … 14
4.4.6 胜负的判断… 19
4.4.7 显示获胜信息… 22
五、游戏功能测试… 22
5.1.1 点击游戏按钮,出现开局,棋盘,模式和退出基本按钮… 23
5.1.2 棋盘布局按钮,可以调整棋盘大小… 23
5.1.3 模式按钮,可以选择是人人还是人机模式进行游戏 … 24
5.1.4 视图按钮可以调整界面的颜色,样式… 24
5.2 人机模式… 26
5.2.1 若黑子先连成五子,则玩家胜利,输出对话框“你赢了,真厉害啊”
… 26
5.2.2 若白子先连成五子,则电脑胜利,输出对话框“你输了,重新开始游
戏”… 26
5.3 人人模式… 27
5.3.1 若黑子先连成五子,则玩家 a 胜利,输出对话框“你赢了,真厉
害”… 27
5.3.2 若白子先连成五子,则玩家 b 胜利,输出对话框“你输了,重新开
始游戏”… 27
5.4 帮助按钮… 28
5.5 点击退出,退出游戏… 28
六、课程总结… 28
南京中医药大学
3
6.1 设计体会… 28
6.2 设计不足… 29
6.3 展望… 29
七.参考文献… 30
南京中医药大学
4
一、概述
1.1 背景
相信大多数人都玩过五子棋这一款非常经典的小游戏, 其中的博弈算法很多文章都有
过专门的介绍,主要针对初学者介绍一种简单的实现五子棋中单机状态和 联机状态下人人
对弈的设计过程和部分源代码。 可将其加入在已有人机对弈的五子棋小游戏中, 增加用户
的满 意度和体验感。通过此次课程设计,巩固所学 Java 语言基本知识,增进 Java 语言编辑
基本功,掌握 JDK、Editplus、Eclipse、JCreator 等开发工具的运用,拓宽常用类库的应用。
使我们通过该教学环节与手段,把所学课程及相关知识加以融会贯通,全面掌握 Java 语言
的编程思想及面向对象程序设计的方法,为今后从事实际工作打下坚实的基础。
1.2 开发工具
本次课程设计,一共设计了一个 Java 版本,使用了主流的 15x20 的棋盘,
配备简单的消息提示,基于 AWT 实现 GUI,开发工具 IntelliJ IDEA 2018.1
1.3 功能图
二、需求分析
随着人们生活压力日益趋增,工作加班在平时已是 家常便饭,越来越多的人都在为数
不多的假期里面,找 一些娱乐方式放松自己,其中选择娱乐性游戏来放松自 己的人占大多
数,例如网络田径游戏、虚拟游戏竞技以 及目前正在发展的 VR 技术,而进入当前这种情
南京中医药大学
5
况的条件 是在现代社会中,当有需求时,供应就会随之产生,更何况不断增长的新网络市
场,如游戏开发以及 5G 的建设, 就是在这样的社会环境下驱动发展的。因此设计一款娱
乐性的计算机游戏是很有市场需求的。 本文以五子棋为例,该游戏开发较为简单,代码量
较少,成本比较低,且游戏对运行环境要求较低,再结合目前的五子棋发展背景,市场前景
较好 。
游戏分为三大部分:第一部分为游戏选项,第二部分为有游戏相关设置,第三部分为游
戏整体界面。其中游戏选项包括六个模块:人人对战、人机对战、重新开始、退出。游戏设
置包括两个模块:棋盘大小设置、棋盘颜色设置。游戏界面包括两个模块:游戏主页面、载
入游戏界面。
一款小游戏的确立是建立在各种各样的需求上面的,这种需求往往来自于玩家的实际需
求,其中玩家的实际需求最为重要.面对游戏拥有不同知识和理解层面的玩家,游戏制作人对
玩家需求的理解程度,在很大程度上决定了此类游戏开发的成败.因此如何更好地的了解,
分析,明确玩家需求,并且能够准确,清晰以文档的形式表达给游戏制作人,保证开发过程
按照满足玩家需求为目的正确开发方向进行,是每游戏游戏制作人需要面对的问题。
制作五子棋小游戏。有两个功能可以实现人机对战还有人人对战两个模式。
该项目为经典版本的五子棋游戏和自创的毁灭玩法所结合,总体而言是一个休闲的小
游戏。其中的规则不难,主要是为了丰富大家的文娱生活,让大家在忙碌的学习课后可以
轻松一小下。这就是本程序的编写初衷。众所周知,经典版本的五子棋不过就是判断 5 连 和 5 连以上的胜负,而这里的毁灭版,可以“毁灭”对方的 4 连状态,从而达到己方的攻
击 ,而使己方达到胜利。而对方亦可以运用这种方法获得胜利。
作为五子棋的设计需要考虑到的最基本的需求莫过于人机对战与人人对战功能的实
现,当然还有下棋过程中的下棋悔棋功能以及判断游戏的胜负等方面的要求。当然最好是
要考虑到界面的友好性,作为一个娱乐软件,还应该考虑到玩家在游戏时的舒适性。
首先,我们需要了解该程序是怎么编写的,需要用到哪些工具,用到哪些知识和方
法。以及是如何运用该方法。
1:了解五子棋的运行机制。
2:了解博弈的对战机制,如:怎么获得胜利,判断胜利的条件。
3:游戏主界面的构造,以及模型的建立。
4:各种功能如何实现,各个部分怎么构成一个整体。
5:事件的处理。
6:如何生成棋盘,以及如何生成棋子。
7:对计时工具的设计,如何运用到多线程来解决。
需要实现的功能:
A.点击开始游戏时在界面上有黑子或白子先行的提示,然后玩家开始行棋。
B.点击游戏设置时提示相应输入限制时间的信息,让玩家设置限定时间。
C.点击悔棋时给玩家一次悔棋机会。
D.点击毁灭时对方玩家棋子变成己方颜色,并且变成方形。
南京中医药大学
6
E.帮助,给出相关信息提示帮助。
三、游戏设计思路
3.1 总体设计
设计人工智能算法五子棋对战,人机对战调试是不可避免的,所以设计一款五子棋调试系统
很有必要。本系统便于调试五子棋 AI,所用 AI 与界面统被分成两个部 分,修改 AI 不需
要更改界面的系统。这两个部分通过标 准输入或输出或网络进行通信,界面系统不仅要实
现人机对战,同时帮助调试 AI。系统功能满足四个方面:(1)有完整的棋盘规格;(2)
界面程序与 AI 实现分离;(3)支持人与人、人与机器人等形式的对战。
3.2 功能设计
3.2.1 人人模式
棋盘数据结构核心:
无论你做数据库开发还是做一些小程序,第一时间考虑的必须是需求+建模。把核心设计
出来。
此次我们用一个二维数组作为棋盘,每条线交叉的地方设为二维数组的值,并约定:
3=空
1=黑棋
2=白棋
然后对应的把下棋,判断输赢(横竖斜)的算法都实现出来。
具体展现如下:
我们需要单击屏幕进行下棋,所以我们需要符合鼠标单击事件的接口。因此我们去接上
MouseListener 的接口。
再然后我们重写 JFrame 里的 paint 方法来画画。
具体体现:如下
南京中医药大学
7
其中横线和竖线都是调用的 Graphics 中的 drawLine 方法。
画圈圈用的是 drawOval 和 fillOval 分别是画空心圆和画实心圆。
3.2.3 人机模式
机器博弈是人工智能领域的重要分支,它的研究对象多以复杂的棋牌类智力游戏为
主,已经得到解决的棋类游戏,几乎全部都应归功于机器博弈近半个世纪的发展。计算机
解决问题的优势在于能把不易解析的问题,借助于现代计算机的运算速度优势枚举出所有
的合理情形而得解;然而,博弈问题的复杂程度决定了它不能过度依赖机器的计算能力。许
多待解决的或已经解决的棋类,其状态空间复杂度或博弈树复杂度量级都太过庞大,所以
我们需要添加约束,并且采用合理的算法进行优化。
五子棋问题是人工智能中的一个经典问题。当今世界,AlphaGo 已经执围棋之牛
耳,五子棋领域却鲜少有人问津。本文根据课堂所学知识结合文献、博客,实现了一个智
能对战的 AI 五子棋游戏平台。
算法介绍如下:
(1) 五子棋界面实现;
(2) 智能判定棋盘走势;
(3) 改进了棋盘扫描方式;
(4) 改良了系统评分表评估方式;
(5) 实现了基于点评分表估值找出最佳落子方式。
五子棋 AI 问题的最大问题是如何实现智能对弈,即当人落子之后,算法如何解读当前
的棋盘并且对其进行分析解读,得到电脑方的最佳落子点。其次还有一个问题是如何判断
胜利,这可以作为前面棋盘局势判定的一个子问题,也可以看做是一个单独的问题,不过
这个问题总体来说较为简单,所以不做详细说明。
五子棋的整体知识构建包含以下部分:
(1) 棋盘局面表示法
(2) 棋局胜利判定
(3) 棋型知识库
(4) 智能博弈流程
对于问题(1),采用数组表示法。棋盘中的各交叉点有三种状态,不妨令 0 表示空(未放
置棋子) ,-1 表示有黑子 ,1 表示有白子,数组表示法的基本思想是:以交叉点对应的数
组索引值来表达物理位置 ,以交叉点对应的元素值表达状态(空、 黑子、 白子)。令 V =
{0 ,1 ,-1} ,棋盘 的第 i 个交叉点的状态 Si ∈V ,任何棋局都可以表示成一个 n ×n
的二元组。
南京中医药大学
8
对于问题(2), 采用数组表示法时,想知道任意两个元素 Si 和 Sj 是否共线,要通过 i
和 j 之间的数值规律来判断。从这方面看,数组表示法是一种原始、低效的表示方法,但
是对于评分表算法来说其性能损失是可以接受的。要判断是否有一方已经胜利,只需要对
整个棋盘判定当前落子点的纵、横、正斜、反斜四个方向的最长延伸出四个位置看是否能
连成一条同色直线即可。具体的操作可以视为:从落子点出发,向两个方向延伸,如果遇
到同色,那么计数器加一,遇到非同色(空白或者异色)则停止在该方向的延伸,一个计
数器记下该方向上的两头的连续同色棋子数。等到四个方向都探索完毕,如果四个计数器
中有一个计数器达到了 5,那么即可判断出已经有五子连珠了,此局结束。
问题(3)棋型知识库主要包括各种既定的棋盘形式,有如下几种:
活四 :有两个连五点(即有两个点可以形成五),图中白点即为连五点。当活四出现的时
候,整个局势已经无法阻止连五了,活四的归属方一定能取得胜利;
冲四 :有一个连五点,如下面三图,均为冲四棋型。图中白点为连五点。 相对比活四来
说,冲四的威胁性就小了很多,因为这个时候,只要跟着防守在那个唯一的连五点上,冲
四就没法形成连五。
活三 :可以形成活四的三,如下图,代表两种最基本的活三棋型。图中白点为活四点。活
三棋型是进攻中最常见的一种,因为活三之后,如果对方不以理会,将可以下一手将活三变
成活四,而活四是无法防守的。所以,面对活三的时候,需要非常谨慎对待。在没有更好的
进攻手段的情况下,必须对其进行防守,以防止其形成可怕的活四棋型。
眠三:只能够形成冲四的三,如下各图,分别代表最基础的六种眠三形状。图中白点代表冲
四点。眠三的棋型与活三的棋型相比,危险系数下降不少,因为眠三棋型即使不去防守,下
一手它也只能形成冲四,而对于单纯的冲四棋型,是可以很简单的防守住的。
南京中医药大学
9
活二 :能够形成活三的二,如下图,是三种基本的活二棋型。图中白点为活三点。
眠二 :能够形成眠三的二。图中四个为最基本的眠二棋型,细心且喜欢思考的同学会根据
眠三介绍中的找到与下列四个基本眠二棋型都不一样的眠二。图中白点为眠三点。
对于上述的棋型,我们主要考虑的是活四、冲四、活三、眠三这几种主要的进攻棋型的防
守与构成,整体棋型遵从以下原则:优先考虑数目,同等数目的情况下考虑是活是眠。评
分表算法的设计整体偏向于防守。
对于问题(4),当下棋型的评估分析,算法严格遵从以下流程:
当人类方落下一子,算法启动,扫描全局,得到人类棋子的集合和电脑棋子的集合。全局扫
描之后,对当前局势进行排序、计算。对每个集合的每个空白点位置打分,打分依据是根据
这个点周围四个方向上的同色连续棋子的数量。按照这些最后得到的评分,得出最大值。得
到人类方和电脑方的两个最大值之后,进行比较,如果人类方局势较好(分数较高),则算
法将下一次落子位置设置为人类方得分最高的点,尽力降低人类方的下一步得分;如果电脑
方的分数较高,那么则直接在使得分数最高的点落子即可。
3.3 游戏包设计
五子棋游戏属于棋类游戏,因此可以定义一个 chess 包来包含棋盘的所有规格及整体模板。
南京中医药大学
10
3.4 界面棋盘设计
在对棋盘界面设计方面要考虑简洁友好,符合游戏者需求。棋子的设计方面系统中设
置了两种棋子颜色,white 或者 black, 游戏者可自行选择。棋子怎样画出来,怎样使棋子
按我们所想的方式来绘制出来是设计的主要难题。运行时要求当每次点击鼠标的时候就在
点击鼠标的地方画一个棋子,所以得定义一个棋子的类使点击鼠标时系统把棋子绘制出
来。这样主界面里的棋子就确定了,而且也确定了几个所需要的类。可以先定义好这些类
了。
有了以上的准备就可以把棋盘绘制出来了,下棋时每次在适当位置点击鼠标的时候就
在所点击的位置上画出你这个角色的颜色,然后计算机会自动的下棋,计算机自动下棋要
有一个控制变量来控制能不能下棋。人可以随意的下子,可是计算机就要计算在哪个位置
下子了。这里由计算机下子的算法来确定,人人对战的话就不象单机游戏一样,要计算机
来判断人下子之后计算机下那一个地方了,人人对战只要在双方下子的时候判断赢棋情
况,当然还要同步的控制两个人下棋的顺序,这样的话就要用到线程了,各自都继承或实
现线程类或接口,以便各自能随时单独控制接发消息。
3.5 算法设计
对于五子棋游戏,无论人机对战,还是双人对战,都需要判断棋盘上是否存在五子
连珠情况,这既是游戏名字的由来,也是游戏结束的标志。判断五子连珠的原理是从横,
竖,左斜线,右斜线 4 条线上判断是否存在 5 个相连的同类棋子。
对战一方落子后,在该处向 8 个方向检测连续的同类棋子,如果检测到直线方向上
存在 5 个连续的同类棋子(包含本位置棋子),则判断为“连五”并结束检测循环。基于
检测结果,可以判断游戏是否结束,并根据获胜方的落子代码判断获胜方是谁。
由于不考虑禁手问题,在实现“连五”过程中,我们可以考虑完成“双四”,“四三”,
“双三”,“冲四”,“活三”,“活四”来实现目的。
活四:有两个点能形成“连五”的四就是活四;
冲四:只有一个点能形成“连五”的四叫做“冲四”,或者叫做“单四”;
活三:己方在落一子就能形成“活四”的三叫做“活三”。“活三”分为“连活三”和
“跳活三”。连活三:在棋盘某一条阳线或阴线上有同色三子相连,且在此三子两端延长
线上有一端至少有一个,另一端至少有两个无子的交叉点与此三子紧密相连。跳活三:中
间仅间隔一个无子交叉点的连三,但两端延长线均至少有一个无子的交叉点与此三子相
南京中医药大学
11
连。
双三:由于黑方走一着在无子交叉点上同时形成二个或二个以上黑方 " 活 " 的局面。
双四:由于黑方走一着在无子交叉点上同时形成二个或二个以上黑方 " 四 " 的局面。
四三:指某一方同时具备两个先手,其中一个是 " 四 " ,一个是 " 活三 " 。
在实现上面这些高级算法的时候,我们需要一个基础,就是对制定位置周围情况进行检
测。在棋盘上面,棋子存在 8 个移动方向,检测时需要对每个方向进行检测。为了简单直
观,这里将每步棋子的移动生成一个新的棋子。
四、游戏实现
4.1 ChessFrame 主要功能实现
类 ChessFrame 主要功能是创建五子棋游戏主窗体和菜单,主要代码如下:
class ChessFrame extends JFrame implements ActionListener {
private String[] strsize={“20x15”,“30x20”,“40x30”};
private String[] strmode={“人机对弈”,“人人对弈”};
public static boolean iscomputer=true,checkcomputer=true;
private int width,height;
private ChessModel cm;
private MainPanel mp;
4.2 游戏主窗体实现
构造五子棋游戏的主窗体,主要代码如下:
public ChessFrame() {
this.setTitle(“五子棋游戏”);
cm=new ChessModel(1);
mp=new MainPanel(cm);
Container con=this.getContentPane();
con.add(mp,“Center”);
this.setResizable(false);
this.addWindowListener(new ChessWindowEvent());
MapSize(20,15);
南京中医药大学
12
JMenuBar mbar = new JMenuBar();
this.setJMenuBar(mbar);
JMenu gameMenu = new JMenu(“游戏”);
mbar.add(makeMenu(gameMenu, new Object[] {
“开局”, “棋盘”,“模式”, null, “退出”
}, this));
JMenu lookMenu =new JMenu(“视图”);
mbar.add(makeMenu(lookMenu,new Object[] {
“Metal”,“Motif”,“Windows”
},this));
JMenu helpMenu = new JMenu(“帮助”);
mbar.add(makeMenu(helpMenu, new Object[] {
“关于”
}, this));
}
4.3 主菜单实现
构造五子棋游戏的主菜单,代码如下:
public JMenu makeMenu(Object parent, Object items[], Object target){
JMenu m = null;
if(parent instanceof JMenu)
m = (JMenu)parent;
else if(parent instanceof String)
m = new JMenu((String)parent);
else
return null;
for(int i = 0; i < items.length; i++)
if(items[i] == null)
m.addSeparator();
else if(items[i] == “棋盘”){
JMenu jm = new JMenu(“棋盘”);
ButtonGroup group=new ButtonGroup();
JRadioButtonMenuItem rmenu;
南京中医药大学
13
for (int j=0;j
if (j0)
rmenu.setSelected(true);
jm.add(rmenu);
group.add(rmenu);
}
m.add(jm);
}else if(items[i] == “模式”){
JMenu jm = new JMenu(“模式”);
ButtonGroup group=new ButtonGroup();
JRadioButtonMenuItem rmenu;
for (int h=0;h
if(h
rmenu.setSelected(true);
jm.add(rmenu);
group.add(rmenu);
}
m.add(jm);
}else
m.add(makeMenuItem(items[i], target));
return m;
}
4.4 具体实现步骤与关键代码
4.4.1 首先创建一个 JFrame 窗体, 取名 ChessJFrame.java。
4.4.2 创建下棋面板 为绘制棋盘做准备, 创建一个 JPanel 面板,
取名为 Panel.java,
代码如下: public Panel() { URL white_url = getClass ().getResource ( 白 棋图片路径);URL
南京中医药大学
14
black_url = getClass().getResource(黑棋 图片路径); whiteimg = new ImageIcon (white_url).
getImage(); // 初始化白旗图片 blackimg = new ImageIcon(black_url).getIm 鄄 age(); // 初
始化黑旗图片 size = new Dimension(getWidth(), getHeight()); // 定 义 组 件 宽 高
setPreferredSize(size); // 设 置 此 组 件 的 大 小 initComponents(); // 面 板 初 始 化 }
initComponents() 函数的内容请读者自行完善, 其 中需要包含鼠标监听事件, 以方便实
现落子。
4.4.3 绘制棋盘
利用 drawLine() 函数在已有的下棋面板上绘制棋盘,代码如下:
g.drawLine (棋盘左边界, 棋盘上边界 + 棋盘高度, 棋盘右边界, 棋盘上边界 + 棋盘高度);
/*drawLine(int x1, int y1, int x2, int y2) x1,y1 为起点的坐标 x2,y2 为终点的坐标 /
// 画每条横线
g.drawLine (棋盘左边界 + 棋盘宽度, 棋盘上边界, 棋盘左边界 + 棋盘宽度, 棋盘下边界);
// 画每条竖线 g 为 Graphics2D 类的变量。
到此为止, 下棋面板的构造基本完成, 接下来就是如何实现在下棋面板上落子的功能:
获取鼠标点击事件 此处与前文提到过鼠标监听事件相对应,用来确认鼠标点击下棋面板是
否发生,代码如下:
addMouse(new java.awt.event.MouseAdapter() // 添加鼠标点击事件
{
public void mouseClicked (java.awt.event. MouseEvent evt) {
// 鼠标点击触发方法
ormMouse(evt);
// 运行自定义的事件
} });
4.4.5 下棋功能的实现
//根据坐标计算出棋盘方格棋子的信息(如白子还是黑子)
//然后调用 draw 方法在棋盘上画出相应的棋子
public void paintComponent(Graphics g){
super.paintComponent(g);
for(int j = 0; j <= height; j++){
for(int i = 0; i <= width; i++){
int v = cm.getarrMapShow()[i][j];
draw(g, i, j, v);
}
} }
//根据提供的棋子信息(颜色、坐标)画棋子
public void draw(Graphics g,int i, int j, int v){
int x = 20 * i+20;
int y = 20 * j+20;
南京中医药大学
15
//画棋盘
if(i!=width && j!=height){
g.setColor(Color.white);
g.drawRect(x,y,20,20);
}
//画黑色棋子
if(v == 1 ){
g.setColor(Color.gray);
g.drawOval(x-8,y-8,16,16);
g.setColor(Color.black);
g.fillOval(x-8,y-8,16,16);
}
//画白色棋子
if(v == 2 ){
g.setColor(Color.gray);
g.drawOval(x-8,y-8,16,16);
g.setColor(Color.white);
g.fillOval(x-8,y-8,16,16);
}
if(v ==3){
g.setColor(Color.cyan);
g.drawOval(x-8,y-8,16,16);}
}
//响应鼠标的点击事件,根据鼠标的点击来下棋,
//根据下棋判断胜负等
public void mousePressed(MouseEvent evt){
int x = (evt.getX()-10) / 20;
int y = (evt.getY()-10) / 20;
System.out.println(x+" “+y);
if (evt.getModifiers()==MouseEvent.BUTTON1_MASK){
cm.play(x,y);
System.out.println(cm.getisOdd()+” "+cm.getarrMapShow()[x][y]);
repaint();
if(cm.judgeSuccess(x,y,cm.getisOdd())){
cm.showSuccess(this);
evt.consume();
ChessFrame.iscomputer=false;
}
//响应鼠标的拖动事件
public void mouseMoved(MouseEvent moveevt){
int x = (moveevt.getX()-10) / 20;
int y = (moveevt.getY()-10) / 20;
cm.readyplay(x,y);
repaint();
南京中医药大学
16
}}
class ChessWindowEvent extends WindowAdapter{
public void windowClosing(WindowEvent e){
System.exit(0);
}
ChessWindowEvent()
{} }
//计算机走棋
/
*说明:用穷举法判断每一个坐标点的四个方向的的最大棋子数,
*最后得出棋子数最大值的坐标,下子
**/
public void computerDo(int width,int height){
int max_black,max_white,max_temp,max=0;
setisOdd(true);
System.out.println(“计算机走棋 …”);
for(int i = 0; i <= width; i++){
for(int j = 0; j <= height; j++){
if(!chessExist(i,j)){//算法判断是否下子
max_white=checkMax(i,j,2);//判断白子的最大值
max_black=checkMax(i,j,1);//判断黑子的最大值
max_temp=Math.max(max_white,max_black);if(max_temp>max){
max=max_temp;
this.x=i;
this.y=j; } } } }
setX(this.x);
setY(this.y);
this.arrMapShow[this.x][this.y]=2;
}
//记录电脑下子后的横向坐标
public void setX(int x){
this.x=x; }
//记录电脑下子后的纵向坐标
public void setY(int y){
this.y=y; }
南京中医药大学
17
//获取电脑下子的横向坐标
public int getX(){
return this.x; }
//获取电脑下子的纵向坐标
public int getY(){
return this.y; }
//计算棋盘上某一方格上八个方向棋子的最大值,
//这八个方向分别是:左、右、上、下、左上、左下、右上、右下
public int checkMax(int x, int y,int black_or_white){
int num=0,max_num,max_temp=0;
int x_temp=x,y_temp=y;
int x_temp1=x_temp,y_temp1=y_temp;
//judge right
for(int i=1;i<5;i++){
x_temp1+=1;
if(x_temp1>this.width)
break;
if(this.arrMapShow[x_temp1][y_temp1]==black_or_white)
num++;
else
break; }
//judge left
x_temp1=x_temp;
for(int i=1;i<5;i++){
x_temp1-=1;
if(x_temp1<0)
break;
if(this.arrMapShow[x_temp1][y_temp1]==black_or_white)
num++;
else
break; }
if(num<5)
max_temp=num;
//judge up
x_temp1=x_temp;
y_temp1=y_temp;
num=0;
for(int i=1;i<5;i++){
y_temp1-=1;
if(y_temp1<0)
南京中医药大学
18
break;
if(this.arrMapShow[x_temp1][y_temp1]==black_or_white)
num++;
else
break; }
//judge down
y_temp1=y_temp;
for(int i=1;i<5;i++){
y_temp1+=1;
if(y_temp1>this.height)
break;
if(this.arrMapShow[x_temp1][y_temp1]==black_or_white)
num++;
else
break; }
if(num>max_temp&&num<5)max_temp=num;
//judge left_up
x_temp1=x_temp;
y_temp1=y_temp;
num=0;
for(int i=1;i<5;i++){
x_temp1-=1;
y_temp1-=1;
if(y_temp1<0 || x_temp1<0)
break;
if(this.arrMapShow[x_temp1][y_temp1]==black_or_white)
num++;
else
break; }
//judge right_down
x_temp1=x_temp;
y_temp1=y_temp;
for(int i=1;i<5;i++){
x_temp1+=1;
y_temp1+=1;
if(y_temp1>this.height || x_temp1>this.width)
break;
if(this.arrMapShow[x_temp1][y_temp1]==black_or_white)
num++;
else
break;
南京中医药大学
19
}
if(num>max_temp&&num<5)
max_temp=num;
//judge right_up
x_temp1=x_temp;
y_temp1=y_temp;
num=0;
for(int i=1;i<5;i++){
x_temp1+=1;
y_temp1-=1;
if(y_temp1<0 || x_temp1>this.width)
break;
if(this.arrMapShow[x_temp1][y_temp1]==black_or_white)
num++;
else break; }
//judge left_down
x_temp1=x_temp;
y_temp1=y_temp;
for(int i=1;i<5;i++){
x_temp1-=1;
y_temp1+=1;
if(y_temp1>this.height || x_temp1<0)
break;
if(this.arrMapShow[x_temp1][y_temp1]==black_or_white)
num++;
else
break; }
if(num>max_temp&&num<5)
max_temp=num;
max_num=max_temp;
return max_num; }
4.4.6 胜负的判断
//判断胜负
public boolean judgeSuccess(int x,int y,boolean isodd){
int num=1;
int arrvalue;
int x_temp=x,y_temp=y;
if(isodd)
南京中医药大学
20
arrvalue=2;
else
arrvalue=1;
int x_temp1=x_temp,y_temp1=y_temp;
//判断右边
for(int i=1;i<6;i++){
x_temp1+=1;
if(x_temp1>this.width)
break;
if(this.arrMapShow[x_temp1][y_temp1]==arrvalue)
num++;
else
break; }
//判断左边
x_temp1=x_temp;
for(int i=1;i<6;i++){x_temp1-=1;
if(x_temp1<0)
break;
if(this.arrMapShow[x_temp1][y_temp1]arrvalue)
num++;
else
break; }
if(num5)
return true;
//判断上方
x_temp1=x_temp;
y_temp1=y_temp;
num=1;
for(int i=1;i<6;i++){
y_temp1-=1;
if(y_temp1<0)
break;
if(this.arrMapShow[x_temp1][y_temp1]==arrvalue)
num++;
else
break; }
//判断下方
y_temp1=y_temp;
for(int i=1;i<6;i++){
y_temp1+=1;
if(y_temp1>this.height)
南京中医药大学
21
break;
if(this.arrMapShow[x_temp1][y_temp1]arrvalue)
num++;
else
break; }
if(num5)
return true;
//判断左上
x_temp1=x_temp;
y_temp1=y_temp;
num=1;
for(int i=1;i<6;i++){
x_temp1-=1;y_temp1-=1;
if(y_temp1<0 || x_temp1<0)
break;
if(this.arrMapShow[x_temp1][y_temp1]==arrvalue)
num++;
else
break; }
//判断右下
x_temp1=x_temp;
y_temp1=y_temp;
for(int i=1;i<6;i++){
x_temp1+=1;
y_temp1+=1;
if(y_temp1>this.height || x_temp1>this.width)
break;
if(this.arrMapShow[x_temp1][y_temp1]arrvalue)
num++;
else
break; }
if(num5)
return true;
//判断右上
x_temp1=x_temp;
y_temp1=y_temp;
num=1;
for(int i=1;i<6;i++){
x_temp1+=1;
y_temp1-=1;
if(y_temp1<0 || x_temp1>this.width)
南京中医药大学
22
break;
if(this.arrMapShow[x_temp1][y_temp1]==arrvalue)
num++;
else
break; }
//判断左下
x_temp1=x_temp;
y_temp1=y_temp;
for(int i=1;i<6;i++){
x_temp1-=1;
y_temp1+=1;if(y_temp1>this.height || x_temp1<0)
break;
if(this.arrMapShow[x_temp1][y_temp1]arrvalue)
num++;
else
break; }
if(num5)
return true;
return false; }
4.4.7 显示获胜信息
//赢棋后的提示
public void showSuccess(JPanel jp){
JOptionPane.showMessageDialog(jp,“你赢了,好厉害!”,“win”,
JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
//输棋后的提示
public void showDefeat(JPanel jp){
JOptionPane.showMessageDialog(jp,“你输了,请重新开始!”,“lost”,
JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
} }五、游戏功能测试
南京中医药大学
23
游戏性能测试是测试游戏的当前实现能否满足早期阶段的需求分析,本文主要对各个按钮的
功能都依次进行测试 游戏功能测试用例表如表 1 所示。
表一:游戏功能测试样例表
测试项 输入 输出 测试结果
游戏主页面功能按
钮是否正常
点击功能按钮进行
测试
功能按钮有反馈 反馈正常
游戏进行中按钮是
否正常
在棋盘上下子 控制台显示棋的位
置,并且判断输赢结
果
反馈正常
游戏中重新开始按
钮,退出按钮是否正
常
点击功能按钮进行
测试
能重新开始游戏或
退出游戏
反馈正常
5.1.1 点击游戏按钮,出现开局,棋盘,模式和退出基本按钮
5.1.2 棋盘布局按钮,可以调整棋盘大小
南京中医药大学
24
5.1.3 模式按钮,可以选择是人人还是人机模式进行游戏
5.1.4 视图按钮可以调整界面的颜色,样式
南京中医药大学
25
南京中医药大学
26
5.2 人机模式
玩家持黑棋,电脑持白棋。玩家先手,电脑经过调用方法寻找适合
的位置进行落子。
5.2.1 若黑子先连成五子,则玩家胜利,输出对话框“你赢了,真厉
害”
5.2.2 若白子先连成五子,则电脑胜利,输出对话框“你输了,重新
开始游戏”
南京中医药大学
27
5.3 人人模式
两个玩家进行游戏,玩家 a 持黑棋,玩家 b 持白棋。玩家 a 先手,
玩家 b 经过思考寻找适合的位置进行落子。
5.3.1 若黑子先连成五子,则玩家 a 胜利,输出对话框“你赢了,真
厉害”
5.3.2 若白子先连成五子,则玩家 b 胜利,输出对话框“你输了,重
新开始游戏”
南京中医药大学
28
5.4 帮助按钮 5.5 点击退出,退出游戏
六、课程总结
6.1 设计体会
通过这次课程设计,我进一步加深对基础理论的理解,扩大专业知识面,对收集资
料、查阅文献、方案制定等实践方面得到了很好的锻练,促进对所学知识应用能力的提
高。同时我渐渐的复习了 Java 使用方法和编程语法,之后的编程过程也相对得心应手,基
本完成了预期计划的要求。
南京中医药大学
29
6.2 设计不足
因为近期时间较为紧迫,所以 Java 课程设计我们选择了较为简单的五子棋问题进行课
程设计。在本次课程设计中,我们的编码能力、调试能力、算法解读实现能力、函数优化
能力等各方面有了长足的进步。在本次的设计过程中也出现了几个问题,下面对这些问题
进行一个简单的描述:
(1) 对棋盘局势的判断力不够,因为只是简单的对当前的棋盘局势进行判断,基本等同
于一个粗通规则而且天赋不高的五子棋选手。如果对手很细心,而且熟练经营各种布局策
略,那么基本这个算法就会被钻研出习惯,从而被轻易针对,而且针对方案百试不爽;
(2) 判断棋局形式的时候对边界的评分算法跟中心区域的评分算法一致,无法有效提前
识别边界,降低边界空白点的权重;
(3) 用户图形界面需要改进,另外可以增设 PK 模式以及选色、选择棋盘大小功能等;
(4)由于将画棋盘的功能和菜单功能高度绑定,所以无法实现直接再来一盘的功能。
6.3 展望
后续可以尝试用博弈树算法尝试与当前算法进行比较。评分表算法牺牲了更高的精
度,以求迅速的得出最佳落子点;而博弈树可以通过提前落子进行全局预判进行更全方位
的对人类方的围追堵截。
另外,可以通过在课堂上学到的知识,比如 BFS、DFS、A*算法、决策树算法 等应用
于五子棋的智能决策中。
南京中医药大学
30
七.参考文献
[1]耿祥义.JAVA 大学实用教程.北京:电子工业出版社.2005.3:85-113
[2]朱战立,沈伟.Java 程序设计实用指南.北京:电子工业出版社,2005.1:48-135
[3] 唐大仕.Java 程序设计[M]. 北京:北方交通大学出版社:2007.05:56-92
[4]叶核亚. JAVA2 程序设计实用教程[M].北京:电子工业出版社;2008.4:64-98
[5]邢素萍. JAVA 办公自动化项目方案精解[M].北京:航空工业出版社, 2006.9:35-120
[5] 郑欢 . 基于 SOPC 的人机博弈系统设计与实现 [J]. 四川水 泥 , 2019(4):109-109.
[7] 光洋 . 爱恩斯坦棋计算机博弈系统的研究与实现 [D]. 安徽 大学 , 2016. [3] 王令宇 .
基于 SaaS 模式的即时通信平台的设计与实现 [D]. 北京邮电大学 , 2015.
[8] 毛丽民 , 朱培逸 , 卢振利 , 等 . 基于 LabVIEW 的五子棋博 弈算法的研究 [J]. 计算
机应用 , 2016.