项目设计-----五子棋
一、团队成员
组长:郭瀚文 202203010057
组员:关乾春 202203010058 邓国岩 202203010059
二、主要内容
项目完整代码:https://gitee.com/memoryee/gobang
一个简易的五子棋游戏,能够实现离线和联网对战。
离线模式能够支持本地双人对战。
联网模式需要用户登录并等待服务器匹配对手
三、简介
1、设计目标
通过socket编程,GUI设计,mysql等技术的学习,来实现一个联网的多人五子棋小游戏
2、实现技术
socket编程,GUI设计,mysql
3、开发环境
java
4、功能特点
能够在本地实现双人对战
同时也能通过服务器联网实现异地对战
四、功能介绍
1、离线模式
(1)落子
通过二维数组存储棋子在棋盘上的位置,在绘制棋盘,实现落子的功能
代码如下:
//在Mouse类中,通过重写mosueclicked方法来获取鼠标点击位置与棋盘格子的关系
public void mouseClicked(MouseEvent e) {
int x = e.getX();// 鼠标点击处获取x、y坐标
int y = e.getY();
// 获取落子坐标,此处进行判断让获取的坐标位于棋盘线交点处
if ((x - x0) % size > size / 2) {
x1 = (x - x0) / size + 1;
}
else if ((x - x0) % size <= size / 2) {
x1 = (x - x0) / size;
}
if ((y - y0) % size > size / 2) {
y1 = (y - y0) / size + 1;
}
else if ((y - y0) % size <= size / 2) {
y1 = (y - y0) / size;
}
// System.out.println(y1 + " " + x1);
// System.out.println(chessArr[y1][x1]);
//判断本地游戏是否开始
if (start) {
// 判断棋子是否会越出棋盘界
if (0 <= x1 && x1 <= 14 && 0 <= y1 && y1 <= 14) {
// 判断只有空位置才能下棋
if (chessArr[y1][x1] == 0) {
if (count % 2 == 0) {
//static1.black.paintIcon(chessPanel, g, x1 * size - 25 + x0, y1 * size - 25 + y0);
chessArr[y1][x1] = 1;// 记录棋盘上每颗棋子的颜色,黑色记1,白色记-1
chesses[count++] = new Chess(x1, y1, 1);
}
else {
//static1.white.paintIcon(chessPanel, g, x1 * size - 25 + x0, y1 * size - 25 + y0);
chessArr[y1][x1] = -1;
chesses[count++] = new Chess(x1, y1, -1);
}
historyArea.refresh(y1, x1, chessArr[y1][x1]);
chessPanel.repaint();
}
}
else {
System.out.print("超出棋盘边界");
}
int winner = win.checkWin(x1, y1);//获得谁是赢家
if(winner != 0) {
winner(winner);
}
}
}
(2)悔棋
定义chess类来存储一个棋子的坐标及颜色,定义一个chess的一位数组,用于表示第几步的棋
子是什么颜色以及坐标是多少,悔棋的时候按倒序依次取出棋子然后重新绘制棋盘,从而实现
悔棋的效果
代码如下:
//Mouse类中的方法
public void regret() {
if(start && count >= 1) {
-- count;
int x = chesses[count].getX();
int y = chesses[count].getY();
chessArr[y][x] = 0;
historyArea.setText("");
for(int i = 0; i < count; i ++ ) {
x = chesses[i].getX();
y = chesses[i].getY();
int color = chesses[i].getColor();
historyArea.refresh(y, x, color);
}
chessPanel.repaint();
}
}
(3)复盘
原理同(2),按照顺序依次取出棋子,然后按顺序绘制在棋盘上。
为了实现复盘的效果,同时新建一个计时器类,设定固定的时间间隔来实现依次下棋的效果。
代码如下:
public void repeat() {
timer = new Timer();
timer.schedule(new TimerTask() {
int x, y, color, idx = 0;
@Override
public void run() {
if(idx < count) {
Chess thisChess = chesses[idx];
x = thisChess.getX();
y = thisChess.getY();
color = thisChess.getColor();
chessArr[y][x] = color;
historyArea.refresh(y, x, color);
chessPanel.repaint();
++ idx;
}
else {
timer.cancel();
}
}
}, 1000, 1000);
//复盘后要禁止下棋,不用清零count因为开始时count一定为0
start = false;
}
(4)获胜
当某一方下棋后,判断该棋子各个方向的同色棋子是否达到五个
每个方向单独计数
某个方向的同色棋子数达到五个,判定游戏结束,禁止下棋
public class Win {
private int[][] chessArr = new int[15][15];
private int count = 0;
public Win(int[][] chessArr) {
this.chessArr = chessArr;
}
//判断四个方向是否连成五个的判断函数
//水平
public int countchessX(int x1, int y1) {
count = 1;
for (int i = x1 + 1; i < chessArr.length; i++) {
if (chessArr[y1][x1] == chessArr[y1][i]) {
count++;
}
else {
break;
}
}
for (int i = x1 - 1; i >= 0; i--) {
if (chessArr[y1][x1] == chessArr[y1][i]) {
count++;
}
else {
break;
}
}
// System.out.println("X" + count);
return count;
}
//竖直
public int countchessY(int x1, int y1) {
count = 1;
for (int i = y1 + 1; i < chessArr.length; i++) {
if (chessArr[y1][x1] == chessArr[i][x1]) {
count++;
}
else {
break;
}
}
for (int i = y1 - 1; i >= 0; i--) {
if (chessArr[y1][x1] == chessArr[i][x1]) {
count++;
}
else {
break;
}
}
// System.out.println("Y" + count);
return count;
}
//y = x
public int countchessM(int x1, int y1) {
count = 1;
for (int i = x1 + 1, j = y1 + 1; i < chessArr.length && j < chessArr.length; i++, j++) {
if (chessArr[y1][x1] == chessArr[j][i]) {
count++;
}
else {
break;
}
}
for (int i = x1 - 1, j = y1 - 1; i >= 0 && j >= 0; i--, j--) {
if (chessArr[y1][x1] == chessArr[j][i]) {
count++;
}
else {
break;
}
}
// System.out.println("M" + count);
return count;
}
//y = -x
public int countchessN(int x1, int y1) {
count = 1;
for (int i = x1 + 1, j = y1 - 1; i < chessArr.length && j >= 0; i++, j--) {
if (chessArr[y1][x1] == chessArr[j][i]) {
count++;
}
else {
break;
}
}
for (int i = x1 - 1, j = y1 + 1; i >= 0 && j < chessArr.length; i--, j++) {
if (chessArr[y1][x1] == chessArr[j][i]) {
count++;
}
else {
break;
}
}
return count;
}
//判断输赢的函数,返回哪个颜色获胜
public int checkWin(int x1, int y1) {
int ret = 0;
if (countchessX(x1, y1) >= 5 || countchessY(x1, y1) >= 5 || countchessM(x1, y1) >= 5 || countchessN(x1, y1) >= 5) {
if (chessArr[y1][x1] == 1) { //最后下黑棋
ret = 1;
}
else if (chessArr[y1][x1] == -1) { //最后下白棋
ret = -1;
}
}
return ret;
}
}
2、在线模式
(1)用户登录
当用户点击联网对战按钮的时候,会弹出一个登陆界面,如果账号第一次登录则需要注册
如果,已经注册过,则会显示登陆成功,并显示当前用户的用户名
客户端及服务端的代码,请移步git仓库
https://gitee.com/memoryee/gobang
(2)联网匹配
当用户登录成功后,就会于服务端去连接,当服务端的连接人数位两人时,游戏就会开始,就
可以开始下棋了,最先链接进入服务端的用户为先手,也就是黑棋
同上
客户端及服务端的代码,请移步git仓库
https://gitee.com/memoryee/gobang
五、主要功能截图
1、主界面
2、游戏界面
3、用户登录界面
六、技术难点
网络通信:实现网络通信是五子棋联网游戏的关键难点。需要在客户端和服务器端之间建立可靠的通信
连接,以保证双方可以实时传递游戏状态和数据信息。
游戏同步:在对弈双方进行游戏时,需要将游戏状态同步给对方,确保对弈双方看到的游戏状态是一致
且同步的。若游戏状态出现了不一致的情况,则会影响游戏的公平性和可玩性。
网络延迟:由于网络的延迟,可能会出现客户端和服务器端的数据不同步,或是造成游戏时间的卡顿。
为了减轻这种情况的影响,需要对网络延迟进行优化,采用更稳定的网络协议和传输方式进行数据传输。
算法优化:五子棋的算法较为复杂,需要进行深度优化,以避免游戏卡顿和影响游戏操作。此外,还需
要处理好游戏结束后的胜负判断、计分等问题。
安全性:网络游戏涉及到用户的个人信息和账号信息,需要考虑网络安全问题,防止信息被篡改或者泄
露。
总之,五子棋联网游戏,在实现过程中需要结合以上难点,采用合适的技术手段进行实现。同时,也需
要不断对游戏性能和用户体验进行优化,以提升游戏体验和用户满意度。
七、启示
代码结构和可读性:实现五子棋联网游戏需要编写复杂的代码,对代码结构和可读性的要求十分高。
一个好的代码结构可以使代码更易于维护和修改,同时提高代码质量和可靠性。在编写代码时应尽量
避免重复代码和冗余代码,同时注重代码的格式和注释,让代码更加易懂。
网络通信:网络通信是现代软件设计中一个必不可少的重要模块。在实现五子棋联网游戏时,需要使
用网络通信技术实现客户端和服务器之间的数据传输。理解网络通信原理和技术可以为实现其他类型
的网络应用提供帮助。
算法优化:五子棋算法的优化需要经过多次实践和不断调整才能达到最佳效果,能够通过学习不同算
法和技巧来提高算法的效率。算法的优化对于软件设计和实现来说都是非常重要的一步,可以提高软
件的性能、稳定性和可靠性。