技术交流:Java五子棋游戏+聊天室(文末源代码)

结合Java网络编程,设计一款包含五子棋游戏与聊天室功能的应用,支持玩家注册登录、擂台挑战、观战、群聊及私聊。采用多线程、TCP/UDP通信、安全技术,实现游戏和聊天的实时交互。

Java:五子棋游戏+聊天室

综合运用java网络编程知识(必须用到流、线程池、TCP或UDP,以及安全通信技术)

设计技术:

  1. 掌握字节流与字符流的应用
  2. 掌握多线程及线程池的应用
  3. 掌握基于TCP的网络编程技术
  4. 掌握基于UDP的网络编程技术
  5. 掌握安全通信技术
  6. 掌握HTTP通信技术

游戏功能

  • 基本功能:
    1>玩家注册、登录(通过安全技术处理敏感信息);
    2>加入擂台(擂主列表)、挑战擂主(对战列表);
    3>观战
    4>群聊吐槽(在线玩家列表,及时更新列表);
    5>对战双方可以私聊。
  • 其他功能:
    玩家经验值积分,并分设段位;发送表情包,分享图片;保存棋盘;打开新闻链接等

(相关代码在底部)

游戏展示

游戏界面均使用JavaFX
相关文档:JavaFX中文文档

数据库设计

制作了一个简易的表,对应用户的账号密码经验值邮箱。扩展:表中可以加入md5密码串列,验证密码时通信传输的过程不是明文密码,而是经过md5加密的字符串。验证密码只需要对比表中对应md5即可。

数据库表

注册

用户的账号密码放在数据库表中,所以注册是需要检查用户名是否已经存在,如果存在则注册失败,相反则注册成功。

注册界面

在这里插入图片描述

注册失败

注册失败

注册成功

注册成功

登录

登录除了基本的账号密码检查之外,还要注意该用户是否已经登录,如果已经登录则提醒已登录并关闭游戏窗口。

登录界面

登录界面

登录失败

提示玩家已经登录
账号或密码错误

登陆成功

登录成功

游戏过程

界面

游戏界面

加入擂台

加入擂台

主动挑战或接受挑战

主动挑战或接受挑战

输赢判断和观战

输赢判断和观战

平局和投降

平局和投降平局和投降平局和投降
平局和投降

保存棋盘和链接

截取屏幕生成图片保存棋盘和txt文本。
后续可以读取txt获取当时的游戏棋盘布局,自行扩展。
保存棋盘和链接保存棋盘和链接

查看信息

查看信息

聊天室

进入聊天室

进入聊天室

群聊

群聊

私聊

私聊

发送文件或图片

发送文件或图片

离开聊天室

离开聊天室

服务端

服务端的配置


public class ServerConfig {
	//服务器开启的UDP端口
	public final static SocketAddress SERVER_ADDR = new InetSocketAddress("0.0.0.0", 6666);
	//public final static int CLIENT_LISTEN_PORT_DEFAULT = 5000;
	private static HashMap<String, Player> hostMap = new HashMap<String, Player>();//用于存放擂主信息
	private static HashMap<String, Player> playerMap = new HashMap<String, Player>();//用于存放所有玩家的信息
	private static HashMap<String,Player> playersComList=new HashMap<String, Player>();//用于存在所有在线玩家的信息
	private static HashMap<String,Player> playingMap = new HashMap<String,Player>();//用于存放正在比赛的玩家
	private static HashMap<String,Player> guanZhanMap = new HashMap<String,Player>();//存放观战的玩家
	public static void addHost(String name, Player player){
		hostMap.put(name, player);
	}//添加擂主
	public static void addComPlayer(String name ,Player player ){playersComList.put(name,player);}//添加聊天室在线玩家
	public static void addPlayingPlayer(String name ,Player player ){playingMap.put(name,player);}//添加游戏正在对战玩家

	public static boolean containHost(String name){
		return hostMap.containsKey(name);
	}//判断擂主是否存在
	public static boolean containPlaying(String name){
		return playingMap.containsKey(name);
	}//判断擂主是否存在
	public static boolean containPlayer(String name){
		return playerMap.containsKey(name);
	}//判断玩家是否存在

	public static HashMap<String,Player> getHostMap(){return hostMap;}//获取擂主Map
	public static HashMap<String, Player> getPlayerMap(){
		return playerMap;
	}//获取玩家Map
	public static HashMap<String,Player> getPlayerComMap(){return playersComList;}//获取聊天室玩家Map
	public static HashMap<String,Player> getGuanZhanMap(){return guanZhanMap;}//获取观战Map

	public static Player getPlayer(String name){
		return playerMap.get(name);
	}//获取玩家
	public static Player getComPlayer(String name){return playersComList.get(name);}//获取聊天室玩家
	public static Player getGuanZhan(String name){return guanZhanMap.get(name);}//获取观战玩家

	public static void addPlaying(String name, Player player){
		playingMap.put(name, player);
	}//添加在线玩家
	public static void addPlayer(String name, Player player){
		playerMap.put(name, player);
	}//添加玩家
	public static void addGuanZhanPlayer(String name,Player player){guanZhanMap.put(name,player);}//添加观战玩家

	public static void delComPlayer(String name){
		playersComList.remove(name);
	}//删除聊天室玩家
	public static void delHostPlayer(String name){ hostMap.remove(name); }//删除擂主
	public static void delPlaying(String name){ playingMap.remove(name); }//删除在线玩家
	public static void delMapPlayer(String name){playerMap.remove(name);}//删除玩家
	public static void delGuanZhan(String name){guanZhanMap.remove(name);}//删除观战玩家
	public static void delAllPlayer(String name){
		delGuanZhan(name);
		delMapPlayer(name);
		delHostPlayer(name);
		delComPlayer(name);
		delPlaying(name);
	}
	//获取玩家地址
	public static SocketAddress getPlayerAddr(String name){ return getPlayer(name).getAddress(); }
	//获取聊天室玩家列表
	public static  String getComNamesList(){
		String str = "";
		Iterator<String> it = playersComList.keySet().iterator();
		while(it.hasNext()){
			str = str  + it.next() + ":";
		}
		System.out.println("get:"+str);
		return str;
	}
	//获取擂主列表
	public static String getHostNamesList(){
		String str = "";	
		Iterator<String> it = hostMap.keySet().iterator();	
		while(it.hasNext()){
			str = str  + it.next() + ":";		
		}
		System.out.println("get:"+str);
		return str;
	}
}

通信类Message的实现


import java.io.*;
public class Message implements Serializable{
	int msgType;//信息类型,参看类MessageType中的定义
	int status;//信息的状态:分为成功和失败
	Object content;//信息的内容
	Player fromPlayer;//信息的发送方
	Player toPlayer;//信息的接收方

	public Player getFromPlayer() {
		return fromPlayer;
	}
	public void setFromPlayer(Player fromPlayer) {
		this.fromPlayer = fromPlayer;
	}
	public Player getToPlayer() {
		return toPlayer;
	}
	public void setToPlayer(Player toPlayer) {
		this.toPlayer = toPlayer;
	}	
	public int getMsgType() {
		return msgType;
	}
	public void setMsgType(int msgType) {
		this.msgType = msgType;
	}
	public int getStatus() {
		return status;
	}
	public void setStatus(int status) {
		this.status = status;
	}
	public Object getContent() {
		return content;
	}
	public void setContent(Object content) {
		this.content = content;
	}
	public String toString(){
		return "["+msgType +"," + status + ", " + fromPlayer + ", " + toPlayer + ", " + content;
	}
	
	/**
	 * 将信息Message的对象转换成字节数组(传递给DatagramPacket),用于socket通信
	 * @param obj
	 * @return
	 */
	public static byte[] convertToBytes(Message obj){
		try(
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ObjectOutputStream ois = new ObjectOutputStream(baos);					
			) {
			ois.writeObject(obj);
			return baos.toByteArray();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return null;
	}
    
	/**
	 * 将字节数组(从DatagramPacket中获取)转换成Message的对象。
	 * @param bytes
	 * @param offset
	 * @param length
	 * @return
	 */
	public static Message convertToObj(byte[] bytes, int offset, int length){
		try (
			ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
			ObjectInputStream ois = new ObjectInputStream(bais);		
		){
			return (Message) ois.readObject();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return null;	
	}
}

Message类型说明

public class MessageType {
    public static final int SUCCESS = 0;
    public static final int FAIL = -1;
    public static final int JOIN_GAME = 1;//申请加入游戏的请求信息
    public static final int JOIN_HOST = 2;//申请加入擂主的请求信息
    public static final int CHALLENGE = 3;//挑战擂主的请求信息
    public static final int CHALLENGE_RSP = 4;//挑战擂主的请求信息
    public static final int UPDATE_HOST = 5;//更新擂主列表的信息
    public static final int PLAY = 6;//玩家下了一步棋的信息
    public static final int HUIQI = 8;//悔棋
    public static final int HUIQI_RSP = 9;
    public static final int SURRENDER = 10;//投降
    public static final int DOGFALL = 11;//平局
    public static final int DOGFALL_RSP = 12;//平局回应
    public static final int JOIN_COM = 15;//加入聊天室
    public static final int PUBLIC_CHAT = 16;//广播
    public static final int PRIVATE_CHAT = 17;//私聊
    public static final int UPDATE_COM = 20;//更新在线玩家的信息
    public static final int QUIT_COM=21;//退出聊天室
    public static final int QUIT_HOST=22;//退出擂台
    public static final int QUIT_GAME=23;//退出游戏
    public static final int SENDFILES=24;//发送图片请求
    public static final int SENDFILES_RSP=25;//图片回应
    public static final int GUIZHAN=26;//观战
    public static final int QUI_GUANZHAN=27;//退出观战
}

封装玩家信息:


public class Player implements Serializable{
	String name;//玩家名字
	SocketAddress address;//玩家的socket地址
	int color;//玩家的棋子颜色

	public int getColor() {
		return color;
	}

	public void setColor(int color) {
		this.color = color;
	}

	public Player(String name, SocketAddress address){
		this.name = name;
		this.address = address;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	public SocketAddress getAddress()  {

		return address;
	}
	public void setAddress(SocketAddress address) {
		this.address = address;
	}
	public String toString(){
		return "[" + name+"," + address + "]";
	}
}

DataBase类的创建


import java.security.MessageDigest;
import java.sql.*;

public class DataBase {
    private static final String JDBC_DEIVER = "com.mysql.cj.jdbc.Driver";
    private static final String DB_URL = "jdbc:mysql://localhost:3306/mysql?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT\n";
    //?useUnicode=true&characterEncoding=utf8&useSSL=false
    private static final String USER = "root";
    private static final String PASS = "123456";
    private static Connection conn = null;
    private static Statement stmt = null;
    private static ResultSet rs = null;
    public static String string2MD5(String inStr){
        MessageDigest md5 = null;
        try{
            md5 = MessageDigest.getInstance("MD5");
        }catch (Exception e){
            System.out.println(e.toString());
            e.printStackTrace();
            return "";
        }
        char[] charArray = inStr.toCharArray();
        byte[] byteArray = new byte[charArray.length];

        for (int i = 0; i < charArray.length; i++)
            byteArray[i] = (byte) charArray[i];
        byte[] md5Bytes = md5.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++){
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16)
                hexValue.append("0");
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();

    }

    /**
     * 加密解密算法 执行一次加密,两次解密
     */
    public static String convertMD5(String inStr){

        char[] a = inStr.toCharArray();
        for (int i = 0; i < a.length; i++){
            a[i] = (char) (a[i] ^ 't');
        }
        String s = new String(a);
        return s;

    }
    //  连接数据库
    public static void connectDB() {
        try {
            Class.forName(JDBC_DEIVER);
            //STEP 3:建立连接到数据库
//            System.out.println("正在连接数据库");
            conn = DriverManager.getConnection(DB_URL, USER, PASS);
            stmt = conn.createStatement();
        } catch (ClassNotFoundException | SQLException e) {
            System.out.println("连接数据库失败");
            e.printStackTrace();
        }
    }

    public static int checkUser(String name,String password){
        System.out.println("加密后的密码: "+password);
        password= convertMD5((password));//解密
        System.out.println("解密后的密码: "+password);

        int result = 99;
        try {
            String sqlContent = "SELECT COUNT(*) FROM game WHERE name='%s' and password='%s';";
            String sql = String.format(sqlContent, name,password);
            ResultSet rs = stmt.executeQuery(sql);
            while (rs.next()) {
                result = rs.getInt(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return result;
    }


    //  查询用户表中是否存在该用户名  返回值:0没有1有
    public static int checkName(String name) {
        int result = 99;

        try {
            String sqlContent = "SELECT COUNT(*) FROM game WHERE name='%s';";
            String sql = String.format(sqlContent, name);
            ResultSet rs = stmt.executeQuery(sql);
            while (rs.next()) {
                result = rs.getInt(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return result;
    }

    //  断开数据库
    public static void closeDB() {
        try {
            if (stmt != null)
                stmt.close();
            if (conn != null)
                conn.close();
        } catch (SQLException e) {
            System.out.println("关闭数据库失败");
            e.printStackTrace();
        }
        System.out.println("关闭数据库成功");
    }

    //  添加新用户   返回值:0失败1成功
    public static int addUser(String name, String password, String email) {

        try {

            if (checkName(name) == 1) {
                System.out.println("添加用户失败,该用户名已经存在。");
                return 0;
            } else {
                String sqlC = "INSERT INTO game(name,password,email) VALUE('%s','%s','%s');";
                String sql = String.format(sqlC, name, password, email);
                stmt.executeUpdate(sql);
                System.out.println("添加用户成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return 1;
    }

    // 增加经验
    public static void addExc(String name) {

        int exp = 0;
        try {
            String sqlContent = "SELECT * FROM game WHERE name='%s';";
            String sql = String.format(sqlContent, name);
            ResultSet rs = stmt.executeQuery(sql);
            while (rs.next()) {
                exp = rs.getInt("exp") + 10;
//                result=rs.getString("exc");
//                result = rs.getInt(1);
            }

            String updata = "update game set exp='%s' where name='%s';";
            String updataSql = String.format(updata, exp, name);
            stmt.executeUpdate(updataSql);
            System.out.println("用户:" + name + "增加10经验成功。");
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

    public static void delExc(String name){
        int exp=0;
        try {
            String sqlContent = "SELECT * FROM game WHERE name='%s';";
            String sql = String.format(sqlContent, name);
            ResultSet rs = stmt.executeQuery(sql);
            while (rs.next()) {
                exp = rs.getInt("exp") - 10;
//                result=rs.getString("exc");
//                result = rs.getInt(1);
            }

            String updata = "update game set exp='%s' where name='%s';";
            String updataSql = String.format(updata, exp, name);
            stmt.executeUpdate(updataSql);
            System.out.println("用户:" + name + "减少10经验成功。");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    // 查看用户信息
    public static String selectUser(String name) {
        String password = null;
        String email = null;
//        String grade=null;
        int exp = 0;
        try {
            String sqlContent = "SELECT * FROM game WHERE name='%s';";
            String sql = String.format(sqlContent, name);
            ResultSet rs = stmt.executeQuery(sql);
            while (rs.next()) {

                password = rs.getString("password");
                exp = rs.getInt("exp");
                email = rs.getString("email");
//                grade=rs.getString("grade");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        String grade=grade(exp);
        return "\n用户名:"+name + "\n密码:" + password + "\n经验:" + exp + "\n邮箱:" + email+ "\n段位:" + grade;
    }

    public static String grade(int exp){
        String grade="";
        if(exp<50){
            grade="青铜";
        }else if(exp<200){
            grade="白银";
        }else if(exp<500){
            grade="黄金";
        }else if(exp<1000){
            grade="钻石";
        }else if(exp<2500){
            grade="王者";
        }else{
            grade="大神";
        }
        return grade;
    }
}

落子点的信息

import java.io.Serializable;

public class Point implements Serializable{
	public int column, row,action;
	public int color;
	public Point(int column, int row, int color, int action){
		this.column = column;
		this.row = row;
		this.color = color;
		this.action = action;
	}
	public String toString(){
		return "[" + this.column + "," + row + "," + color + "," + action + "]";
	}
	
}

客户端

客户端的配置

ClientConfig.java

public class ClientConfig {
	//服务器的地址
	public static final SocketAddress SERVER_ADDR 
			= new InetSocketAddress("0.0.0.0", 6666);
	//本地的地址
	public static final SocketAddress LOCAL_ADDR 
			= new InetSocketAddress("0.0.0.0", 1111);
	
	public static final int ACTION_TYPE_ADD = 1;//新下棋
	public static final int ACTION_TYPE_DEL = 0;//悔棋
	public static final int COLOR_WHITE=2;
	public static final int COLOR_BLACK=1;
	public static final int COLOR_BLANK=0;
	
}

五子棋盘

Chess5Pane.java


import CurriculumDesign.Server.Message;
import CurriculumDesign.Server.Point;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import java.net.DatagramPacket;
import java.net.DatagramSocket;


public class Chess5Pane extends Pane {

    private int x_0 = 30, y_0 = 30; //棋盘左上角的位置
    private int N = 9; //N*N的棋盘
    private int k = 60; //方格宽(高)度
    private int r = 20; //棋子(圆)半径
    private int color = ClientConfig.COLOR_BLACK;//先手为黑子: 1表示黑子,2表示白子,0表示没有棋子
    private int[][] data = new int[N + 1][N + 1];
    public Competition competition;

    public Chess5Pane() {

        setMaxSize(N * k + x_0 * 2, N * k + y_0 * 2);
        setMinSize(N * k + x_0 * 2, N * k + y_0 * 2);

        //-fx-border-color:设置边框颜色;-fx-border-width设置边框宽度;-fx-background-color:设置背景颜色
        setStyle("-fx-border-color:#EED8AE;-fx-background-color:#EED8AE;-fx-border-width:5");

        setOnMouseClicked(this::mouseClickHandler);

        //画棋盘
        drawBoard();
    }

    public Competition getCompetition() {
        return this.competition;
    }

    /**
     * 画棋盘线
     */
    public void drawBoard() {
        //画横向线
        for (int i = 0; i <= N; i++) {
            getChildren().add(new Line(x_0, y_0 + i * k, x_0 + N * k, y_0 + i * k));
        }
        //画纵向线
        for (int i = 0; i <= N; i++) {
            getChildren().add(new Line(x_0 + i * k, y_0, x_0 + i * k, y_0 + N * k));
        }
    }

    public void setColor(int color) {
        this.color = color;
    }

    public void setCompetition(Competition com) { this.competition = com; }

    public void setData(int[][] data){this.data=data;}
    public int[][] getData() {
        return data;
    }

//    public void setData(int[][] data) {
//        this.data = data;
//    }

    /**
     * 在指定棋盘下棋点绘制指定颜色的棋子(圆)
     *
     * @param row    棋盘行数
     * @param column 棋盘列数
     * @param color  棋子颜色,1为黑子,2为白子
     */
    public void drawChess(int row, int column, int color) {
        //根据给定的行列值,求出实际的坐标点
        int x_c = x_0 + column * k;
        int y_c = y_0 + row * k;
        Circle circle = new Circle(x_c, y_c, r, color == 1 ? Color.BLACK : Color.WHITE);
        getChildren().add(circle);
        data[row][column] = color;

    }

    public void removeChess(int row, int column, int color) {
        //根据给定的行列值,求出实际的坐标点
        int x_c = x_0 + column * k;
        int y_c = y_0 + row * k;
//		Circle circle = new Circle(x_c,y_c,r,color==1?Color.BLACK:Color.WHITE);
        Circle circle = new Circle(x_c, y_c, r, color == 1 ? Color.BLACK : Color.WHITE);
//		getChildren().removeIf(a ->(Color.WHITE));

        getChildren().remove(circle);
        data[row][column] = 0;


    }
    public static String printArr1(int[][] arr) {
        String str = "";
        for (int x = 0; x < arr.length; x++) {
            for (int y = 0; y < arr[x].length; y++) {
                str = str + arr[x][y];
            }
        }
        return str;
    }
    /**
     * 响应鼠标事件,检查对应位置的落子情况,并在对应位置添加棋子
     *
     * @param e
     */
    public void mouseClickHandler(MouseEvent e) {

        if (e.getClickCount() == 2) {//鼠标双击

            int column = (int) Math.round((e.getX() - x_0) / (k));
            int row = (int) Math.round((e.getY() - y_0) / (k));

            if (data[row][column] == 0) {

                drawChess(row, column, color);    //画棋子



                try (DatagramSocket socket = new DatagramSocket(0)) {
//                    socket.setSoTimeout(5000);
                    Message msg = new Message();
                    msg.setFromPlayer(competition.getLocalPlayer());
                    msg.setToPlayer(competition.getRemotePlayer());
                    msg.setMsgType(6);
                    msg.setContent(new Point(column, row, color, ClientConfig.ACTION_TYPE_ADD));
                    byte[] msgBytes = Message.convertToBytes(msg);
                    DatagramPacket pout = new DatagramPacket(msgBytes, msgBytes.length,
                            ClientConfig.SERVER_ADDR);
                    socket.send(pout);
                    setMouseTransparent(true);

                } catch (Exception ex) {
                    // TODO: handle exception
                    ex.printStackTrace();
                }
                //color= color==1?2:1;//变换棋子颜色
                
                if (Judgement.judge(data) == color) {
                        competition.setResult(color);
                        setMouseTransparent(true);
                }
            } else {
                Chess5Utils.showAlert("该位置已下子");
            }
        } else {
            //System.out.println("click");
        }
    }

    /**
     * 1. 清除棋盘上所有棋子,
     * 2. 同时将数组data的所有元素值重置为0,
     */
    public void clear() {
        //只移除棋子,在这里不能用getChildren().clear(),否则会将棋盘线也清除
        getChildren().removeIf(shape -> (shape instanceof Circle));
        //将数组data的所有元素值重置为0
        data = new int[N + 1][N + 1];
    }
}

棋盘判断

Judgement.java


public class Judgement {
	/** 连续多少子算赢 */
	public static int MAX = 5; 
	/**
	 * 根据棋盘状态评判胜负。
	 * 若水平、垂直、斜线或反斜线4个方向中,存在连续MAX个相同颜色的棋子,则胜负已分!
	 * @param data 棋盘状态(二维数组),0无子,1黑子,2白子
	 * @return 返回棋局评判,0胜负未分,1黑胜,2白胜
	 */
	public static int judge(int[][] data){
		int j1 = hLine(data);
		if(j1>0) return j1;
		
		int j2 = vLine(data);
		if(j2>0) return j2;
		
		int j3 = xLine(data);
		if(j3>0) return j3;
		
		int j4 = rxLine(data);
		if(j4>0) return j4;
		return 0;
	}
	/** 
	 * 水平方向的胜负判断 
	 * @param data 棋盘状态(二维数组),0无子,1黑子,2白子
	 * @return 返回棋局评判,0尚无胜负,1黑胜,2白胜
	 */
	private static int hLine(int[][] data){
		int black=0,white=0;
		for(int i=0; i<data.length; i++){
			black=0; white=0;
			for(int j=0; j<data[i].length; j++){
				if(data[i][j]==1){
					black++;
					white = 0;
				}
				else if(data[i][j]==2){
					white++;
					black = 0;
				}else{
					black = white = 0;
				}
				if(black>=MAX) return 1;
				if(white>=MAX) return 2;
			}			
		}
		return 0;
	}	
	/** 
	 * 垂直方向的胜负判断 
 	 * @param data 棋盘状态(二维数组),0无子,1黑子,2白子
	 * @return 返回棋局评判,0尚无胜负,1黑胜,2白胜
	 */
	private static int vLine(int[][] data){
		int black=0,white=0;
		for(int i=0; i<data.length; i++){
			black=0; white=0;
			for(int j=0; j<data[i].length; j++){
				if(data[j][i]==1){
					black++;
					white = 0;
				}
				else if(data[j][i]==2){
					white++;
					black = 0;
				}else{
					black = white = 0;
				}
				if(black>=MAX) return 1;
				if(white>=MAX) return 2;
			}			
		}
		return 0;
	}
	/** 
	 * 斜线(右上-左下)方向 
	 * 同一条线上,x+y等于常数(规律为0到N+N)。
	 * @param data 棋盘状态(二维数组),0无子,1黑子,2白子
	 * @return 返回棋局评判,0尚无胜负,1黑胜,2白胜
	 */
	private static int xLine(int[][] data){
		int black=0,white=0;
		//Bug: sum<=data.length => sum<=data.length*2-2
		for(int sum=0; sum<=data.length*2-2; sum++){
			black=0; white=0;
			for(int i=0; i<=sum; i++) {//Bug: i<sum => i<=sum
				int j = sum - i;
				if(i>=data.length || i<0) continue;
				if(j>=data.length || j<0) continue;				
				if(data[i][j]==1){
					black++;
					white = 0;
				}
				else if(data[i][j]==2){
					white++;
					black = 0;
				}else{
					black = white = 0;
				}
				if(black>=MAX) return 1;
				if(white>=MAX) return 2;
			}			
		}
		return 0;
	}
	/** 
	 * 反斜线(左上-右下)方向 
	 * 同一条线上,x-y等于常数(规律为从负N-1到正N-1)
	 * @param data 棋盘状态(二维数组),0无子,1黑子,2白子
	 * @return 返回棋局评判,0尚无胜负,1黑胜,2白胜
	 */
	private static int rxLine(int[][] data){
		int black=0,white=0;
		for(int sub=-(data.length-1); sub<=data.length-1; sub++){
			black=0; white=0;
			for(int i=0; i<data.length; i++) {
				int j = i - sub;
				if(i>=data.length || i<0) continue;
				if(j>=data.length || j<0) continue;
				if(data[i][j]==1){
					black++;
					white = 0;
				}
				else if(data[i][j]==2){
					white++; //Bug: black++ => white++
					black = 0;
				}else{
					black = white = 0;
				}
				if(black>=MAX) return 1;
				if(white>=MAX) return 2;
			}			
		}
		return 0;
	}
}

比赛信息配置

Competition.java

public class Competition {
	Player localPlayer, remotePlayer;
	int[][]data;
	int result;
	public Player getLocalPlayer() {
		return localPlayer;
	}
	public void setLocalPlayer(Player localPlayer) {
		this.localPlayer = localPlayer;
	}
	public Player getRemotePlayer() {
		return remotePlayer;
	}
	public void setRemotePlayer(Player remotePlayer) {
		this.remotePlayer = remotePlayer;
	}
	public int[][] getData() {
		return data;
	}
	public void setData(int[][] data) {
		this.data = data;
	}
	public int getResult() {
		return result;
	}
	public void setResult(int result) {
		this.result = result;
	}

}

服务器及客户端的多线程

服务器和客户端的多线程就不在这里展示了,避免文章过长。

源代码

源代码不免费喔,需要的小伙伴请私信我。

java网络五子棋 下面的源代码分为4个文件; chessClient.java:客户端主程序。 chessInterface.java:客户端的界面。 chessPad.java:棋盘的绘制。 chessServer.java:服务器端。 可同时容纳50个人同时在线下棋,聊天。 没有加上详细注释,不过绝对可以运行,j2sdk1.4下通过。 /********************************************************************************************* 1.chessClient.java **********************************************************************************************/ import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; import java.util.*; class clientThread extends Thread { chessClient chessclient; clientThread(chessClient chessclient) { this.chessclient=chessclient; } public void acceptMessage(String recMessage) { if(recMessage.startsWith("/userlist ")) { StringTokenizer userToken=new StringTokenizer(recMessage," "); int userNumber=0; chessclient.userpad.userList.removeAll(); chessclient.inputpad.userChoice.removeAll(); chessclient.inputpad.userChoice.addItem("所有人"); while(userToken.hasMoreTokens()) { String user=(String)userToken.nextToken(" "); if(userNumber>0 && !user.startsWith("[inchess]")) { chessclient.userpad.userList.add(user); chessclient.inputpad.userChoice.addItem(user); } userNumber++; } chessclient.inputpad.userChoice.select("所有人"); } else if(recMessage.startsWith("/yourname ")) { chessclient.chessClientName=recMessage.substring(10); chessclient.setTitle("Java五子棋客户端 "+"用户名:"+chessclient.chessClientName); } else if(recMessage.equals("/reject")) { try { chessclient.chesspad.statusText.setText("不能加入游戏"); chessclient.controlpad.cancelGameButton.setEnabled(false); chessclient.controlpad.joinGameButton.setEnabled(true); chessclient.controlpad.creatGameButton.setEnabled(true); } catch(Exception ef) { chessclient.chatpad.chatLineArea.setText("chessclient.chesspad.chessSocket.close无法关闭"); } chessclient.controlpad.joinGameButton.setEnabled(true); } else if(recMessage.startsWith("/peer ")) { chessclient.chesspad.chessPeerName=recMessage.substring(6); if(chessclient.isServer) { chessclient.chesspad.chessColor=1; chessclient.chesspad.isMouseEnabled=true; chessclient.chesspad.statusText.setText("请黑棋下子"); } else if(chessclient.isClient) { chessclient.chesspad.chessColor=-1; chessclient.chesspad.statusText.setText("已加入游戏,等待对方下子..."); } } else if(recMessage.equals("/youwin")) { chessclient.isOnChess=false; chessclient.chesspad.chessVictory(chessclient.chesspad.chessColor); chessclient.chesspad.statusText.setText("对方退出,请点放弃游戏退出连接"); chessclient.chesspad.isMouseEnabled=false; } else if(recMessage.equals("/OK")) { ……………………………………………………………………………………catch(Exception ee) { } } System.exit(0); } public void windowActivated(WindowEvent ea) { } }); add(westPanel,BorderLayout.WEST); add(centerPanel,BorderLayout.CENTER); add(southPanel,BorderLayout.SOUTH); pack(); setSize(670,548); setVisible(true); setResizable(false); validate(); } public boolean connectServer(String serverIP,int serverPort) throws Exception { try { chatSocket=new Socket(serverIP,serverPort); in=new DataInputStream(chatSocket.getInputStream()); out=new DataOutputStream(chatSocket.getOutputStream()); clientThread clientthread=new clientThread(this); clientthread.start(); isOnChat=true; return true; } catch(IOException ex) { chatpad.chatLineArea.setText("chessClient:connectServer:无法连接,建议重新启动程序 \n"); } return false; } public void actionPerformed(ActionEvent e) { if(e.getSource()==controlpad.connectButton) { host=chesspad.host=controlpad.inputIP.getText(); try { if(connectServer(host,port)) { chatpad.chatLineArea.setText(""); controlpad.connectButton.setEnabled(false); controlpad.creatGameButton.setEnabled(true); controlpad.joinGameButton.setEnabled(true); chesspad.statusText.setText("连接成功,请创建游戏或加入游戏"); } } catch(Exception ei) { chatpad.chatLineArea.setText("controlpad.connectButton:无法连接,建议重新启动程序 \n"); } } if(e.getSource()==controlpad.exitGameButton) { if(isOnChat) { try { chatSocket.close(); } catch(Exception ed) { } } if(isOnChess || isGameConnected) { try { chesspad.chessSocket.close(); } catch(Exception ee) { } } System.exit(0); } if(e.getSource()==controlpad.joinGameButton) { String selectedUser=userpad.userList.getSelectedItem(); if(selectedUser==null || selectedUser.startsWith("[inchess]") || selectedUser.equals(chessClientName)) { chesspad.statusText.setText("必须先选定一个有效用户"); } else { try { if(!isGameConnected) { if(chesspad.connectServer(chesspad.host,chesspad.port)) { isGameConnected=true; isOnChess=true; isClient=true; controlpad.creatGameButton.setEnabled(false); controlpad.joinGameButton.setEnabled(false); controlpad.cancelGameButton.setEnabled(true); chesspad.chessthread.sendMessage("/joingame "+userpad.userList.getSelectedItem()+" "+chessClientName); } } else { isOnChess=true; isClient=true; controlpad.creatGameButton.setEnabled(false); controlpad.joinGameButton.setEnabled(false); controlpad.cancelGameButton.setEnabled(true); chesspad.chessthread.sendMessage("/joingame "+userpad.userList.getSelectedItem()+" "+chessClientName); } } catch(Exception ee) { isGameConnected=false; isOnChess=false; isClient=false; controlpad.creatGameButton.setEnabled(true); controlpad.joinGameButton.setEnabled(true); controlpad.cancelGameButton.setEnabled(false); chatpad.chatLineArea.setText("chesspad.connectServer无法连接 \n"+ee); } } } if(e.getSource()==controlpad.creatGameButton) { try { if(!isGameConnected) { if(chesspad.connectServer(chesspad.host,chesspad.port)) { isGameConnected=true; isOnChess=true; isServer=true; controlpad.creatGameButton.setEnabled(false); controlpad.joinGameButton.setEnabled(false); controlpad.cancelGameButton.setEnabled(true); chesspad.chessthread.sendMessage("/creatgame "+"[inchess]"+chessClientName); } } else { isOnChess=true; isServer=true; controlpad.creatGameButton.setEnabled(false); controlpad.joinGameButton.setEnabled(false); controlpad.cancelGameButton.setEnabled(true); chesspad.chessthread.sendMessage("/creatgame "+"[inchess]"+chessClientName); } } catch(Exception ec) { isGameConnected=false; isOnChess=false; isServer=false; controlpad.creatGameButton.setEnabled(true); controlpad.joinGameButton.setEnabled(true); controlpad.cancelGameButton.setEnabled(false); ec.printStackTrace(); chatpad.chatLineArea.setText("chesspad.connectServer无法连接 \n"+ec); } } if(e.getSource()==controlpad.cancelGameButton) { if(isOnChess) { chesspad.chessthread.sendMessage("/giveup "+chessClientName); chesspad.chessVictory(-1*chesspad.chessColor); controlpad.creatGameButton.setEnabled(true); controlpad.joinGameButton.setEnabled(true); controlpad.cancelGameButton.setEnabled(false); chesspad.statusText.setText("请建立游戏或者加入游戏"); } if(!isOnChess) { controlpad.creatGameButton.setEnabled(true); controlpad.joinGameButton.setEnabled(true); controlpad.cancelGameButton.setEnabled(false); chesspad.statusText.setText("请建立游戏或者加入游戏"); } isClient=isServer=false; } } public void keyPressed(KeyEvent e) { TextField inputWords=(TextField)e.getSource(); if(e.getKeyCode()==KeyEvent.VK_ENTER) { if(inputpad.userChoice.getSelectedItem().equals("所有人")) { try { out.writeUTF(inputWords.getText()); inputWords.setText(""); } catch(Exception ea) { chatpad.chatLineArea.setText("chessClient:KeyPressed无法连接,建议重新连接 \n"); userpad.userList.removeAll(); inputpad.userChoice.removeAll(); inputWords.setText(""); controlpad.connectButton.setEnabled(true); } } else { try { out.writeUTF("/"+inputpad.userChoice.getSelectedItem()+" "+inputWords.getText()); inputWords.setText(""); } catch(Exception ea) { chatpad.chatLineArea.setText("chessClient:KeyPressed无法连接,建议重新连接 \n"); userpad.userList.removeAll(); inputpad.userChoice.removeAll(); inputWords.setText(""); controlpad.connectButton.setEnabled(true); } } } } public void keyTyped(KeyEvent e) { } public void keyReleased(KeyEvent e) { } public static void main(String args[]) { chessClient chessClient=new chessClient(); } } /****************************************************************************************** 下面是:chessInteface.java ******************************************************************************************/ import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; class userPad extends Panel { List userList=new List(10); userPad() { setLayout(new BorderLayout()); for(int i=0;i<50;i++) { userList.add(i+"."+"没有用户"); } add(userList,BorderLayout.CENTER); } } class chatPad extends Panel { TextArea chatLineArea=new TextArea("",18,30,TextArea.SCROLLBARS_VERTICAL_ONLY); chatPad() { setLayout(new BorderLayout()); add(chatLineArea,BorderLayout.CENTER); } } class controlPad extends Panel { Label IPlabel=new Label("IP",Label.LEFT); TextField inputIP=new TextField("localhost",10); Button connectButton=new Button("连接主机"); Button creatGameButton=new Button("建立游戏"); Button joinGameButton=new Button("加入游戏"); Button cancelGameButton=new Button("放弃游戏"); Button exitGameButton=new Button("关闭程序"); controlPad() { setLayout(new FlowLayout(FlowLayout.LEFT)); setBackground(Color.pink); add(IPlabel); add(inputIP); add(connectButton); add(creatGameButton); add(joinGameButton); add(cancelGameButton); add(exitGameButton); } } class inputPad extends Panel { TextField inputWords=new TextField("",40); Choice userChoice=new Choice(); inputPad() { setLayout(new FlowLayout(FlowLayout.LEFT)); for(int i=0;i=1 && chessOptNum<=3) { chessOpt[chessOptNum-1]=chessToken; } chessOptNum++; } chesspad.netChessPaint(Integer.parseInt(chessOpt[0]),Integer.parseInt(chessOpt[1]),Integer.parseInt(chessOpt[2])); } else if(recMessage.startsWith("/yourname ")) { chesspad.chessSelfName=recMessage.substring(10); } else if(recMessage.equals("/error")) { chesspad.statusText.setText("错误:没有这个用户,请退出程序,重新加入"); } else { //System.out.println(recMessage); } } public void run() { String message=""; try { while(true) { message=chesspad.inData.readUTF(); acceptMessage(message); } } catch(IOException es) { } } } class chessPad extends Panel implements MouseListener,ActionListener { int chessPoint_x=-1,chessPoint_y=-1,chessColor=1; int chessBlack_x[]=new int[200]; int chessBlack_y[]=new int[200]; int chessWhite_x[]=new int[200]; int chessWhite_y[]=new int[200]; int chessBlackCount=0,chessWhiteCount=0; int chessBlackWin=0,chessWhiteWin=0; boolean isMouseEnabled=false,isWin=false,isInGame=false; TextField statusText=new TextField("请先连接服务器"); Socket chessSocket; DataInputStream inData; DataOutputStream outData; String chessSelfName=null; String chessPeerName=null; String host=null; int port=4331; chessThread chessthread=new chessThread(this); chessPad() { setSize(440,440); setLayout(null); setBackground(Color.pink); addMouseListener(this); add(statusText); statusText.setBounds(40,5,360,24); statusText.setEditable(false); } public boolean connectServer(String ServerIP,int ServerPort) throws Exception { try { chessSocket=new Socket(ServerIP,ServerPort); inData=new DataInputStream(chessSocket.getInputStream()); outData=new DataOutputStream(chessSocket.getOutputStream()); chessthread.start(); return true; } catch(IOException ex) { statusText.setText("chessPad:connectServer:无法连接 \n"); } return false; } public void chessVictory(int chessColorWin) { this.removeAll(); for(int i=0;i<=chessBlackCount;i++) { chessBlack_x[i]=0; chessBlack_y[i]=0; } for(int i=0;i<=chessWhiteCount;i++) { chessWhite_x[i]=0; chessWhite_y[i]=0; } chessBlackCount=0; chessWhiteCount=0; add(statusText); statusText.setBounds(40,5,360,24); if(chessColorWin==1) { chessBlackWin++; statusText.setText("黑棋胜,黑:白为"+chessBlackWin+":"+chessWhiteWin+",重新开局,等待白棋下子..."); } else if(chessColorWin==-1) { chessWhiteWin++; statusText.setText("白棋胜,黑:白为"+chessBlackWin+":"+chessWhiteWin+",重新开局,等待黑棋下子..."); } } public void getLocation(int a,int b,int color) { if(color==1) { chessBlack_x[chessBlackCount]=a*20; chessBlack_y[chessBlackCount]=b*20; chessBlackCount++; } else if(color==-1) { chessWhite_x[chessWhiteCount]=a*20; chessWhite_y[chessWhiteCount]=b*20; chessWhiteCount++; } } public boolean checkWin(int a,int b,int checkColor) { int step=1,chessLink=1,chessLinkTest=1,chessCompare=0; if(checkColor==1) { chessLink=1; for(step=1;step<=4;step++) { for(chessCompare=0;chessCompare<=chessBlackCount;chessCompare++) { if(((a+step)*20==chessBlack_x[chessCompare]) && ((b*20)==chessBlack_y[chessCompare])) { chessLink=chessLink+1; if(chessLink==5) { return(true); } } } if(chessLink==(chessLinkTest+1)) chessLinkTest++; else break; } for(step=1;step<=4;step++) { for(chessCompare=0;chessCompare<=chessBlackCount;chessCompare++) { if(((a-step)*20==chessBlack_x[chessCompare]) && (b*20==chessBlack_y[chessCompare])) { chessLink++; if(chessLink==5) { return(true); } } } if(chessLink==(chessLinkTest+1)) chessLinkTest++; else break; } chessLink=1; chessLinkTest=1; for(step=1;step<=4;step++) { for(chessCompare=0;chessCompare<=chessBlackCount;chessCompare++) { if((a*20==chessBlack_x[chessCompare]) && ((b+step)*20==chessBlack_y[chessCompare])) { chessLink++; if(chessLink==5) { return(true); } } } if(chessLink==(chessLinkTest+1)) chessLinkTest++; else break; } for(step=1;step<=4;step++) { for(chessCompare=0;chessCompare<=chessBlackCount;chessCompare++) { if((a*20==chessBlack_x[chessCompare]) && ((b-step)*20==chessBlack_y[chessCompare])) { chessLink++; if(chessLink==5) { return(true); } } } if(chessLink==(chessLinkTest+1)) chessLinkTest++; else break; } chessLink=1; chessLinkTest=1; for(step=1;step<=4;step++) { for(chessCompare=0;chessCompare<=chessBlackCount;chessCompare++) { if(((a-step)*20==chessBlack_x[chessCompare]) && ((b+step)*20==chessBlack_y[chessCompare])) { chessLink++; if(chessLink==5) { return(true); } } } if(chessLink==(chessLinkTest+1)) chessLinkTest++; else break; } for(step=1;step<=4;step++) { for(chessCompare=0;chessCompare<=chessBlackCount;chessCompare++) { if(((a+step)*20==chessBlack_x[chessCompare]) && ((b-step)*20==chessBlack_y[chessCompare])) { chessLink++; if(chessLink==5) { return(true); } } } if(chessLink==(chessLinkTest+1)) chessLinkTest++; else break; } chessLink=1; chessLinkTest=1; for(step=1;step<=4;step++) { for(chessCompare=0;chessCompare<=chessBlackCount;chessCompare++) { if(((a+step)*20==chessBlack_x[chessCompare]) && ((b+step)*20==chessBlack_y[chessCompare])) { chessLink++; if(chessLink==5) { return(true); } } } if(chessLink==(chessLinkTest+1)) chessLinkTest++; else break; } for(step=1;step<=4;step++) { for(chessCompare=0;chessCompare<=chessBlackCount;chessCompare++) { if(((a-step)*20==chessBlack_x[chessCompare]) && ((b-step)*20==chessBlack_y[chessCompare])) { chessLink++; if(chessLink==5) { return(true); } }
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值