闲来无事,写一个命令行版的斗地主 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
请不要在回答技术问题时复制粘贴 AI 生成的内容
iamniconico

闲来无事,写一个命令行版的斗地主

  •  3
     
  •   iamniconico Nov 6, 2018 13719 views
    This topic creaed in 2729 days ago, the information mentioned may be changed or developed.

    我将之命名为 ratel,对,没错,平头哥,就是这么霸气(怂

    在发这篇主题的时候,ratel 还在开发的最后阶段,已经完成了基本的交互和游戏环节,有待优化,这里放出技术栈:

    • 平台:Java
    • 网络包:netty 4.x
    • 通讯协议:TCP/IP
    • 编解码:粗暴的 jvm 字节码

    项目地址:https://github.com/ainilili/ratel

    整个流程不难,首先,我需要将客户端和服务端搭起来,netty 提供着简洁的 api,可以快速的部署服务端和客户端,所以这个环节没有任何难度!一个简单的结构图如下:

    通讯这一块搞定,接下来要思考的问题就是如何进行互动,这个问题将会引发出更深层的问题?

    • 1、服务端如何存储客户端信息
    • 2、服务端如何识别客户端
    • 3、Poker 出牌的操作怎么通过命令行完成
    • 4、Poker 的类型鉴定与比较
    • 5、命令行如何显示客户端的回合计时
    • 6、客户端掉线
    • 7、其余未知问题

    作为一个正在开发的项目,更多的难以解决的疑难杂症还等待着我去发现,本帖也将持续更新至 ratel 完结。

    针对于以上问题的思考之后,我决定将数据持久化在内存中(要考虑 jvm 会不会 gc 掉,所以这里使用 final 修饰 static ),服务端抽象出Room - 游戏房间,ClientSide - 客户端信息Poker - 结构这三个最主要的数据结构,网路逐渐变得复杂起来

    详细结构如下

    Room{ Client{ Poker{ int 唯一标识 int 唯一标识 int 大小 int 状态 int 房间标识 int 花色 map 客户端字典 str 昵称 } list 客户端列表 list 手持牌 int 地主标识 int 状态 int 地主牌 int 类型(农民|地主) struct 上次出手的信息 client 下手 int 上次出手人 client 上手 } } 

    每当一个客户端连接时,将会构造一个 Client 对象,分配一个唯一的标识供服务端识别,Room 由客户端建立,并且在此基础之上,其他客户端可以加入已创建且状态未满的房间,当游戏开始后,将会为房间中的所有客户端派发 Poker。

    这种流程看似可行,按照这种模式,ratel 由 0 走到了 1

    但 ratel 的重点并不止于此,各种问题(网络,安全,用户体验等)还有待解决。

    ratel 开发完毕之后,大家工作之余偷偷开心一下,命令行下划划水。

    Supplement 1    Nov 7, 2018

    根据大家的建议,对ratel的出牌方式做了一些修改,以及新增客户端退出或者异常断开的应对方案。

    新的出牌规则: 3 -> 3 4 -> 4 5 -> 5 6 -> 6 7 -> 7 8 -> 8 9 -> 9 10 -> T/t/0 J -> J/j Q -> Q/q K -> K/k A -> A/a/1 2 -> 2 S(小王)-> S/s X(大王)-> X/x

    例如如下牌:

    Poker: ┌──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐ │3 |5 |6 |6 |7 |8 |8 |9 |9 |9 |10|J |Q |Q |K |K |2 |2 |2 |X | │ | | | | | | | | | | | | | | | | | | | | └──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘ 

    出牌的输入是:

    56789 t jqk 

    则输出是:

    Poker: ┌──┐──┐──┐──┐──┐──┐──┐──┐──┐ │5 |6 |7 |8 |9 |10|J |Q |K | │ | | | | | | | | | └──┘──┘──┘──┘──┘──┘──┘──┘──┘ 

    56789 t jqk将会被解析成{'5','6','7','8','9','t','j','q','k'}并发往服务端进行命中判断及出牌

    最后上图

    Supplement 2    Nov 12, 2018
    107 replies    2019-01-14 15:39:11 +08:00
    1  2  
    cnit
        1
    cnit  
       Nov 6, 2018
    牛皮,我就会 9*9 乘法表
    liaojl
        2
    liaojl  
       Nov 6, 2018 via iPhone
    叫地主
    iamniconico
        3
    iamniconico  
    OP
       Nov 6, 2018 via Android
    @liaojl 我抢
    iamniconico
        4
    iamniconico  
    OP
       Nov 6, 2018 via Android
    大佬低调了,斗地主都是 javase 的知识
    Bigglesworth
        5
    Bigglesworth  
       Nov 6, 2018
    要不起
    hourann
        6
    hourann  
       Nov 6, 2018 via iPhone
    牛啊
    johnniang
        7
    johnniang  
       Nov 6, 2018 via Android
    厉害厉害
    richangfan
        8
    richangfan  
       Nov 6, 2018 via Android
    pass
    zaneenaz
        9
    zaneenaz  
       Nov 6, 2018 via Android
    快点啊等到花儿都谢了,,厉害。
    iamniconico
        10
    iamniconico  
    OP
       Nov 6, 2018 via Android
    四个二带俩王,我摊牌了
    lovefantasy
        11
    lovefantasy  
       Nov 7, 2018 via iPhone
    大佬啊
    syahd
        12
    syahd  
       Nov 7, 2018 via Android
    声音有不
    alakey1989
        13
    alakey1989  
       Nov 7, 2018
    膜拜老哥
    catinsides
        14
    catinsides  
       Nov 7, 2018
    自带 bgm 的主题
    sinv
        15
    sinv  
       Nov 7, 2018 via iPhone   1
    上次有一把,上家在要地主的过程超时了,应该是掉线了,根据规则他就托管了,我一看直接要了 3 分牌还不错,惊喜来了,下家一看直接放弃抵抗也托管了,然后就变成我斗俩机器人农民。

    ……

    ……

    干,我特么输了。

    被轰了三个炸弹,然后我自己还放了 4 个 A,3 个 2 加一个小鬼憋手里了……

    May725
        16
    May725  
       Nov 7, 2018 via iPhone
    哈哈,前两年也有在终端斗地主的想法,用 c 写了一半,就没继续下去了。加油,以后 v2 滑水又多了一种方式
    Cbdy
        17
    Cbdy  
       Nov 7, 2018 via Android
    o 家不是要把 jvm 序列化砍了吗?
    easylee
        18
    easylee  
       Nov 7, 2018 via Android
    有才!看到标题我还在想怎么显示牌呢。戳 star 去咯。
    iamniconico
        19
    iamniconico  
    OP
       Nov 7, 2018 via Android
    @Cbdy java10 不清楚,java8 还在
    iamniconico
        20
    iamniconico  
    OP
       Nov 7, 2018 via Android
    @whwq2012 想法不错,准备试试
    wikilike7
        22
    wikilike7  
       Nov 7, 2018
    @sinv 传说中的人打不过电脑,哈哈
    artandlol
        23
    artandlol  
       Nov 7, 2018
    什么时候出 releases
    hfc
        24
    hfc  
       Nov 7, 2018
    请问,你是在考虑涉及完大部分数据结构、逻辑等之后才开始开发的嘛?
    iamniconico
        25
    iamniconico  
    OP
       Nov 7, 2018
    @artandlol 预计近两周内
    simonguo
        26
    simonguo  
       Nov 7, 2018 via iPhone
    iamniconico
        27
    iamniconico  
    OP
       Nov 7, 2018
    @hfc 不全是,有些逻辑和数据结构的缺陷是在开发过程中发现的!
    baicheng10
        28
    baicheng10  
       Nov 7, 2018
    插眼
    loongwang
        29
    loongwang  
       Nov 7, 2018
    牛皮牛皮
    KgM4gLtF0shViDH3
        30
    KgM4gLtF0shViDH3  
       Nov 7, 2018 via iPhone
    花色怎么看啊
    iamniconico
        31
    iamniconico  
    OP
       Nov 7, 2018
    @Cbdy 看样子是准备要砍了,同时也准备给出弥补?
    > To replace the current serialization technology, a small serialization framework would be placed in the platform once records, the Java version of data classes, are supported. The framework could support a graph of records, and developers could plug in a serialization engine of their choice, supporting formats such as JSON or XML, enabling serialization of records in a safe way. But Reinhold cannot yet say which release of Java will have the records capability.
    iamniconico
        32
    iamniconico  
    OP
       Nov 7, 2018
    @bestkayle 看下最后一张图
    reticentfat
        33
    reticentfat  
       Nov 7, 2018
    出了请通知我
    CodingDoge
        34
    CodingDoge  
       Nov 7, 2018
    划水新境界
    zhang1215
        35
    zhang1215  
       Nov 7, 2018 via iPhone
    花式划水
    realkenshinji
        36
    realkenshinji  
       Nov 7, 2018
    没有 test ?我们除了 watch 和 star 你的项目,难道不能 contribute ??
    Cbdy
        37
    Cbdy  
       Nov 7, 2018
    @iamniconico
    估计是 JDK 官方出一个 JSON 库吧,类似 GSON 或者 FastXML 转正的感觉
    参考一下这个:JSR 374 Specification,https://javaee.github.io/jsonp/
    Daveedo
        38
    Daveedo  
       Nov 7, 2018
    加油鸭!
    iamniconico
        39
    iamniconico  
    OP
       Nov 7, 2018 via Android
    @realkenshinji 等 Beta 版本完毕
    iamniconico
        40
    iamniconico  
    OP
       Nov 7, 2018 via Android
    @Daveedo 感谢支持
    iamniconico
        41
    iamniconico  
    OP
       Nov 7, 2018
    @Cbdy json 固然好,我之前也考虑用之,不足的一点是 json 无法传递对象类型,接收方在不知道什么类型的情况下,只能转为 map 结构,数据处理起来不太方便,但是我之后还是会换一种编解码方式的,jvm serialization 局限性太高,影响 ratel client 向 python,shell 发展
    qwe61655
        42
    qwe61655  
       Nov 7, 2018 via iPhone
    收藏了,
    bullettrain1433
        43
    bullettrain1433  
       Nov 7, 2018
    等消息
    loveCoding
        44
    loveCoding  
       Nov 7, 2018
    @iamniconico #41 pb 序列化吧
    iamniconico
        45
    iamniconico  
    OP
       Nov 7, 2018
    ratel 不会让大家久等的
    iamniconico
        46
    iamniconico  
    OP
       Nov 7, 2018
    @loveCoding pb 好麻烦的,回头试试,不知道适不适合当前模型
    lrh3321
        47
    lrh3321  
       Nov 7, 2018
    star 了
    zclHIT
        48
    zclHIT  
       Nov 7, 2018
    star 了,坐等 beta test 和 release:)
    iamniconico
        49
    iamniconico  
    OP
       Nov 7, 2018
    @zclHIT 感谢支持
    tianlang1989
        50
    tianlang1989  
       Nov 7, 2018
    能不能不要有牌的样式 就纯数字就行了
    划水利器
    先 star 为敬
    iamniconico
        51
    iamniconico  
    OP
       Nov 7, 2018
    @tianlang1989 好主意,我会提供主题的修改入口的
    tigerZhang
        52
    tigerZhang  
       Nov 7, 2018
    输入 index ,有点蛋疼,能不能通过光标左右选牌
    mason961125
        53
    mason961125  
       Nov 7, 2018
    工作量严重不饱和!(滑稽
    leavan
        54
    leavan  
       Nov 7, 2018
    我觉得可以增加选牌的动态效果。比如输入 2,第二张牌就弹出来...比较直观。
    iamniconico
        55
    iamniconico  
    OP
       Nov 7, 2018 via Android
    @tigerZhang 命令行版的应该做不了,我会思考一下的
    iamniconico
        56
    iamniconico  
    OP
       Nov 7, 2018 via Android
    @leavan 优化时会改进一下选牌方案,不过弹出来有点不现实,可能需要 gui 的支持
    natforum
        57
    natforum  
       Nov 7, 2018   6
    cstj0505
        58
    cstj0505  
       Nov 7, 2018
    @iamniconico 对象类型作为属性放进去,反序列化先去拿到对象类型
    iamniconico
        59
    iamniconico  
    OP
       Nov 7, 2018 via Android
    @cstj0505 我也这样想过,准备换一种跨平台的方式,优化一下数据传输结构
    leavan
        60
    leavan  
       Nov 7, 2018
    @iamniconico 没有不现实吧,你就在字符界面里牌的顶端留一个空白行,弹出来的就把这张牌空白行放到底端就行了
    kulove
        61
    kulove  
       Nov 7, 2018
    直接输牌数字也行吧?比如对 2,是 2 2,三带一是,9 9 9 6.。
    iamniconico
        62
    iamniconico  
    OP
       Nov 7, 2018
    @leavan 命令行打印只能 append,不能 modify 之前已经输出的,所以做不到的
    crab
        63
    crab  
       Nov 7, 2018
    给阿姨倒杯卡布奇诺
    leavan
        64
    leavan  
       Nov 7, 2018
    最好能做一个光标,不需要鼠标,用类似 Vim 的操作模式,然后空格弹出或弹回某张牌,回车出牌,操作模式会简单很多。对这种精致的小项目很喜欢,已 star,不过不太喜欢这种交互性比较少的出牌方式,期待改进哈~
    iamniconico
        65
    iamniconico  
    OP
       Nov 7, 2018
    @kulove 主意不错,这样方便选取,感谢
    Skifary
        66
    Skifary  
       Nov 7, 2018
    @natforum 莫名其妙的笑到不停
    leavan
        67
    leavan  
       Nov 7, 2018
    @iamniconico 我记得是有方法的,你去搜一下某些进度条的实现方式...
    iamniconico
        68
    iamniconico  
    OP
       Nov 7, 2018
    @leavan 感谢,之后会扩展客户端至其他平台,可能 linux 的 shell 下就可以实现你说的
    iamniconico
        69
    iamniconico  
    OP
       Nov 7, 2018
    @crab 作者是男的,只是爱好动漫
    ID2333
        70
    ID2333  
       Nov 7, 2018
    脑洞真 6,想玩~
    NotNil1
        71
    NotNil1  
       Nov 7, 2018
    感觉做个下五子棋的会简单一点哈
    1847bell
        72
    1847bell  
       Nov 7, 2018
    我的,看得出来你确实很闲……
    NotNil1
        73
    NotNil1  
       Nov 7, 2018
    客户端代码怎么分发呢
    MicroPan
        74
    MicroPan  
       Nov 7, 2018
    666,前排关注~
    MrUser
        75
    MrUser  
       Nov 7, 2018
    出牌时直接输入要出的牌呗,程序给转成索引,输入 index 太难受了:1=3,3=5,5=6 ……快绕晕了都还怎么记牌
    realpg
        76
    realpg  
    PRO
       Nov 7, 2018
    @iamniconico #65
    其实直接输入牌字母也可以
    定义一下两个王是什么符号,比如 A 和 B
    然后 1(A)23456789XJQK
    问你出啥牌 直接输 111JJ
    有效避免图形界面摸鱼困难

    另外 提供老板键 一键终端变为编译界面
    iamniconico
        77
    iamniconico  
    OP
       Nov 7, 2018
    @MrUser 没问题,我也发现这个挺蛋疼的
    iamniconico
        78
    iamniconico  
    OP
       Nov 7, 2018
    @realpg 我再考虑 10 用什么字母代替,还是说用 0 ?
    realpg
        79
    realpg  
    PRO
       Nov 7, 2018
    @iamniconico #78
    用 X 比较好吧
    然后考虑用户习惯兼容个 A=1
    iamniconico
    80
    iamniconico  
    OP
       Nov 7, 2018
    3 4 5 6 7 8 9 T J Q K A 2 S X
    3 4 5 6 7 8 9 10 J Q K A 2 小王 大王
    单字母取消空格
    iamniconico
        81
    iamniconico  
    OP
       Nov 7, 2018
    @realpg 可以的,不过 X 我准备用来表示大王
    MrUser
        82
    MrUser  
       Nov 7, 2018
    大王大写 W,小王小写 w
    abmin521
        83
    abmin521  
       Nov 7, 2018
    前排预定
    Kirscheis
        84
    Kirscheis  
       Nov 7, 2018 via Android
    nb,插个眼
    wsstest
        85
    wsstest  
       Nov 7, 2018
    坐等,更新求艾特
    q397064399
        86
    q397064399  
       Nov 7, 2018
    现在搞个 Java 依赖是真的多,一下子 springboot 全家桶 全来了
    ginux
        87
    ginux  
       Nov 7, 2018
    服务端的高并发考虑是怎么处理的
    iamniconico
        88
    iamniconico  
    OP
       Nov 7, 2018
    @ginux
    高并发危险点主要在于加入房间这一块,不过也简单,对 status 加 volatile 修饰,处理事件时判断一下,创建房间的 id 分配采用 AtomicInteger 生成 id,客户端的 id 则直接采用 channel 的 socketAddress 在服务端的应用端口。

    当然还有一些未知的并发问题和安全问题,之后会加强优化
    iamniconico
        89
    iamniconico  
    OP
       Nov 7, 2018
    @q397064399 是的,应用体积太膨胀了,很多公司都自研框架,当然我也有一套
    https://github.com/ainilili/no-framework
    q397064399
        90
    q397064399  
       Nov 7, 2018
    @iamniconico #89 还有目前我都没跑起来你那个程序. 把打包上传到 maven 的跟使用的 隔离开来吧 或者写个打包运行的描述也好.
    susucoolsama
        91
    susucoolsama  
       Nov 7, 2018
    lei 了,想法不错啊,有木有智障对手的设定。
    iamniconico
        92
    iamniconico  
    OP
       Nov 7, 2018 via Android
    @q397064399 不好意思,给你发个 demo 地址
    https://gitee.com/ainilili/CoffeeTime
    iamniconico
        93
    iamniconico  
    OP
       Nov 7, 2018 via Android
    @wsstest 已更新,看附言<(_ _)>
    dinjufen
        94
    dinjufen  
       Nov 7, 2018
    看完了我想写一个 GUI 的斗地主,但感觉好难
    iamniconico
        95
    iamniconico  
    OP
       Nov 7, 2018 via Android
    @susucoolsama 说出你的想法
    waruqi
        96
    waruqi  
       Nov 7, 2018 via Android
    纯字符?还是用 tui?
    iamniconico
        97
    iamniconico  
    OP
       Nov 7, 2018
    @waruqi 纯文字
    mseasons
        98
    mseasons  
       Nov 7, 2018
    有意思,我去用 Python3 弄一个
    lexuskingxx
        99
    lexuskingxx  
       Nov 7, 2018
    牛 13 了
    iamniconico
        100
    iamniconico  
    OP
       Nov 7, 2018 via Android
    @mseasons 我准备将服务端做成通用的,以后你可以考虑用 py 写客户端<(_ _)>
    1  2  
    About     Help     Advertise     Blog     API     FAQ     Solana     1401 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 242ms UTC 17:10 PVG 01:10 LAX 10:10 JFK 13:10
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86