Java 联网五子棋(socket)

基于 socket 的联网五子棋,这个项目是我用来参加十二届的易途杯和团队一起写的,虽然没有获奖(其他队伍太强了!!!!)
项目特点
1 . 基于 socket 实现了联网状态下的五子棋
2 . 使用 Graphics 实现棋盘的绘制和棋子的绘制
3 . 实现了五子棋的基本功能
项目缺点
1 . 没有实现悔棋的功能
2 . 用户界面不够美观,用户体验感不好
3 . 没有采用多线程(不会啊!)

下面就直接附上代码和运行截图吧,至于具体代码的解释等以后再进行更新吧,有不懂的可以在下面评论留言,看到会回复的!

运行界面
Java 联网五子棋(socket)_第1张图片

游戏界面
Java 联网五子棋(socket)_第2张图片

下面就直接给出代码吧!

首页面

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的制作,一定要有,这是一个加分项,不止是加分项还是一个项目演示的基本思路,害,总之还是自己太菜了,下次继续加油吧!!!!!!!!!!!!

你可能感兴趣的:(项目,java)