V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iamniconico
V2EX  ›  程序员

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

  •  3
     
  •   iamniconico · 2018-11-06 21:50:10 +08:00 · 12099 次点击
    这是一个创建于 2210 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我将之命名为 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 开发完毕之后,大家工作之余偷偷开心一下,命令行下划划水。

    第 1 条附言  ·  2018-11-07 18:45:20 +08:00

    根据大家的建议,对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'}并发往服务端进行命中判断及出牌

    最后上图

    第 2 条附言  ·  2018-11-12 20:44:41 +08:00
    107 条回复    2019-01-14 15:39:11 +08:00
    1  2  
    cnit
        1
    cnit  
       2018-11-06 22:24:00 +08:00
    牛皮,我就会 9*9 乘法表
    liaojl
        2
    liaojl  
       2018-11-06 22:55:23 +08:00 via iPhone
    叫地主
    iamniconico
        3
    iamniconico  
    OP
       2018-11-06 23:28:16 +08:00 via Android
    @liaojl 我抢
    iamniconico
        4
    iamniconico  
    OP
       2018-11-06 23:29:13 +08:00 via Android
    大佬低调了,斗地主都是 javase 的知识
    Bigglesworth
        5
    Bigglesworth  
       2018-11-06 23:33:46 +08:00
    要不起
    hourann
        6
    hourann  
       2018-11-06 23:36:27 +08:00 via iPhone
    牛啊😂
    johnniang
        7
    johnniang  
       2018-11-06 23:36:55 +08:00 via Android
    厉害厉害
    richangfan
        8
    richangfan  
       2018-11-06 23:38:37 +08:00 via Android
    pass
    zaneenaz
        9
    zaneenaz  
       2018-11-06 23:40:52 +08:00 via Android
    快点啊等到花儿都谢了,😄,厉害。
    iamniconico
        10
    iamniconico  
    OP
       2018-11-06 23:59:11 +08:00 via Android
    四个二带俩王,我摊牌了😎
    lovefantasy
        11
    lovefantasy  
       2018-11-07 00:08:34 +08:00 via iPhone
    大佬啊
    whwq2012
        12
    whwq2012  
       2018-11-07 00:11:28 +08:00 via Android
    声音有不
    alakey1989
        13
    alakey1989  
       2018-11-07 00:30:43 +08:00
    膜拜老哥
    catinsides
        14
    catinsides  
       2018-11-07 00:39:33 +08:00
    自带 bgm 的主题
    sinv
        15
    sinv  
       2018-11-07 01:07:06 +08:00 via iPhone   ❤️ 1
    上次有一把,上家在要地主的过程超时了,应该是掉线了,根据规则他就托管了,我一看直接要了 3 分牌还不错,惊喜来了,下家一看直接放弃抵抗也托管了,然后就变成我斗俩机器人农民。

    ……

    ……

    干,我特么输了。

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

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

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

    当然还有一些未知的并发问题和安全问题,之后会加强优化
    iamniconico
        89
    iamniconico  
    OP
       2018-11-07 17:27:16 +08:00
    @q397064399 是的,应用体积太膨胀了,很多公司都自研框架,当然我也有一套
    https://github.com/ainilili/no-framework
    q397064399
        90
    q397064399  
       2018-11-07 17:30:27 +08:00
    @iamniconico #89 还有目前我都没跑起来你那个程序. 把打包上传到 maven 的跟使用的 隔离开来吧 或者写个打包运行的描述也好.
    susucoolsama
        91
    susucoolsama  
       2018-11-07 18:07:34 +08:00
    lei 了,想法不错啊,有木有智障对手的设定。
    iamniconico
        92
    iamniconico  
    OP
       2018-11-07 18:53:56 +08:00 via Android
    @q397064399 不好意思,给你发个 demo 地址
    https://gitee.com/ainilili/CoffeeTime
    iamniconico
        93
    iamniconico  
    OP
       2018-11-07 18:54:42 +08:00 via Android
    @wsstest 已更新,看附言<(_ _)>
    dinjufen
        94
    dinjufen  
       2018-11-07 19:02:40 +08:00
    看完了我想写一个 GUI 的斗地主,但感觉好难
    iamniconico
        95
    iamniconico  
    OP
       2018-11-07 19:19:12 +08:00 via Android
    @susucoolsama 说出你的想法
    waruqi
        96
    waruqi  
       2018-11-07 19:36:59 +08:00 via Android
    纯字符?还是用 tui?
    iamniconico
        97
    iamniconico  
    OP
       2018-11-07 19:47:30 +08:00
    @waruqi 纯文字
    mseasons
        98
    mseasons  
       2018-11-07 19:49:28 +08:00
    有意思,我去用 Python3 弄一个
    lexuskingxx
        99
    lexuskingxx  
       2018-11-07 20:16:26 +08:00
    牛 13 了
    iamniconico
        100
    iamniconico  
    OP
       2018-11-07 22:38:37 +08:00 via Android
    @mseasons 我准备将服务端做成通用的,以后你可以考虑用 py 写客户端<(_ _)>
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1072 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 23:25 · PVG 07:25 · LAX 15:25 · JFK 18:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.