基于 socket 的联网五子棋,这个项目是我用来参加十二届的易途杯和团队一起写的,虽然没有获奖(其他队伍太强了!!!!)
项目特点
1 . 基于 socket 实现了联网状态下的五子棋
2 . 使用 Graphics 实现棋盘的绘制和棋子的绘制
3 . 实现了五子棋的基本功能
项目缺点
1 . 没有实现悔棋的功能
2 . 用户界面不够美观,用户体验感不好
3 . 没有采用多线程(不会啊!)
下面就直接附上代码和运行截图吧,至于具体代码的解释等以后再进行更新吧,有不懂的可以在下面评论留言,看到会回复的!
首页面
package jobangfinaly;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class JframeDemo extends JPanel implements MouseListener{
// 坐标
static int x;
static int y;
// 传送的坐标
static int ex;
static int ey;
// 悔棋的坐标
static int px;
static int py;
// 初始化的一些变量
boolean me = true;
boolean one = true;
static boolean start = false;
// 棋盘
static int[][] chess = new int[12][12];
static String userNameIp; // 对方的ip地址
static InetAddress inetAddress; // 客户端的ip地址
static int clientPort; // 客户端端口
static int serverPort; // 服务端端口
static boolean danJi; // 选择单机模式
public static void main(String[] args) {
JFrame frame;
frame = new JFrame();
frame.setTitle("五子棋");
frame.setSize(660,785);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
JframeDemo jobang = new JframeDemo();
frame.add(jobang,BorderLayout.NORTH);
jobang.setPreferredSize(new Dimension(0,650));
JPanel button = new JPanel();
button.setBackground(new Color(222,184,135));
button.setPreferredSize(new Dimension(0,100));
frame.add(button,BorderLayout.SOUTH);
JButton rc = new JButton();
button.add(rc);
rc.setPreferredSize(new Dimension(100,50));
rc.setText("退出游戏");
// rc.setOpaque(false);
rc.setBorder(BorderFactory.createLineBorder(new Color(255,218,185),2));
rc.setBackground(new Color(244,164,96));
rc.setForeground(new Color(250,235,215));
rc.setFont(new Font("微软雅黑",Font.BOLD,14));
rc.addMouseListener(new MouseListener() {
@Override
public void mouseReleased(MouseEvent e) {
int choice = JOptionPane.showConfirmDialog(null,"是否退出游戏","退出游戏",JOptionPane.OK_CANCEL_OPTION);
if(choice == JOptionPane.OK_OPTION) {
System.exit(0);
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseClicked(MouseEvent e) {
}
});
int chose = JOptionPane.showConfirmDialog(null, "选择联网或者单机", "模式选择", JOptionPane.YES_OPTION, JOptionPane.WARNING_MESSAGE);
if(chose == JOptionPane.YES_OPTION) {
try {
userNameIp = JOptionPane.showInputDialog(null, "请输入对方的IP地址", "模式选择", JOptionPane.WARNING_MESSAGE).trim();
clientPort = Integer.parseInt(JOptionPane.showInputDialog(null, "请输入您的端口号", "端口号范围:1024~65535",JOptionPane.WARNING_MESSAGE).trim());
serverPort = Integer.parseInt(JOptionPane.showInputDialog(null, "请输入对方的端口号", "端口号范围:1024~65535", JOptionPane.WARNING_MESSAGE).trim());
} catch (Exception e) {
// 输入错误,或者不输入的情况
JOptionPane.showMessageDialog(null, "输入错误,请重新打开游戏吧!", "错误", JOptionPane.ERROR_MESSAGE);
System.exit(0);
e.printStackTrace();
}
try {
inetAddress =InetAddress.getByName(userNameIp);
} catch (UnknownHostException e) {
e.printStackTrace();
}
if(inetAddress != null) {
JOptionPane.showMessageDialog(null, "开始", "游戏马上开始", JOptionPane.WARNING_MESSAGE);
start = true;
if(clientPort == serverPort) {
danJi = true; //端口号相等,进入单机模式
} else {
danJi = false; // 反之进入联机模式
}
jobang.run1();
}
}
if(chose == JOptionPane.NO_OPTION || chose == JOptionPane.CLOSED_OPTION) {
// 选择单机模式,关闭窗口也默认为选择单机模式
JOptionPane.showMessageDialog(null, "您将与您自己进行对弈!", "单机模式", JOptionPane.INFORMATION_MESSAGE);
try {
inetAddress = InetAddress.getLocalHost(); // 获取本地的IP地址
serverPort = clientPort = 7778; // 设置默认端口号
start = true;
danJi = true;
jobang.run1();
} catch (UnknownHostException e) {
JOptionPane.showMessageDialog(null, "本地IP地址错误!", "单机模式启动失败", JOptionPane.ERROR_MESSAGE);
System.exit(0);
e.printStackTrace();
}
}
}
public void run1() {
CLearChess clearChess = new CLearChess(JframeDemo.this); // 绘制棋盘
clearChess.clearChess();
Receive receive = new Receive(JframeDemo.this); // 开启接收数据
receive.receive();
}
public JframeDemo() {
setBackground(new Color(222,184,135));
addMouseListener(this);
setVisible(true);
}
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
DrawChessBoard drawChessBoard = new DrawChessBoard();
drawChessBoard.drawChessBoard(graphics);
DrawChess drawChess = new DrawChess();
drawChess.drawChess(graphics);
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
if (start == false) {
return;
}
ex = e.getX();
ey = e.getY();
if (ex >= 25 && ex <= 618 && ey >= 25 && ey <= 618) {
// 控制鼠标点击位于棋盘内部
x = (ex - 19) / 50; // 使棋子排列在棋盘交点处
y = (ey - 19) / 50;
px = x;
py = y;
}
else return ;
if (chess[x][y] != 0) {
// 当点击位置已经有棋子,则此次点击无效,并继续落子
return;
}
if (one == true) {
// 轮到一方落子时,落子判断胜负,并传送鼠标点击的坐标
ChangeChess changeChess = new ChangeChess(JframeDemo.this);
changeChess.doit();// 若传送坐标前判断胜负,则会导致最后一颗棋子落子信息阻塞,判断完毕后再次传送,故此处不判断
Send sendxy = new Send(JframeDemo.this);
sendxy.sendXY(ex, ey);// 先传送坐标再判断胜负
CheckWiner checkWiner = new CheckWiner(JframeDemo.this);
checkWiner.checkWiner();
}
one = false;// 换到对方落子
}
}
用户下棋
package jobangfinaly;
public class ChangeChess {
JframeDemo jDemo =null;
public ChangeChess(JframeDemo jDemo) {
super();
this.jDemo = jDemo;
}
public void doit() {
// 判断落子颜色及判断胜方
jDemo.x = (jDemo.ex - 19) / 50; // 将棋子放置在交叉线上
jDemo.y = (jDemo.ey - 19) / 50;
if (jDemo.chess[jDemo.x][jDemo.y] == 0) {
// 点击位置无棋子
if (jDemo.me == true) {
jDemo.chess[jDemo.x][jDemo.y] = 11;// 黑子
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
if (jDemo.chess[i][j] == 22) {
jDemo.chess[i][j] = 2;// 把刚才下的加白框的白子转换为普通白子
}
}
}
jDemo.me = false;// 换为白子落子
} else if (jDemo.me == false) {
jDemo.chess[jDemo.x][jDemo.y] = 22;// 白子
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
if (jDemo.chess[i][j] == 11) {
jDemo.chess[i][j] = 1;// 把刚才下的加黑框的黑子转换为普通黑子
}
}
}
jDemo.me = true;// 换为黑子落子
}
}
jDemo.repaint();// 重绘棋盘后判断胜方
}
}
判断是否胜利
package jobangfinaly;
import javax.swing.JOptionPane;
public class CheckWiner {
JframeDemo jDemo =null;
public CheckWiner(JframeDemo jDemo) {
this.jDemo = jDemo;
}
public void checkWiner() {
// 判断胜方
CLearChess clearChess = new CLearChess(jDemo);
int bcount = 0;
int wcount = 0;
for (int i = 0; i < 12; i++) {
// 横向判断
for (int j = 0; j < 12; j++) {
// 判断黑棋
if (jDemo.chess[i][j] == 1 || jDemo.chess[i][j] == 11) {
bcount++;
if (bcount == 5) {
JOptionPane.showMessageDialog(jDemo, "黑棋胜利");
clearChess.clearChess();
return;
}
} else {
bcount = 0;
}
// 判断白棋
if (jDemo.chess[i][j] == 2 || jDemo.chess[i][j] == 22) {
wcount++;
if (wcount == 5) {
JOptionPane.showMessageDialog(jDemo, "白棋胜利");
clearChess.clearChess();
return;
}
} else {
wcount = 0;
}
}
}
for (int i = 0; i < 12; i++) {
// 竖向判断
for (int j = 0; j < 12; j++) {
if (jDemo.chess[j][i] == 1 || jDemo.chess[j][i] == 11) {
bcount++;
if (bcount == 5) {
JOptionPane.showMessageDialog(jDemo, "黑棋胜利");
clearChess.clearChess();
return;
}
} else {
bcount = 0;
}
if (jDemo.chess[j][i] == 2 || jDemo.chess[j][i] == 22) {
wcount++;
if (wcount == 5) {
JOptionPane.showMessageDialog(jDemo, "白棋胜利");
clearChess.clearChess();
return;
}
} else {
wcount = 0;
}
}
}
for (int i = 0; i < 8; i++) {
// 左向右斜判断
for (int j = 0; j < 8; j++) {
for (int k = 0; k < 5; k++) {
if (jDemo.chess[i + k][j + k] == 1 || jDemo.chess[i + k][j + k] == 11) {
bcount++;
if (bcount == 5) {
JOptionPane.showMessageDialog(jDemo, "黑棋胜利");
clearChess.clearChess();
return;
}
} else {
bcount = 0;
}
if (jDemo.chess[i + k][j + k] == 2 || jDemo.chess[i + k][j + k] == 22) {
wcount++;
if (wcount == 5) {
JOptionPane.showMessageDialog(jDemo, "白棋胜利");
clearChess.clearChess();
return;
}
} else {
wcount = 0;
}
}
}
}
for (int i = 4; i < 12; i++) {
// 右向左斜判断 11->12
for (int j = 7; j >= 0; j--) {
for (int k = 0; k < 5; k++) {
if (jDemo.chess[i - k][j + k] == 1 || jDemo.chess[i - k][j + k] == 11) {
bcount++;
if (bcount == 5) {
JOptionPane.showMessageDialog(jDemo, "黑棋胜利");
clearChess.clearChess();
return;
}
} else {
bcount = 0;
}
if (jDemo.chess[i - k][j + k] == 2 || jDemo.chess[i - k][j + k] == 22) {
wcount++;
if (wcount == 5) {
JOptionPane.showMessageDialog(jDemo, "白棋胜利");
clearChess.clearChess();
return;
}
} else {
wcount = 0;
}
}
}
}
}
}
初始化棋盘
package jobangfinaly;
public class CLearChess {
JframeDemo jDemo =null;
public CLearChess(JframeDemo jframeDemo) {
this.jDemo=jframeDemo;
}
public void clearChess() {
// 初始化棋盘
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
jDemo.chess[i][j] = 0;
}
}
jDemo.me = true;// 初始化为己方落黑子
jDemo.repaint();
}
}
绘制棋子
package jobangfinaly;
import java.awt.Color;
import java.awt.Graphics;
public class DrawChess {
public void drawChess(Graphics g) {
JframeDemo jDemo = new JframeDemo();
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
if (jDemo.chess[i][j] == 1) {
g.setColor(Color.black);
g.fillOval((i + 1) * 50 - 19, (j + 1) * 50 - 19, 38, 38);
} else if (jDemo.chess[i][j] == 2) {
g.setColor(Color.white);
g.fillOval((i + 1) * 50 - 19, (j + 1) * 50 - 19, 38, 38);
} else if (jDemo.chess[i][j] == 11) {
// 点击落黑子时外加个黑框
g.setColor(Color.black);
g.fillOval((i + 1) * 50 - 19, (j + 1) * 50 - 19, 38, 38);
g.drawRect((i + 1) * 50 - 19, (j + 1) * 50 - 19, 38, 38);
} else if (jDemo.chess[i][j] == 22) {
// 点击落白子时棋子外加个白框
g.setColor(Color.white);
g.fillOval((i + 1) * 50 - 19, (j + 1) * 50 - 19, 38, 38);
g.drawRect((i + 1) * 50 - 19, (j + 1) * 50 - 19, 38, 38);
}
}
}
}
}
绘制棋盘
package jobangfinaly;
import java.awt.Color;
import java.awt.Graphics;
public class DrawChessBoard {
public void drawChessBoard(Graphics g) {
// 画棋盘
for (int i = 50; i <= 600; i += 50) {
g.setColor(Color.WHITE);
g.drawLine(i, 50, i, 600);
g.drawLine(50, i, 600, i);
}
}
}
接受数据
package jobangfinaly;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JOptionPane;
public class Receive {
JframeDemo jDemo =null;
public Receive(JframeDemo jDemo) {
this.jDemo = jDemo;
}
public void receive() {
// 服务端接收对方发来的坐标
ChangeChess doit = new ChangeChess(jDemo);
CheckWiner checkWiner = new CheckWiner(jDemo);
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(jDemo.clientPort);
} catch (IOException e) {
e.printStackTrace();
}// 从该端口接收数据
while (true) {
Socket sSocket = null;
try {
sSocket = serverSocket.accept();
} catch (IOException e) {
e.printStackTrace();
}
InputStream is = null;
try {
is = sSocket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
byte[] bys = new byte[1024];
int len = 0;
try {
len = is.read(bys);
} catch (IOException e) {
e.printStackTrace();
}
String strReceive = new String(bys, 0, len);
String[] strs = strReceive.split("-");// 使用"-"分割字符串,得到坐标
jDemo.ex = Integer.parseInt(strs[0]);
jDemo.ey = Integer.parseInt(strs[1]);
doit.doit();// 落子
checkWiner.checkWiner();
jDemo.one = true;// 变为己方落子
}
}
}
发送坐标
package jobangfinaly;
import java.io.OutputStream;
import java.net.Socket;
import javax.swing.JOptionPane;
public class Send {
JframeDemo jDemo = null;
public Send(JframeDemo jDemo) {
super();
this.jDemo = jDemo;
}
public void sendXY(int xSend, int ySend) {
// 传送鼠标点击的坐标
try {
// 问题在于每次传送坐标都要重新创建一个socket对象,不知道怎么改进
Socket socket = new Socket(jDemo.inetAddress, jDemo.serverPort);// 设置对方服务器端IP,并设置端口号为9653;
OutputStream os = socket.getOutputStream();
String strr = xSend + "-" + ySend;// 使用-符号连接坐标,并以字符串形式发送到服务端
os.write(strr.getBytes());
socket.shutdownOutput();// 及时发送位置信息,不用closs()是保持通信一直连接
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, "您的网络连接错误!", "网络错误", JOptionPane.ERROR_MESSAGE);
System.exit(0);
ex.printStackTrace();
}
}
}
这次的易途杯比赛浪费了好多时间,而且最后也没有获奖,团队里就两个人在努力,害,下次做项目的话,一定要找好团队,确定具体的计划,确定好具体的分工,写好项目思路,写好项目报告,好好学习基础知识,不会的地方要搞明白,还有PPT的制作,一定要有,这是一个加分项,不止是加分项还是一个项目演示的基本思路,害,总之还是自己太菜了,下次继续加油吧!!!!!!!!!!!!