Java 在线纸牌游戏

Java TCP通信 FastJson 在线纸牌游戏

主要想法

  • 设计初衷:本作品名称叫做在线纸牌游戏。开发该作品的原因:在学习了JavaTCP与UDP网络编程的相关知识,以及对Java多线程知识比较感兴趣所以结合两者知识萌生了一个制作在线纸牌游戏的想法。
  • 该作品的主要功能是:第一,在线即时信息聊天,具体表现为在游戏开始之前,玩家进入了相应的房间之后,玩家可以跟同在房间内的玩家进行聊天。第二,纸牌的玩法,与斗地主的规则类似,只不过本游戏的地主是随机分配,且三名玩家的牌的数量相同,最先出完的玩家赢得游戏的胜利。
  • 主要用法:首先在云服务器上运行Server端,之后只要在本地终端或者java编辑器中运行Client端程序即可。游戏需要三名玩家在同一房间内才可以进行游戏。
  • 借鉴产品:斗地主
  • 创新点:
    1.采用TCP封装Send和Receive方法,在方法传输上具有稳定和即时的特点
    2.传输的信息封装以及解析采用了FastJson的数据序列化和反序列化方法。通过FastJson把程序中的Data对象转化为特定格式的Json字符串传输。其特点是有稳定性和速度极快。

概要设计

client:

在这里插入图片描述

Server:

在这里插入图片描述

人机交互:

在这里插入图片描述

核心代码部分

  • 牌型获取
/**
     * create by: shoutoudelanfanqie
     * description: 返回提供的牌的牌型。
     * 经过判断每一张牌是否属于正确的牌
     *    1张牌:PASS或者一张单牌
     *    2张牌:对子或者王炸
     *    3张牌:三个X
     *    4张牌:炸子或者三带一
     *    5张牌:单牌顺子或者三带一对
     *    6张牌:对子顺子
     *    7张牌:单牌顺子
     *    8张牌:对子顺子
     *    10张牌:对子顺子
     * create time: 2022/5/19 20:45
     * @param cardSeparated 已经从String分开的牌的集合体
     * @return java.lang.String
     */
    public static String getCardType(String[] cardSeparated){
        //如果自己没有这张牌那么直接返回错误的牌
        if(!isConfirmed(cardSeparated)){
            return WRONG_CARD;
        }

        int cardLength=cardSeparated.length;

        switch (cardLength) {
            case 1-> {
                if (cardSeparated[0].equals(PASS)) {
                    return PASS;
                } else {
                    return SINGLE;
                }
            }
            case 2-> {
                if (isSame(cardSeparated)) {
                    return PAIRS;
                } else if (cardSeparated[0].equals(BIG_KING)
                        && cardSeparated[1].equals(SMALL_KING)) {
                    return KING_BOMB;
                } else {
                    return WRONG_CARD;
                }
            }
            case 3-> {
                if (isSame(cardSeparated)) {
                    return THREES;
                } else {
                    return WRONG_CARD;
                }
            }
            case 4-> {
                if (isSame(cardSeparated)) {
                    return BOMB;
                } else if (isSame(cardSeparated, 1, 3)
                        && !cardSeparated[3].equals(SMALL_KING)
                        && !cardSeparated[3].equals(BIG_KING)) {
                    return THREE_WITH_SINGLE;
                } else {
                    return WRONG_CARD;
                }
            }
            case 5,7-> {
                if (isSame(cardSeparated, 1, 3)
                        && isSame(cardSeparated, 4, 5)) {
                    return THREE_WITH_PAIRS;
                } else if (isShunZi(cardSeparated, SINGLE_SHUN_ZI)) {
                    return SINGLE_SHUN_ZI;
                } else {
                    return WRONG_CARD;
                }
            }
            case 6,8-> {
                if (isShunZi(cardSeparated, SINGLE_SHUN_ZI)) {
                    return SINGLE_SHUN_ZI;
                } else if (isShunZi(cardSeparated, PAIRS_SHUN_ZI)) {
                    return PAIRS_SHUN_ZI;
                } else {
                    return WRONG_CARD;
                }
            }
            case 10-> {
                if (isShunZi(cardSeparated, PAIRS_SHUN_ZI)) {
                    return PAIRS_SHUN_ZI;
                }
            }
        }
        return WRONG_CARD;
    }
  • Send和Receive封装
/**
      * create by: shoutoudelanfanqie
      * description: 接受来自服务器信息的静态方法
      * create time: 2022/5/29 11:18
      */
    public static Data receive(){
        String msgReceived = null;
        try {
            msgReceived =dis.readUTF();
        } catch (IOException e) {
            System.out.println("数据接受异常");
        }
        Data data= JSONObject.parseObject(msgReceived,Data.class);

        return data;
    }


    /**
      * create by: shoutoudelanfanqie
      * description: 向服务器发送信息的方法
      * create time: 2022/5/29 11:19
      *
      * @param msgToBeSend 将要发送的信息
      */
    public static void send(Data msgToBeSend){

        if(msgToBeSend!=null){
            try {
                String msg=JSONObject.toJSONString(msgToBeSend);
                dos.writeUTF(msg);

                dos.flush();
            } catch (IOException e) {
                System.out.println("连接异常!");
            }
        }
    }
  • Server端的出牌提示逻辑
/**
      * @author: shoutoudelanfanqie
      * @description: 游戏开始,玩牌
      * @createtime: 2022/5/31 15:56
     */
    public void playCards() {
        while (gameIsStart) {
            //默认第二个玩家第一个出牌
            dataReceived = playerMap.get(secondPlayer).getTransmit().receive();
            if (dataReceived.getDataType().equals(Type.GAME_OVER)) {
                //如果出牌是结束信息,那么向所有人发送信息通知游戏已结束
                playerMap.get(secondPlayer).sendToOther(dataReceived, this.getPlayerMap());
                break;
            } else if (dataReceived.getDataType().equals(Type.CARD_PLAY)) {
                System.out.println("信息种类:" + dataReceived.getDataType() + "   房间号:" + this.roomNumber +
                                "   出牌人:" + dataReceived.getWhoSend() +
                                "   出牌类型:" + dataReceived.getCardType() + "   出牌内容:" + dataReceived.getDataText());
                //在服务端的后台输出出牌信息
                //如果是出牌信息
                dataReceived.setMyTurn(false);
                //按照顺序给另外两名玩家设定是否出牌
                playerMap.get(firstPlayer).getTransmit().send(dataReceived);
                //2号是地主先出牌,所以2号出完之后1号不出,3号出牌
                dataReceived.setMyTurn(true);
                playerMap.get(thirdPlayer).getTransmit().send(dataReceived);
            }


            dataReceived = playerMap.get(thirdPlayer).getTransmit().receive();
            if (dataReceived.getDataType().equals(Type.GAME_OVER)) {
                //如果出牌是结束信息,那么向所有人发送信息通知游戏已结束
                playerMap.get(secondPlayer).sendToOther(dataReceived, this.getPlayerMap());
                break;
            } else if (dataReceived.getDataType().equals(Type.CARD_PLAY)) {
                System.out.println("信息种类:" + dataReceived.getDataType() + "   房间号:" + this.roomNumber +
                        "   出牌人:" + dataReceived.getWhoSend() +
                        "   出牌类型:" + dataReceived.getCardType() + "   出牌内容:" + dataReceived.getDataText());
                //在服务端的后台输出出牌信息
                dataReceived.setMyTurn(false);
                playerMap.get(secondPlayer).getTransmit().send(dataReceived);
                dataReceived.setMyTurn(true);
                playerMap.get(firstPlayer).getTransmit().send(dataReceived);
            }


            dataReceived = playerMap.get(firstPlayer).getTransmit().receive();
            if (dataReceived.getDataType().equals(Type.GAME_OVER)) {
                //如果出牌是结束信息,那么向所有人发送信息通知游戏已结束
                playerMap.get(secondPlayer).sendToOther(dataReceived, this.getPlayerMap());
                break;
            } else if (dataReceived.getDataType().equals(Type.CARD_PLAY)) {
                System.out.println("信息种类:" + dataReceived.getDataType() + "   房间号:" + this.roomNumber +
                        "   出牌人:" + dataReceived.getWhoSend() +
                        "   出牌类型:" + dataReceived.getCardType() + "   出牌内容:" + dataReceived.getDataText());
                //在服务端的后台输出出牌信息
                dataReceived.setMyTurn(true);
                playerMap.get(secondPlayer).getTransmit().send(dataReceived);
                dataReceived.setMyTurn(false);
                playerMap.get(thirdPlayer).getTransmit().send(dataReceived);
            }
        }
    }

主要测试

  • 运行速度上:由TCP以及FastJson的保证,在信息传输和展示上速度快且准确率高。但是在一些特定场景,比如说牌的展示上,为了获得一些动态的效果,采用了sleep
  • 安全性: 安全性较低,在一些不确定场景会出现线程安全问题,因为本人对线程类知识匮乏,所以在一些特定场景下存在较多线程安全的问题。
  • 部署方便性:部署较为方便合理,只需要在服务器上运行Server程序,之后在本地终端上运行Client程序即可
  • 可用性:房间复用性较差(作者尝试解决但是未果)。房间只能一次性使用,即一个服务端的开启最多支持五轮游戏。

更多图片

在这里插入图片描述

使用方法

  • 第一步:在java编辑器或者安装了jdk的设备终端上运行Server.jar程序
    在这里插入图片描述

  • 第二步:在终端运行Client.jar
    在这里插入图片描述

  • 第三步:根据提示进行游戏即可
    在这里插入图片描述

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值