• 请不要在回答技术问题时复制粘贴 AI 生成的内容
iamniconico
V2EX  ›  程序员

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

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

    ……

    ……

    干,我特么输了。

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

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

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

    当然还有一些未知的并发问题和安全问题,之后会加强优化
    iamniconico
    iamniconico
    OP
    Nov 7, 2018
    89
    @q397064399 是的,应用体积太膨胀了,很多公司都自研框架,当然我也有一套
    https://github.com/ainilili/no-framework
    q397064399
    q397064399
    Nov 7, 2018
    90
    @iamniconico #89 还有目前我都没跑起来你那个程序. 把打包上传到 maven 的跟使用的 隔离开来吧 或者写个打包运行的描述也好.
    susucoolsama
    susucoolsama
    Nov 7, 2018
    91
    lei 了,想法不错啊,有木有智障对手的设定。
    iamniconico
    iamniconico
    OP
    Nov 7, 2018 via Android
    92
    @q397064399 不好意思,给你发个 demo 地址
    https://gitee.com/ainilili/CoffeeTime
    iamniconico
    iamniconico
    OP
    Nov 7, 2018 via Android
    93
    @wsstest 已更新,看附言<(_ _)>
    dinjufen
    dinjufen
    Nov 7, 2018
    94
    看完了我想写一个 GUI 的斗地主,但感觉好难
    iamniconico
    iamniconico
    OP
    Nov 7, 2018 via Android
    95
    @susucoolsama 说出你的想法
    waruqi
    waruqi
    Nov 7, 2018 via Android
    96
    纯字符?还是用 tui?
    iamniconico
    iamniconico
    OP
    Nov 7, 2018
    97
    @waruqi 纯文字
    mseasons
    mseasons
    Nov 7, 2018
    98
    有意思,我去用 Python3 弄一个
    lexuskingxx
    lexuskingxx
    Nov 7, 2018
    99
    牛 13 了
    iamniconico
    iamniconico
    OP
    Nov 7, 2018 via Android
    100
    @mseasons 我准备将服务端做成通用的,以后你可以考虑用 py 写客户端<(_ _)>
    1  2  
    ❮ ❯
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   3061 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 170ms · UTC 04:32 · PVG 12:32 · LAX 20:32 · JFK 23:32
    ♥ Do have faith in what you're doing.