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

Java:五子棋游戏+聊天室[文末源代码]

  • Java:五子棋游戏+聊天室
    • 设计技术:
    • 游戏功能
    • 游戏展示
    • 数据库设计
      • 注册
        • 注册界面
        • 注册失败
        • 注册成功
      • 登录
        • 登录界面
        • 登录失败
        • 登陆成功
      • 游戏过程
        • 界面
        • 加入擂台
        • 主动挑战或接受挑战
        • 输赢判断和观战
        • 平局和投降
        • 保存棋盘和链接
        • 查看信息
      • 聊天室
        • 进入聊天室
        • 群聊
        • 私聊
        • 发送文件或图片
        • 离开聊天室
    • 服务端
      • 服务端的配置
      • 通信类Message的实现
      • Message类型说明
      • 封装玩家信息:
      • DataBase类的创建
      • 落子点的信息
    • 客户端
      • 客户端的配置
      • 五子棋盘
      • 棋盘判断
      • 比赛信息配置
    • 服务器及客户端的多线程
  • 源代码

Java:五子棋游戏+聊天室

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

设计技术:

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

游戏功能

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

(相关代码在底部)

游戏展示

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

数据库设计

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

技术交流:Java五子棋游戏+聊天室(文末源代码)_第1张图片

注册

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

注册界面

技术交流:Java五子棋游戏+聊天室(文末源代码)_第2张图片

注册失败

技术交流:Java五子棋游戏+聊天室(文末源代码)_第3张图片

注册成功

技术交流:Java五子棋游戏+聊天室(文末源代码)_第4张图片

登录

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

登录界面

技术交流:Java五子棋游戏+聊天室(文末源代码)_第5张图片

登录失败

技术交流:Java五子棋游戏+聊天室(文末源代码)_第6张图片
技术交流:Java五子棋游戏+聊天室(文末源代码)_第7张图片

登陆成功

技术交流:Java五子棋游戏+聊天室(文末源代码)_第8张图片

游戏过程

界面

技术交流:Java五子棋游戏+聊天室(文末源代码)_第9张图片

加入擂台

技术交流:Java五子棋游戏+聊天室(文末源代码)_第10张图片

主动挑战或接受挑战

技术交流:Java五子棋游戏+聊天室(文末源代码)_第11张图片

输赢判断和观战

技术交流:Java五子棋游戏+聊天室(文末源代码)_第12张图片

平局和投降

技术交流:Java五子棋游戏+聊天室(文末源代码)_第13张图片技术交流:Java五子棋游戏+聊天室(文末源代码)_第14张图片技术交流:Java五子棋游戏+聊天室(文末源代码)_第15张图片
技术交流:Java五子棋游戏+聊天室(文末源代码)_第16张图片

保存棋盘和链接

截取屏幕生成图片保存棋盘和txt文本。
后续可以读取txt获取当时的游戏棋盘布局,自行扩展。
技术交流:Java五子棋游戏+聊天室(文末源代码)_第17张图片技术交流:Java五子棋游戏+聊天室(文末源代码)_第18张图片

查看信息

技术交流:Java五子棋游戏+聊天室(文末源代码)_第19张图片

聊天室

进入聊天室

技术交流:Java五子棋游戏+聊天室(文末源代码)_第20张图片

群聊

技术交流:Java五子棋游戏+聊天室(文末源代码)_第21张图片

私聊

技术交流:Java五子棋游戏+聊天室(文末源代码)_第22张图片

发送文件或图片

技术交流:Java五子棋游戏+聊天室(文末源代码)_第23张图片

离开聊天室

技术交流:Java五子棋游戏+聊天室(文末源代码)_第24张图片

服务端

服务端的配置


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 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)