dou-cl 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/PUBLISH.md +111 -4
  2. package/README.md +60 -185
  3. package/package.json +3 -2
package/PUBLISH.md CHANGED
@@ -155,6 +155,71 @@ npm publish --otp=123456
155
155
  npm 已经公告:**Bypass 2FA token 的"直接发布"能力会在 2027 年 1 月移除**。
156
156
  长期方案是 trusted publishing(OIDC),**完全不需要 token**,也就没有 2FA 这档事 —— 见 §7。
157
157
 
158
+ ### 2.2 换手机 / 丢了手机怎么办
159
+
160
+ 先说结论:**TOTP 验证码不绑手机,绑的是那串密钥(secret)。**
161
+ 6 位数字是用 `HMAC-SHA1(secret, 当前时间/30)` 算出来的 —— 只要新手机里有同一串 secret,
162
+ 算出来的码一模一样,npm 那边什么都不用改。
163
+
164
+ 所以关键只有一个:**那串 secret 能不能跟着你到新手机。**
165
+
166
+ | 你用的验证器 | 换机后 |
167
+ | --- | --- |
168
+ | iPhone 自带「密码」App | 存在 **iCloud 钥匙串**(端到端加密),同一 Apple ID 的新机自动同步,大概率直接能用 |
169
+ | Google Authenticator | 默认**不同步**。要么它自己的 Cloud sync 开了(需 Google 账号),要么用「转移账号」扫码手动搬 |
170
+ | 微软 Authenticator / Authy 等 | 多数有云备份,看有没有开 |
171
+ | 小众 / 国产验证器 | 多数不同步,**必须自己抄出 secret** |
172
+
173
+ > 登录时是**打开 App 看 6 位数字** = TOTP(上面这张表适用);
174
+ > 如果是**弹一下 Face ID 就直接过** = security key / passkey,那是另一套 ——
175
+ > Apple 的 passkey 走 iCloud 钥匙串也会同步,但不保证,恢复码照样是兜底。
176
+
177
+ ⚠️ **别指望用 Apple「快速开始」迁移就万事大吉** —— 不少验证器 App 故意不把 secret 放进设备备份(安全考虑)。
178
+
179
+ #### 现在就去做的三件事(按性价比排序)
180
+
181
+ 1. **存下恢复码**:登录 npm → 头像 → **Account** → Two-Factor Authentication →
182
+ **Modify 2FA** → **Manage Recovery Codes**。能看到就抄到密码管理器;
183
+ 看不到就 **Regenerate Code** 重新生成一套(**旧的会立刻全部失效**)。
184
+
185
+ 2. **关联 GitHub 账号**:Account → **Linked Accounts & Recovery Option** → **Link with GitHub**。
186
+ 这是丢了设备、又丢了恢复码之后**唯一能加速找回**的东西 ——
187
+ npm 的账号恢复表单里就有一个 "Connect to GitHub" 按钮,专门用来让客服核验你。
188
+
189
+ 3. **把 secret 本身也备份**:光有恢复码只能救账号,救不了"顺手发个版"。
190
+ 把 npm 的 TOTP secret(或直接换成走 iCloud 钥匙串的验证器)放进密码管理器,
191
+ 以后换机是自动跟过去的。
192
+
193
+ #### ⚠️ 恢复码有个大坑:用一次触发 72 小时冻结
194
+
195
+ 用恢复码登录后,npm 会给账号加一个**安全冻结**,**不能提前解除**,自动到期。
196
+ 冻结期内:
197
+
198
+ - ✅ 能登录、浏览/下载/安装包、改密码、**添加新的 2FA 方式**
199
+ - ❌ **不能发布/取消发布、不能建 token、不能改包设置和维护者、不能改组织成员**
200
+
201
+ 也就是说:**手机丢了当天别想发版,至少等 3 天。** 这也是为什么下面这条路更值得走。
202
+
203
+ #### 设备 + 恢复码都丢了
204
+
205
+ 走 npm 的账号恢复流程:
206
+
207
+ 1. <https://www.npmjs.com/login> → 在 2FA 页面点 **Use a recovery code or request a reset**
208
+ 2. 点 **Try recovering your account** → **Start Account Recovery**
209
+ 3. 填注册邮箱收到的**一次性验证码**(邮箱也进不去就选 **Skip email verification**)
210
+ 4. 开 support ticket,**How can we help?** 选 **Reset my two-factor authentication (2FA)**;
211
+ 之前关联过 GitHub 就点 **Connect to GitHub** 帮客服核验
212
+ 5. **Submit Support Ticket**
213
+
214
+ #### 真正根治:发布这件事根本不需要手机
215
+
216
+ 对你的 `dou-cl` 来说,最省心的不是"怎么保住手机",而是**让发布流程不依赖 2FA**:
217
+
218
+ - **短期**:建一个勾了 **Bypass 2FA** 的 granular token(§2.1 路 B),发布不用输验证码。
219
+ 代价是 token 有有效期,且 2027-01 之后不能直接发布。
220
+ - **长期**:**trusted publishing(OIDC)**(§7)—— CI 里 `git push` 一个 tag 就发版,
221
+ **不需要 2FA、不需要 token、不需要手机上任何东西**。换手机、丢手机、人在外面都不影响。
222
+
158
223
  ---
159
224
 
160
225
  ## 3. 别人怎么玩
@@ -178,19 +243,60 @@ npx dou-cl --join 192.168.1.10:8080 --code ABCD
178
243
  npx dou-cl --match doudizhu --server 1.2.3.4:8080
179
244
  ```
180
245
 
181
- ### ⚠️ 刚发完可能拉不到
246
+ ### ⚠️ 刚发完那几分钟,npx 会拉不到
247
+
248
+ 发布命令**返回成功 ≠ 立刻全网点都能下**。registry 上先出现一个占位版本,真正的版本号
249
+ 要再过一会儿才生效;CDN 和淘宝镜像还要再传播一轮。这期间 `npx` 会拉到空壳,
250
+ 报的是这句:
251
+
252
+ ```
253
+ npm error could not determine executable to run
254
+ ```
255
+
256
+ **看到这句先别慌,八成不是包的问题,是时间差。** 实测时间线(本包第一次发布):
257
+
258
+ ```
259
+ 10:07:40 registry 上出现占位版本 0.0.0-stage
260
+ 10:09:48 真正的 1.0.0 才生效 ← 这之后才下得到
261
+ 10:09:10 在另一个窗口跑 npx ← 早了 38 秒,于是报错
262
+ ```
263
+
264
+ #### 怎么确认到底是"时间差"还是"包真的坏了"
182
265
 
183
- 如果对方的 npm 也配了淘宝镜像(npmmirror),**镜像同步有几分钟到几十分钟延迟**,
184
- 刚发布立刻 `npx dou-cl` 可能 404。两个办法:
266
+ ```bash
267
+ # 1. 官方源上有没有你的版本、bin 对不对
268
+ npm view dou-cl version bin --registry=https://registry.npmjs.org/
269
+ # version = '1.0.0'
270
+ # bin = { doucl: 'bin/dou-cl.js', 'dou-cl': 'bin/dou-cl.js' }
271
+
272
+ # 2. 把已发布的 tarball 拉下来,确认 bin 文件真的在里面
273
+ curl -sSL -o pkg.tgz https://registry.npmjs.org/dou-cl/-/dou-cl-1.0.0.tgz
274
+ tar -tzf pkg.tgz | grep bin/
275
+
276
+ # 3. 直接装一遍跑
277
+ npx --yes ./pkg.tgz --version
278
+ ```
279
+
280
+ 第 1 步有正确的 `bin`、第 2 步能看到 `package/bin/dou-cl.js`、第 3 步能跑 ——
281
+ 那包就是好的,纯粹是等的时间不够。
282
+
283
+ #### 两个加速办法
185
284
 
186
285
  ```bash
187
- # 立刻能用的写法,绕开镜像
286
+ # 绕开镜像,直接走官方源(最快)
188
287
  npx --registry=https://registry.npmjs.org/ dou-cl
189
288
 
190
289
  # 或者直接等几分钟再试
191
290
  npx dou-cl
192
291
  ```
193
292
 
293
+ > 如果等了很久还是这句,而且 `npm view dou-cl bin` **也**看不到 `bin` 字段,
294
+ > 那才是真的发错了(比如从别的目录发的、或者 `package.json` 里的 `bin` 名字和包名不一致),
295
+ > 去看 §5 的错误对照表。
296
+ >
297
+ > 另外:如果试过好几次,npx 可能把空壳缓存下来了,清一下再试:
298
+ > `npm cache clean --force`(或者删掉 `%LOCALAPPDATA%\npm-cache\_npx` 下相关目录)。
299
+
194
300
  ---
195
301
 
196
302
  ## 4. 以后更新版本
@@ -224,6 +330,7 @@ git push --follow-tags
224
330
  | `E403 You do not have permission to publish "dou-cli"` | 名字被占用(就是本文第 0 节那事)。换名或改 `package.json` 的 `name` |
225
331
  | `E403 You do not have permission to publish "dou-cl"` | token 的 Packages and scopes 没勾「All packages」,勾不到还不存在的包 |
226
332
  | `E_STAGE_REQUIRED` | token 建成了 *Stage only*,重建时改选 **Read and write → Publish and stage** |
333
+ | `could not determine executable to run` | **九成是时间差**:发布命令刚返回、registry 还没传播完,npx 拉到了占位版本。等几分钟或加 `--registry=https://registry.npmjs.org/`(见 §3)。也可能是包名和 bin 名不一致,用 `npm view dou-cl bin` 确认 |
227
334
  | `EPUBLISHCONFLICT` / `cannot publish over the previously published versions` | 版本号没升。`npm version patch` |
228
335
  | `EOTP` | 开了 2FA,命令会提示你输一次性验证码 |
229
336
  | `npm notice Publishing to https://registry.npmmirror.com` | 说明 `publishConfig` 被改掉了,**千万别发到镜像**,改回来 |
package/README.md CHANGED
@@ -1,230 +1,105 @@
1
- # dou-cl 🃏
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/iguangyu/dou-cl/main/docs/logo.png" alt="dou-cl" width="782">
3
+ </p>
2
4
 
3
- 命令行牌桌 —— **斗地主 / 跑得快 / 510K**,纯终端操作,单机可玩,也能联网对战。
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/dou-cl"><img src="https://img.shields.io/npm/v/dou-cl?color=2ea44f&label=npm" alt="npm version"></a>
7
+ <a href="https://www.npmjs.com/package/dou-cl"><img src="https://img.shields.io/badge/license-MIT-blue" alt="license"></a>
8
+ <img src="https://img.shields.io/badge/node-%3E%3D16-3c873a" alt="node">
9
+ </p>
4
10
 
5
- **摸鱼模式**:整个牌桌伪装成看起来正常的开发输出(日志流 / xxd 转储 / JSON 帧 / git diff),
6
- 信息一条不删,只是换了层壳 —— 工位上扫一眼屏幕的人只会觉得你在看构建日志。
7
- 菜单上只有两件事要选:**玩什么** 和 **单机还是联机**。
8
- 详见 [三、牌桌藏在开发输出里](#三牌桌藏在开发输出里默认)。
11
+ <p align="center"><b>一个伪装成开发控制台的命令行牌桌。</b></p>
9
12
 
10
- 牌面只用一个字符表示点数,不搞花哨的 ASCII 画图:
11
-
12
- ```
13
- 点数: 3 4 5 6 7 8 9 0(=10) J Q K A 2 w=小王 W=大王
14
- 花色: ♠ ♥ ♣ ♦ (--ascii 就会变成 S H C D)
15
- ```
16
-
17
- ---
18
-
19
- ## 一、跑起来
13
+ 跑起来就是一屏正常的开发输出:服务端日志、`xxd` 转储、JSON 帧、git diff。
14
+ 里面是**斗地主 / 跑得快 / 510K**,牌局信息一条不删,只是换了层壳。
15
+ 工位上扫一眼屏幕的人,只会觉得你在看构建日志。
20
16
 
21
17
  ```bash
22
- # 进菜单:只选玩法和是否联机
23
- npx dou-cl
24
-
25
- # 跳过菜单直接开一局(最隐蔽,屏幕上不会闪出任何“游戏”字样)
26
- npx dou-cl -g doudizhu # 斗地主
27
- npx dou-cl -g paodekuai # 跑得快
28
- npx dou-cl -g fivek # 510K
29
-
30
- # 本地源码方式(没发布 npm 也照样用)
31
- node bin/dou-cl.js
32
- npm link # 之后直接敲 dou-cl
33
- npx . # 在项目目录里用 npx 跑
18
+ npx dou-cl # 进菜单
19
+ npx dou-cl -g doudizhu # 跳过菜单直接开一局
34
20
  ```
35
21
 
36
- > 从别人那里拿到这个目录时,先 `npm install`(只有 `ws` 一个依赖,联网用;不装也能单机玩)。
37
-
38
22
  ---
39
23
 
40
- ## 二、操作
41
-
42
- | 操作 | 写法 |
43
- | --- | --- |
44
- | 出牌 | 直接敲点数:`34567` 或 `3 4 5 6 7` |
45
- | 指定花色 | 点数后面接花色:`5s 5h 5c`、`10h`、`Wh` |
46
- | 不要 | `p` 或 `pass` |
47
- | 提示 | `h` 或 `hint` |
48
- | 看真身 | `reveal`(临时打印一次原生牌桌) |
49
- | 换皮肤 | `skin log` / `skin hex` / `skin json` / `skin diff` / `skin term` |
50
- | 重置画面 | `redraw` |
51
- | 帮助 | `?` |
52
- | 退出 | `quit` |
53
-
54
- 几个小细节:
55
-
56
- - 想要同花顺或五十K 时,**不用管花色**,直接敲 `56789` / `50K`,程序会自动挑同一花色那组。
57
- - 花色字母:`s`=♠ `h`=♥ `c`=♣ `d`=♦。
58
- - 电脑出牌有约 0.7 秒间隔,用 `--speed 0` 可以飞快跳过。
59
-
60
- ---
24
+ ## 四种伪装
61
25
 
62
- ## 三、牌桌藏在开发输出里(默认)
26
+ **`log`(默认)** —— 服务端日志流。看 `hand[...]` / `peers=[...]` / `table=`。
63
27
 
64
- 给工位上玩的人准备的:**牌局信息一条都不删,只换一层壳**。
28
+ <p align="center">
29
+ <img src="https://raw.githubusercontent.com/iguangyu/dou-cl/main/docs/skin-log.png" alt="日志流" width="753">
30
+ </p>
65
31
 
66
- ```bash
67
- npx dou-cl # 默认皮肤就是 log(日志流)
68
- npx dou-cl --skin hex # 换皮肤: log / hex / json / diff
69
- npx dou-cl --skin term # 关掉伪装,显示原生牌桌
70
- npx dou-cl --skins # 列皮肤
71
- ```
32
+ 时间戳单调递增,还混着几行无关的噪声日志,整屏就是某个服务在正常打日志。
72
33
 
73
- 游戏里敲 `skin <名>` 可以随时换,`reveal` 可以临时看一眼真身。
34
+ **`hex`** —— `xxd` 十六进制转储。**只读右边 ASCII 列。**
74
35
 
75
- ### 四种壳
36
+ <p align="center">
37
+ <img src="https://raw.githubusercontent.com/iguangyu/dou-cl/main/docs/skin-hex.png" alt="hexdump" width="567">
38
+ </p>
76
39
 
77
- | 皮肤 | 长什么样 | 自洽性 |
78
- | --- | --- | --- |
79
- | `log`(默认) | 服务端结构化日志(`tail -f` 的感觉),牌就是日志字段 | 时间戳单调递增,混了无关噪声行 |
80
- | `hex` | `xxd -c 24` 十六进制转储,右边 ASCII 列就是牌 | **左边 hex 与右边字符严格逐字节对应** |
81
- | `json` | WS 帧 + jq 风格配色 | **去掉颜色就是合法 JSON,能直接 `JSON.parse`** |
82
- | `diff` | YAML 的统一 diff,绿色 `+` 行是当前牌局 | **是真 diff,能 apply 回去得到当前状态** |
40
+ 左边是真 hex、跟右列逐字节对应,不是随便编的。
83
41
 
84
- 关于「信息没丢」这件事 —— 四种壳里都有:
42
+ **`json`** —— WS 收到的 JSON 帧。看 `"hand"` / `"peers"` / `"table"`。
85
43
 
86
- ```
87
- 你的手牌 hand[] / "hand": [...] / hand: [...]
88
- 各家剩几张 peers=[mei:12 fei:8] / "peers": [{ "hold": 12 }]
89
- 谁出的什么 history 里的 play/pass 行
90
- 场上最大 table=mei->[5s 5h 5d 6c] trio1
91
- 轮到谁 turn=self
92
- 底牌/分数 bottom= [...] base= / 结果在 result= 行
93
- ```
44
+ <p align="center">
45
+ <img src="https://raw.githubusercontent.com/iguangyu/dou-cl/main/docs/skin-json.png" alt="JSON" width="579">
46
+ </p>
94
47
 
95
- 其它细节:
48
+ 去掉颜色就是一份合法 JSON,能直接 `JSON.parse`。
96
49
 
97
- - **不清屏**,像真的日志流一样往下追加(`--skin term` 才清屏)。
98
- - 输出**纯 ASCII**,不出现中文,`hex` 的 ASCII 列也不会变成一串 `.`。
99
- - 玩家名会 ASCII 化(你 → `self`,小美 → `mei`),角色是 `landlord` / `farmer`。
100
- - 输入提示符也是伪装的(`dev@ws:~/svc$ `、`node > `、`[tail -f] $ `),你敲的 `34567` 看起来就是条命令。
50
+ **`diff`** —— YAML 的 git diff。**只读绿色 `+` 行。**
101
51
 
102
- ---
52
+ <p align="center">
53
+ <img src="https://raw.githubusercontent.com/iguangyu/dou-cl/main/docs/skin-diff.png" alt="git diff" width="506">
54
+ </p>
103
55
 
104
- ## 四、联网
56
+ 是真 diff,能 `git apply` 回去;红色 `-` 是上一帧,不用看。
105
57
 
106
- 三种玩法都支持联网。房主开服务器,其他人连进来;人数不够的位置由电脑补上。
58
+ 四种壳都是**真货**:hex 逐字节对应、JSON 能解析、diff 能 apply。
59
+ 输出也全是 **ASCII** —— 不出现中文,玩家名是 `self` / `mei`,角色是 `landlord` / `farmer`,
60
+ 输入提示符也是伪装的(`dev@ws:~/svc$ `、`node > `、`[tail -f] $ `),敲的 `34567` 看起来就是条命令。
107
61
 
108
62
  ```bash
109
- # 1. 一个人当服务器(局域网内直连)
110
- npx dou-cl --serve --port 8080
111
-
112
- # 2. 开房间(连到自己或别人的服务器)
113
- npx dou-cl --create doudizhu --server 192.168.1.10:8080
114
-
115
- # 3. 别人加进来
116
- npx dou-cl --join 192.168.1.10:8080 --code ABCD
117
-
118
- # 或者快速匹配(服务器自动凑桌)
119
- npx dou-cl --match doudizhu --server 192.168.1.10:8080
63
+ npx dou-cl --skin hex # 启动时就换
64
+ npx dou-cl --skins # 列出全部
120
65
  ```
121
66
 
122
- 参数说明:
123
-
124
- | 参数 | 作用 |
125
- | --- | --- |
126
- | `--serve [--port N]` | 在本机起服务器,默认端口 8080 |
127
- | `--create <玩法>` | 连服务器并创建一个房间(会打印 4 位房间号) |
128
- | `--join <地址> [--code XXXX]` | 加入房间 |
129
- | `--match <玩法>` | 快速匹配 |
130
- | `--server <地址>` | 服务器地址,也可用环境变量 `DOUCL_SERVER` |
131
- | `--name <昵称>` | 显示的名字 |
132
- | `--skin <名>` | 换伪装皮肤,`term` = 原生牌桌(也可用 `DOUCL_SKIN`) |
133
-
134
- **局域网**:直接 `--serve`,把本机 IP(`ipconfig` 里那个 192.168.x.x)告诉朋友即可。
67
+ 游戏里敲 `skin <名>` 随时换,`reveal` 看一眼原生牌桌,`redraw` 重画一屏。
135
68
 
136
- **公网**:把服务器放到有公网 IP 的机器 / 云主机上跑 `npx dou-cl --serve`,大家用 `--server <公网IP>:8080`。服务端是**权威端**,所有牌局逻辑在服务器上跑,客户端只收自己的手牌,改前端看不到别人的牌。
69
+ ---
137
70
 
138
- 几个实现上的说明:
71
+ ## 操作
139
72
 
140
- - 房间 4 位房间号不会重复,房间空了自动回收。
141
- - 中途断线会被电脑托管,不会卡住别人。
142
- - 轮到你了不动手,90 秒后自动帮你出一张(可在代码里改 `turnTimeout`)。
73
+ 牌面**一个字符表示点数**:`3 4 5 6 7 8 9 0(=10) J Q K A 2`,`w`=小王 `W`=大王;花色 `s h c d`。
143
74
 
144
- ---
75
+ | 操作 | 写法 |
76
+ | --- | --- |
77
+ | 出牌 | 直接敲点数:`34567` 或 `3 4 5 6 7`;指定花色 `5s 5h` |
78
+ | 不要 / 提示 / 帮助 / 退出 | `p` / `h` / `?` / `quit` |
79
+ | 看真身 / 换皮肤 / 重画 | `reveal` / `skin <名>` / `redraw` |
145
80
 
146
- ## 五、玩法
147
-
148
- ### 斗地主
149
- - 3 人,每人 17 张,留 3 张底牌。
150
- - 依次叫分 1/2/3 或不叫,最高分当地主并拿走底牌;三家都不叫则流局重发。
151
- - 牌型:单张、对子、三张、三带一、三带二、顺子(5 张起)、连对(3 对起)、飞机(带单/带对)、四带二、四带两对、炸弹、王炸。
152
- - 胜负:地主先出完 → 地主赢;任一农民先出完 → 农民赢。
153
- - 计分:底分 × 倍数,每个炸弹/王炸 ×2,春天 ×2。
154
-
155
- ### 跑得快
156
- - 3 人,一副牌**去掉大小王**共 52 张,每人 17 张,剩 1 张废弃。
157
- - 首手:持有 ♠3 的玩家先出,且第一手必须带上 ♠3。
158
- - 牌型:和斗地主一样,但**没有王炸**,连对 2 对即可。
159
- - 胜负:谁先出完谁赢,其他人按剩余张数扣分。
160
-
161
- ### 510K
162
- - 4 人,**两副牌**共 108 张,每人 27 张,没有底牌。
163
- - 牌型:单张、对子、三张、顺子(5 张起)、连对(2 对起)、飞机、**同花顺**、**五十K**、炸弹(4 张及以上同点)、王炸。
164
- - **五十K**(同花色的 5·10·K 各一张)是通吃牌型:除炸弹和王炸外,**可以压任何牌型**;同花五十K 之间比花色(♠ > ♥ > ♣ > ♦)。
165
- - **同花顺**可以压同长度的普通顺子。
166
- - 计分:5 = 5 分,10 = 10 分,K = 10 分,两副共 200 分。**每一轮结束时,本轮桌面上的分牌全部归本轮最后出牌的人。**
167
- - 胜负:谁先出完手牌谁赢,分数作为副榜。
81
+ 同花顺、五十K **不用管花色**,直接敲 `56789` / `50K`,程序自动挑同花色那组。
168
82
 
169
83
  ---
170
84
 
171
- ## 六、目录结构
85
+ ## 三种玩法
172
86
 
173
- ```
174
- bin/dou-cl.js 命令行入口(参数解析)
175
- src/core/cards.js 牌模型 / 发牌 / 排序
176
- src/core/combo.js 牌型识别、比大小、候选生成
177
- src/core/rules.js 三种玩法的规则开关
178
- src/games/base.js 通用回合引擎(校验与执行分离)
179
- src/games/doudizhu.js 斗地主(叫分 / 春天 / 计分)
180
- src/games/paodekuai.js 跑得快(♠3 先手)
181
- src/games/fivek.js 510K(收分 / 五十K)
182
- src/bot.js 电脑 AI
183
- src/ui.js 渲染 + 输入解析
184
- src/color.js 颜色(原生与伪装皮肤共用)
185
- src/runner.js 单局循环
186
- src/skins/packet.js 把视野压成与渲染方式无关的状态包
187
- src/skins/log.js 伪装皮肤:日志流
188
- src/skins/hex.js 伪装皮肤:xxd 十六进制转储
189
- src/skins/json.js 伪装皮肤:JSON 帧
190
- src/skins/diff.js 伪装皮肤:git diff
191
- src/skins/index.js 皮肤注册表 + 会话状态
192
- src/net/server.js 房间服务器(权威端)
193
- src/net/client.js 联网客户端
194
- test/sim.js 电脑互打自测
195
- test/smoke.js 渲染 / 输入解析 / 联网全流程
196
- test/local-test.js 本地视角回归(人类手牌不能被看错)
197
- test/skins-test.js 伪装皮肤自洽性(hex 对字节 / JSON 可解析 / diff 可 apply / 纯 ASCII)
198
- test/make-preview.js 生成 预览.html
199
- test/show.js 单看某个皮肤的效果: node test/show.js fivek hex 8
200
- ```
87
+ | 玩法 | 人数 | 简介 |
88
+ | --- | --- | --- |
89
+ | **斗地主** | 3 | 叫分 1/2/3 抢地主,拿 3 张底牌;炸弹 / 春天各 ×2 |
90
+ | **跑得快** | 3 | 一副牌去大小王,持 ♠3 者先出且首手必带 ♠3 |
91
+ | **510K** | 4 | 两副牌,5/10/K 计分;五十K 是通吃牌型 |
201
92
 
202
- 自测:
93
+ 都可以联网:一个人 `--serve` 开服务器,其他人 `--join <地址> --code <房间号>` 进来,
94
+ 或 `--match <玩法>` 快速匹配,人数不够由电脑补齐。
203
95
 
204
96
  ```bash
205
- node test/sim.js 300 # 每种玩法各打 300 局电脑互打,校验规则与牌数守恒
206
- node test/smoke.js # 渲染 / 输入解析 / 服务器+客户端联网打完整一局
207
- node test/local-test.js # 本地对局:渲染视角必须固定在人类座位上
208
- node test/skins-test.js # 伪装皮肤:hex 逐字节、JSON 可解析、diff 可 apply、输出纯 ASCII
209
- npm test # 以上全部
210
- npm run preview # 生成 预览.html,先看看跑起来长什么样
97
+ npx dou-cl --serve --port 8080
98
+ npx dou-cl --join 192.168.1.10:8080 --code ABCD
211
99
  ```
212
100
 
213
101
  ---
214
102
 
215
- ## 七、加新玩法 / 加新皮肤
216
-
217
- **加玩法**:在 `src/core/rules.js` 里加一份规则(座位数、牌堆、最小顺子长度、有没有王炸/五十K……),
218
- 再写一个继承 `src/games/base.js` 的类实现 `setupPhase` / `checkOver` / `onGameEnd`,
219
- 最后在 `src/games/index.js` 注册即可 —— 牌型识别、AI、联网、伪装皮肤全都不用动。
220
-
221
- **加伪装皮肤**:在 `src/skins/` 下加一个模块,导出
222
- `{ key, name, desc, render(p, st), prompt(), help(lines), message(text) }`,
223
- 其中 `p` 是 `packet.build()` 出来的标准状态包(手牌 / 各家张数 / 桌上最大 / 历史 / 结果都已经在里面),
224
- 在 `src/skins/index.js` 的 `LIST` 里注册一行就完事了。
225
-
226
103
  ## License
227
104
 
228
105
  MIT
229
-
230
- 想把它发到 npm 让别的机器 `npx dou-cl` 直接用?看 [PUBLISH.md](PUBLISH.md)。
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dou-cl",
3
- "version": "1.0.0",
4
- "description": "命令行斗地主 / 跑得快 / 510K —— 默认把牌桌伪装成普通开发输出(日志/hexdump/JSON/git diff),支持单机与联网对战",
3
+ "version": "1.0.1",
4
+ "description": "伪装成开发控制台的命令行牌桌 —— 斗地主 / 跑得快 / 510K,牌局藏在终端里",
5
5
  "keywords": [
6
6
  "doudizhu",
7
7
  "斗地主",
@@ -51,6 +51,7 @@
51
51
  "skins": "node test/skins-test.js",
52
52
  "drill": "node test/exercise-test.js",
53
53
  "preview": "node test/make-preview.js",
54
+ "docs": "node tools/make-docs.js",
54
55
  "prepublishOnly": "npm test"
55
56
  },
56
57
  "dependencies": {