您的当前位置:首页正文

五子棋课设

来源:化拓教育网


计算机网络课程设计报告

题 目: 学 院:专 业:学生姓名:学 号:指导教师: 网络五子棋对战

计算机科学与工程学院 软件工程

2012年 3月 9

目录

摘 要 ........................................................... 错误!未定义书签。 第一章 概述 ..................................................... 错误!未定义书签。

1.1 开发背景 ................................................................... 3 1.2 课题意义 ................................................... 错误!未定义书签。

第二章 五子棋程序的介绍 ....................................................... 3

2.1 用户需求分析 ............................................................... 3 2.2 五子棋程序概要设计 .......................................... 错误!未定义书签。

第三章 五子棋的详细设计 ....................................................... 4

3.1 界面的实现及鼠标事件的监听 ................................................. 5 3.2 按钮功能的实现 ............................................................. 6 3.3 棋子表示 ................................................................... 6 3.4 胜负判断……………………………………………………………………………………..12

第四章 五子棋软件测试 ....................................................... 14 总结 ............................................................... 错误!未定义书签。 参考文献 ......................................................................... 25

摘 要

随着经济的发展,社会竞争的激烈,现在社会进入了竞争的时代。上班族为了完成公司业务,每天超负荷的工作;学生为了不落后他人每天早起晚睡不断地学习,压力巨大。所以为了缓解大家的压力,使大家在工作、学习之余娱乐一下,活跃大脑,提高工作、学习效率,我本人设计了一个简易的五子棋游戏。

本系统将利用五子棋游戏作为研究对象,在Windows平台下,运用java语言设计的一个能够实现人机对战的简单游戏。该系统涉及到人工智能方面的知识,而计算机博弈是人工智能研究的一个重要分支,其中还包括几个重要的搜索算法。只有通过一定的研究,才能实现五子棋的人机对战功能。 关键词: 网络对战 ; 五子棋;

第一章 概述

1.1 开发背景

随着计算机技术和互联网的飞速发展,游戏软件是当今世界发展最迅速,最有影响力,最有潜力与活力的领域之一。电脑游戏的出现为人们提供了新的娱乐平台,丰富了人们的业余生活。因此与游戏有关的软件深受广大青少年的喜爱。随着近几年来软件技术的不断进步、不断发展,软件游戏的操作要求越来越简单

而五子棋游戏的诞生更是吸引着不同年龄段的人群,无论男女老少都可以玩,都喜欢玩,而当前微型计算机已经是在广大人群中流行着,用电脑来下五子棋更是一种时尚。现在网络上出现了各种各样的五子棋软件,有大师级的、新手级的等等。所有这些都满足了不同人群的需要,所以当前五子棋越来越被许多人所熟悉。目前的五子棋程序的发展也非常快,从最初的双人发展到人机,然后到现在的网络对战,已经受到越来越多人的喜爱和重视。

第二章 五子棋程序的介绍

2.1 用户需求分析

1.显示一个十五行十五列的五子棋棋盘。

2.用鼠标点击棋盘上的交叉点处,则会准确地在该位置显示出棋子。 3.玩家1为黑方先下棋,玩家2为白方。

4.可以自动判断游戏是否结束,是否黑方或者是白方已经胜利,并且跳出对话框来提示玩家。

5.在游戏棋盘上方会有一个游戏信息,这个游戏信息是用来提示当前是黑白双方的哪一方下子,玩家可以根据这个提示来下棋,而不会导致不清楚轮到哪一方下棋。

6.可以重新开始游戏,在下棋时如果玩家点击结束按钮,则给出提示“对方已经结束游戏!”,然后如果玩家点击开始按钮,则给出提示“对方请求与你开始游戏,是否同意” ,若点击同意,则可以开始下棋,游戏中,若点击断开,则提示“连接已断开,请重新连接主机和客服端”

通过上述用户需求,可以得出一个整体的设计方案,规定游戏的基本功能如下结构图

2.2五子棋程序概要设计

本五子棋游戏主要的有5大功能它们分别是:主机,客户端,开始,断开,结束。2.4图为软件功能结构图:

五子棋

游戏

主机

客户端 开始 结束 断开 图2.1软件功能结构图

流程图

玩家1胜利 玩家2胜利

YES

结束

断开OR结束 开始 菜单、显示棋盘 连接主机AND客户端 主机玩家先下棋 在双方棋盘显示棋子位置,玩家1为黑子,玩家2为白子 NO 对方下棋 YES 玩家1? 五子一线 NO 开始 YES NO 第三章 五子棋的详细设计

3.1 界面的实现及鼠标事件的监听

3.1.1 界面的生成

界面包括棋盘,消息提示窗,还有菜单

在创建完成一个基本窗口后,将棋盘加载进窗口界面,并加入菜单,就得到了一个简单的棋盘。

public static void main(String[] args) {

Gobang gobang = new Gobang(); gobang.setResizable(false);

Dimension s = Toolkit.getDefaultToolkit().getScreenSize(); //获

得屏幕对象,以便使窗体居中显示 gobang.setSize(450, 500);

gobang.setLocation((s.width - gobang.getWidth()) / 2, (s.height gobang.setVisible(true);

- gobang.getHeight()) / 2);

}

public Gobang() {

super(\"五子棋\");

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); menuEvent(); //添加各个菜单的事件监听器 menuInit(); //设置各个菜单的Enable属性

//添加棋子面板

JPanel p1 = new JPanel(new BorderLayout()); p1.add(mp, BorderLayout.CENTER);

JPanel p2 = new JPanel(new GridLayout(15, 15)); for (int i = 0; i < 15; i++) {

for (int j = 0; j < 15; j++) {

p[i][j] = new ToePanel(i, j, this); p2.add(p[i][j]);

server.addActionListener(p[i][j].ms);

client.addActionListener(p[i][j].ms); //点\"客户端\"菜单时清空所有的棋子

start.addActionListener(p[i][j].ms); addActionListener(p[i][j].ms); }

setBackground(Color.BLACK);

message.setFont(new Font(\"宋体\", Font.BOLD, 15));

message.setForeground(Color.BLACK); //初始化时设置消息标签的颜色为 add(message);

showMessageTimer = new Timer(1, al); //初始化时间对象

}

}

Container conPane = this.getContentPane(); conPane.setLayout(new BorderLayout()); conPane.add(p1, BorderLayout.NORTH); conPane.add(p2, BorderLayout.CENTER);

MessagePanel() {

setMessage(\"五子棋\"); }

图3.2运行结果图

3.1.2鼠标事件的监听

MouseEvent是公有类。这个类封装了与鼠标事件有关的信息,包括鼠标单击和处理鼠标事件。首先是添加事件监听器this.addMouseListener(this)(this是java中的一个特殊的对象引用。每个对象对其自身的引用称为this引用。this引用被隐式地引用一个对象的实例变量和方法),鼠标事件由鼠标事件源产生,并且由实现了MouseListener接口的处理对象。发送MouseEvent类的实例给鼠标监视器事件以帮助处理鼠标事件首先判断是否该玩家落子和胜负已分及游戏是否开始,如确实轮到玩家落子,则首先得到鼠标单击坐标,然后转换得到距离最近的落子点,并在这个落子点上绘制相应颜色的棋子,然后将玩家落子的坐标信息发送给对方,并提醒对方落子。代码片段如下:

单击鼠标时执行下棋的方法 addMouseListener(new MouseAdapter() {

public void mousePressed(MouseEvent e) {

//能够下棋的条件:1.当前格子为空 2.该自己下 3.对方没有结束游戏 4.单击的是鼠标左键 if (f == 0 && main.t && main.t2 && e.getButton() == 1) {

});

}

if (main.x != -1)

main.p[main.x][main.y].stopTiShi(); /

xiaQi(main.c); //在鼠标点击处下棋

main.mp.setMessage(\"等待对方落子...\");

main.t = false; //下子后必须等对方下子后才能再下 main.out.println(row); main.out.println(col);

main.checkWin(row, col, main.c);

}

3.2 按钮功能的实现

Java中的鼠标和键盘事件,使用MouseListener接口处理鼠标事件.鼠标事件有5种:按下鼠标键,释放鼠标键,点击鼠标键,鼠标进入和鼠标退出。鼠标事件类型是MouseEvent,主要方法有:

getX(),getY() 获取鼠标位置 getSource() 获取鼠标发生的事件源

事件源获得监视器的方法是addMouseListener()

添加各个菜单的事件监听器 private void menuEvent() {

game.addSeparator(); game.add(server); game.add(client); game.add(start); game.add(stop); game.add(cencal); mb.add(game);

this.setJMenuBar(mb);

\"主机\"菜单

server.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) { }

server.setEnabled(false); client.setEnabled(false); cencal.setEnabled(true); try {

InetAddress ip = InetAddress.getLocalHost(); String address = ip.getHostName(); //获得本机机器名

//

mp.setMessage(address + \"正等待客户端连接...\"); } catch (Exception ee) { }

wc = new WaitClient(); wc.start();

});

\"客户端\"菜单

client.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {

连主机 try {

mp.setMessage(\"五子棋\");

String ip = JOptionPane.showInputDialog(Gobang.this,

//

//

\"请输入主机IP地址或主机名称:\",\"127.0.0.1\"); if (ip != null) {

Socket s = new Socket(ip, 10000);

out = new PrintWriter(s.getOutputStream(), true); in = new BufferedReader(new c_in = new Client_in(); c_in.start(); //开始监视对方状态 mp.setMessage(\"等待对方落子...\"); 连接成功后再设置这些属性 t = false; //客户端后下 t2 = true; c = -1;

InputStreamReader(s.getInputStream()));

//

}

x = -1; y = -1;

server.setEnabled(false); client.setEnabled(false); cencal.setEnabled(true); start.setEnabled(false); stop.setEnabled(true);

} catch (IOException ie) {

mp.setMessage(\"五子棋\");

JOptionPane.showMessageDialog(Gobang.this, \"加入游戏

JOptionPane.ERROR_MESSAGE);

失败!\", \"五子棋\",

}

}

});

\"断开\"菜单

cencal.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {

if (c_in != null) { }

if (wc != null) { } try {

if (s != null)

s.close(); ss.close(); out.close(); in.close(); if (ss != null) if (out != null) if (in != null) wc.stop(); //中断线程 wc = null;

c_in.stop(); //中断线程 c_in = null;

//

} catch (IOException ie) {

System.out.println(\"断开时有错\"); }

mp.setMessage(\"五子棋\"); gameOver();

menuInit(); //将各菜单的Enable属性设为初始值 }

});

//

\"开始\"菜单

start.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) { }

if (!t2) {

mp.setMessage(\"等待对方开始...\"); } else {

mp.setMessage(\"可以落子了!\"); }

myRun();

});

\"结束\"菜单

stop.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) { }

mp.setMessage(\"五子棋\"); gameOver();

传-1,表示我单方面结束游戏 out.println(-1); out.println(-1);

//

//

}

});

3.3 棋子表示

3.3.1五子棋的棋子属性表示

本五子棋中共有二种棋子--黑子和白子.所以用最简单的方法来表示它们,数字1表示黑子、数字-1表示白子,而数字0表示该位置没有棋子。在本程序中我用了一个简单数组,对棋子进行了表示。p[i][j]==1表示黑子、p[i][j]==-1表示白子和p[i][j]==0表示没棋子。

3.3.2绘制棋盘及棋子

在整个窗体中绘制15*15条横竖相间的直线,这种方法只需要一个循环嵌套就能完成,将窗体分成15*15个等分的面板区域,每个面板根据自己所在的行列绘制网格线,这样的好处是将来放置棋子是,点到哪一个面板,面板就绘制一个棋子的圆,不需要使用位置计算方法了,同时每个面板都有自己的行列号,这样很方便的找到后台的14*14的二维数组中对应的数组元素来查找无落子0黑子1白字-1的方法

//绘制玩家棋子

public void paintComponent(Graphics g) {

super.paintComponent(g);//刷新

this.setBackground(Color.green);//设置背景色 画网格线

if (row > 0)

g.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight() /

//

2);

if (row < 14)

g.drawLine(getWidth() / 2, getHeight() / 2, getWidth() / 2,

getHeight());

if (col > 0)

g.drawLine(0, getHeight() / 2, getWidth() / 2, getHeight() /

2);

if (col < 14)

g.drawLine(getWidth() / 2, getHeight() / 2, getWidth(),

getHeight() / 2);

if (row == 3 && col == 3)

g.fillRect(getWidth() / 2 - 2, getHeight() / 2 - 2, 5, 5); g.fillRect(getWidth() / 2 - 2, getHeight() / 2 - 2, 5, 5); g.fillRect(getWidth() / 2 - 2, getHeight() / 2 - 2, 5, 5); g.fillRect(getWidth() / 2 - 2, getHeight() / 2 - 2, 5, 5); g.fillRect(getWidth() / 2 - 2, getHeight() / 2 - 2, 5, 5); g.fillRect(getWidth() / 2 - 2, getHeight() / 2 - 2, 5, 5); g.fillRect(getWidth() / 2 - 2, getHeight() / 2 - 2, 5, 5); g.fillRect(getWidth() / 2 - 2, getHeight() / 2 - 2, 5, 5); g.fillRect(getWidth() / 2 - 2, getHeight() / 2 - 2, 5, 5); if (row == 3 && col == 7) if (row == 3 && col == 11) if (row == 7 && col == 3) if (row == 7 && col == 7) if (row == 7 && col == 11) if (row == 11 && col == 3) if (row == 11 && col == 7) if (row == 11 && col == 11)

设置棋子的直径

w = (getWidth() < getHeight()) ? getWidth() : getHeight(); w = (int) (w * 0.8); switch (flag) { case 1:

g.setColor(Color.black);

g.fillOval((getWidth() - w) / 2, (getHeight() - w) / 2, w, w); break;

g.setColor(Color.white);

g.fillOval((getWidth() - w) / 2, (getHeight() - w) / 2, w, w); break; }

//

case -1:

如下图

3.4 游戏胜负的判断

判断胜负是这个游戏的核心,一个游戏最重要的部分,如果连判断胜负都不可以实现的话,那么这个游戏程序是没有用的。依据五子棋的基本规则,判断某一方向上是否有同一颜色的棋子连成五个或五个以上的,如果有,那么游戏就结束了,并判先连成五子的一方获得了胜利。

主要是从4个方向来判断哪一方先胜,分别是水平方向,垂直方向,左下角到右上角,右下角到左上角,分别写四个函数,当下一个棋子之后,对以这个棋子为中心的四个方向分别判断有没达到5个相同的棋子在一条直线上,如果有则该方为胜。代码实现如下:

函数功能:对指定的下棋点进行胜负判断

boolean checkWin(int row, int col, int who) {

if (p[row][col].f == 0)

return false;

//如果有任意一个方向的连子数有5颗以上,那么就分出了胜负,否则再检查是否是和棋

if (sumRow(row, col) >= 5 || sumCol(row, col) >= 5 || sumLr(row, col) >= 5

|| sumRl(row, col) >= 5) { 胜负已分,但要判断是胜还是负

String str = c == who ? \"恭喜,你赢了!\" : \"哈哈,你输了!\"; mp.setMessage(str);

JOptionPane.showMessageDialog(Gobang.this, gameOver(); return true;

for (int i = 0; i < 15; i++) { } 和棋

for (int j = 0; j < 15; j++) { }

if (p[i][j].f == 0)

return false; //尚未分出胜负

str,

\"五

\

//

JOptionPane.INFORMATION_MESSAGE);

} else {

//

}

}

String str = \"将遇良才,棋逢对手\"; mp.setMessage(str);

JOptionPane.showMessageDialog(Gobang.this, gameOver(); return true;

str,

\"五

\

JOptionPane.INFORMATION_MESSAGE);

函数功能:返回水平方向上的连子数 private int sumRow(int row, int col) { }

private int sumCol(int row, int col) {

int l = row, r = row;

for (int h = row - 1; h >= 0; h--) { }

for (int h = row + 1; h < 15; h++) {

int l = col, r = col;

for (int h = col - 1; h >= 0; h--) { }

for (int h = col + 1; h < 15; h++) { }

return r - l + 1;

if (p[row][h].f == p[row][col].f) { }

r = h; break; } else {

if (p[row][h].f == p[row][col].f) { }

l = h; break; } else {

函数功能:返回垂直方向上的连子数

if (p[h][col].f == p[row][col].f) { }

l = h; break; } else {

}

}

if (p[h][col].f == p[row][col].f) { }

r = h; break; } else {

return r - l + 1;

函数功能:返回左上角到右下角方向上的连子数 private int sumLr(int row, int col) { }

private int sumRl(int row, int col) {

int l = row, r = row;

for (int h = row - 1, h2 = col + 1; h >= 0; h--, h2++) {

if (h2 >= 15)

break;

if (p[h][h2].f == p[row][col].f) {

int l = row, r = row;

for (int h = row - 1, h2 = col - 1; h >= 0; h--, h2--) { }

for (int h = row + 1, h2 = col + 1; h < 15; h++, h2++) { }

return r - l + 1;

if (h2 >= 15) }

break; r = h; break;

if (p[h][h2].f == p[row][col].f) { } else { if (h2 < 0) }

break; l = h; break;

if (p[h][h2].f == p[row][col].f) { } else {

函数功能:返回右上角到左下角方向上的连子数

}

}

}

}

l = h; break;

} else {

for (int h = row + 1, h2 = col - 1; h < 15; h++, h2--) { }

return r - l + 1;

if (h2 < 0) }

break; r = h; break;

if (p[h][h2].f == p[row][col].f) { } else {

第四章 软件测试

任何一个软件在投放市场使用之前,都要进行大量的测试。在测试阶段测试人员努力设计出一系列测试方案,目的却是为了“破坏”已经建造好的软件系统—竭力证明程序中的错误,不能按照预定要求正确工作。这阶段的根本目的是尽可能多地发现并排除软件中隐藏的错误,最终把一个高质量的软件系统交给用户使用。本章主要是对该系统的功能进行了详细的测试,并对程序内部的数据进行了测试和修改。

本系统软件界面有以下几个功能:主机,客户端,开始,断开,结束 点击“主机”按钮,如图一,点击客户端,如图二

图一 图二 点击对方点击“结束”按钮,

当对方点击 开始时

当对方在游戏中点击 结束时

当游戏结束,有一方获胜时

经过对界面各个功能按钮进行了测试,能够正常使用,操作简单易懂非常适合初学者娱乐、学习用。

总结

通过编写这个程序,我体会最为深刻的一点是系统架构和设计模式的重要性。即使是对于一个并不大的程序,代码的组织都是非常重要的,因为这关系到日后的维护以及扩展。这个游戏之中,有关网络Socket编程的知识都可以直接从无所不包的Internet上获取,但是对于系统的架构,却完全是自己的事情,几千上万行的代码需要通过合适的方法组织起来,使程序员编写代码更加有条理,更加符合软件工程的标准,这才是最重要的。对于代码的组织(也就是软件的架构)才是真正软件工业的核心部分,因为软件事实上是直接和经济挂钩的,因此我们必须在编写代码之前选择一种最为合适的方法来组织这些代码

由于时间比较紧张,有一些功能实现的不理想,虽然还不那么完美,但我心里还是充满成就感.为了完成这个项目,我查阅了不少资料。由于我对java方面的知识了解的不多,所以也花很多的时间在学习,可以说是边学边用了。但我还是坚持下来并克服了种种困难,取得了理想的成果。通过这个课设,让我对网络套接字技术了解的更深入与透彻,对JAVA的图形用户界面设计,多线程程序设计,输入输出流等等知识的运用得到进一步提高,通过棋盘的设计,让我学会了图形的布局,对控件的运用理解更深入,其中最难得部分是各个功能的划分和线程之间的关系以及类之间的通讯问题。感谢老师的辛勤指导,还有我的朋友在课设过程中给了我学习上的巨大帮助,在此我表示我最衷心的感谢!

参考文献

[1] 朱福喜. Java语言基础教程[M]. 北京:清华大学出版社,2008年4月 [4] 贾蓉生等. Java 典型应用彻查1000例[M]. 北京:科学出版社,2009年7月 [5] 聂庆亮. Java应用开发指南[M]. 北京:清华大学出版社,2010年1月

附录:一些关键代码: //

等待客户端连接的线程

//WaitClient类

public void run() {

try {

ss = new ServerSocket(10000); s = ss.accept();

out = new PrintWriter(s.getOutputStream(), true);

in = new BufferedReader(new InputStreamReader(s.getInputStream())); c_in = new Client_in(); //建立显示对方棋子的进程 c_in.start();

mp.setMessage(\"请你先下!\"); //连接成功后再设置这些属性

class WaitClient extends Thread {

} //

}

}

t = true; //主机先下

t2 = true; //对方已经准备好,这样才能下棋 c = 1; //主机的棋子颜色为黑色1

x = -1; //刚开始时对方还未下棋,所以置为-1 y = -1;

stop.setEnabled(true); mp.setMessage(\"五子棋\"); menuInit();

JOptionPane.showMessageDialog(Gobang.this, \"创建主机失败!\五子棋\

JOptionPane.ERROR_MESSAGE);

} catch (IOException ie) {

此进程负责用socket的输入流(in)中的信息来显示对方下棋位置 public void run() {

try {

while (true) {

int h = Integer.parseInt(in.readLine()); int l = Integer.parseInt(in.readLine()); if (h == -1) {

if (stop.isEnabled()) { }

gameOver(); t2 = true; if (!t) {

int k = JOptionPane.showConfirmDialog(Gobang.this, \"对方请

\"五子棋\

mp.setMessage(\"五子棋\");

JOptionPane.showMessageDialog(Gobang.this, \"对方已经结

JOptionPane.INFORMATION_MESSAGE);

class Client_in extends Thread {

//收到-1表示对方结束了游戏,-2表示对方开始了游戏,否则收到的是对方落子的行号 //如果\"结束\"菜单可用,则说明正在游戏中,可以弹出消息框;否则只是对方取消了开始,可不

束了游戏!\五子棋\

} else if (h == -2) {

//如果自己还未准备好游戏(也就是还没点开始菜单),就显示对方请求游戏的消息框,否

求与你游戏,是否同意开始?\

JOptionPane.QUESTION_MESSAGE);

行刷新

// }

}

}

}

}

if (k == 0) { }

mp.setMessage(\"可以落子了!\");

mp.setMessage(\"可以落子了!\"); myRun();

notifyActionListeners(); //通知所有的格子刷新监听器进

} else {

} else { }

x = h; y = l;

p[h][l].xiaQi(-c); //画上对方的棋子

p[h][l].tiShi(); //开启提示对方落子位置的功能 t = true; //将这个变量设为true,这样才轮到自己下棋 mp.setMessage(\"该你下了!\"); checkWin(h, l, -c); //判断胜负

保存对方下棋的位置,因为自己下棋时要调用这个格子的停止提示stopTiShi()方法

} catch (Exception e) {

mp.setMessage(\"与对方断开了连接!\"); gameOver(); menuInit(); try { } s = null;

JOptionPane.showMessageDialog(Gobang.this, \"连接已断开!请重新建主机

JOptionPane.ERROR_MESSAGE); if (ss != null)

ss.close();

} catch (IOException ie) {

或客户端!\五子棋\

因篇幅问题不能全部显示,请点此查看更多更全内容