|
1 | 1 | # 雀阁 · 纸牌房 |
2 | 2 |
|
3 | | -> **Forked from** [laivv/doudizhu](https://github.com/laivv/doudizhu.git) |
| 3 | +雀阁是一个基于 Node.js、Socket.IO 和 Vue 2 的在线纸牌房项目。项目最初 fork 自 [laivv/doudizhu](https://github.com/laivv/doudizhu.git),现在已重构为“房间制 + 多玩法”的纸牌游戏平台,当前支持斗地主和掼蛋,并预留继续接入新玩法的结构。 |
4 | 4 |
|
5 | | -> 基于 Node.js + Vue 2 + Socket.IO 的多人在线纸牌房,支持 **动态开房 / 快速匹配 / 好友房号 / 斗地主 / 掼蛋 / 观战 / 国风音画**。 |
| 5 | +## 功能概览 |
6 | 6 |
|
| 7 | +- 动态房间:支持公开房、私密房、房号加入、快速入局。 |
| 8 | +- 斗地主:三人叫分、地主底牌、地主/农民阵营、炸弹与春天倍率、AI 对手、智囊推荐。 |
| 9 | +- 掼蛋:四人两副牌、固定对家、级牌升级、红桃级牌逢人配、AI 补位、智囊推荐、局内队伍计分板。 |
| 10 | +- 观战模式:可不入座观看正在进行的房间。 |
| 11 | +- AI 系统:空位可补 AI,真人可顶替等待态 AI,AI 会自动重新准备。 |
| 12 | +- 聊天系统:房间内自由文本聊天。 |
| 13 | +- 音效与特效:出牌、不出、炸弹、王炸、同花顺等有局内反馈,可静音。 |
| 14 | +- 积分系统:可选 MySQL 持久化,斗地主和掼蛋积分榜独立统计。 |
| 15 | +- Discuz SSO:可选 JWT 单点登录,支持同步 Discuz 用户名和头像。 |
| 16 | +- 移动端:大厅可响应式使用;牌桌在手机端要求横屏。 |
7 | 17 |
|
8 | | ---- |
| 18 | +## 快速开始 |
9 | 19 |
|
10 | | -## 特性 |
| 20 | +要求 Node.js 18 或更高版本。 |
11 | 21 |
|
12 | | -- **动态房间** — 玩家可以开公开房、开私密房、输入房号加入好友房,也可以快速入局自动匹配空房。 |
13 | | -- **多玩法架构** — 斗地主与掼蛋作为独立玩法接入,后续可继续扩展新的纸牌规则。 |
14 | | -- **斗地主** — 三人叫分、底牌、地主/农民阵营、炸弹翻倍、春天结算、AI 陪玩与智囊推荐。 |
15 | | -- **掼蛋** — 四人两副牌、对家组队、级牌升级、红桃级牌逢人配、炸弹/同花顺/四王炸、头游队伍升级结算。 |
16 | | -- **AI 对手** — 斗地主房内一键「召唤 A I 对手」,自动填空座;真人加入时 AI 自动让座、全员退房时自动清场。 |
17 | | -- **观战模式** — 不入座也能旁观对局,棋谱牌势一览无余。 |
18 | | -- **智囊推荐** — 自己回合点「智 囊」即可由内置 AI 自动选出最经济的合法跟牌。 |
19 | | -- **国风视效** — 玉绿背景、朱漆按钮、鎏金徽印;地主登场金光,农民登场玉色光晕;炸弹/王炸/飞机各自专属字幕特效。 |
20 | | -- **Web Audio 音效** — 出牌、不出、叫分、炸弹皆有合成音色,可一键静音。 |
21 | | -- **房间聊天** — 茶馆闲话面板,自由输入或下拉选「快语」短句。 |
22 | | -- **移动端适配** — 大厅、开房、手牌、聊天和操作按钮针对手机竖屏做了响应式布局。 |
23 | | -- **可选 SSO** — 内置 JWT 校验入口,便于与 Discuz 等论坛对接(参见 [discuz-sso/README.md](discuz-sso/README.md))。 |
| 22 | +```bash |
| 23 | +npm install |
| 24 | +npm start |
| 25 | +``` |
24 | 26 |
|
25 | | ---- |
| 27 | +默认监听 `8002`: |
26 | 28 |
|
27 | | -## 截图 |
| 29 | +```text |
| 30 | +http://localhost:8002/ |
| 31 | +``` |
28 | 32 |
|
29 | | -<img width="1702" height="1255" alt="f2f1befc878f15cbbcc39238c5bf0546" src="https://github.com/user-attachments/assets/c0f47639-e6af-4997-acc0-a038c1d9f319" /> |
30 | | -<img width="1700" height="1257" alt="e2384b186038c64b40103a9f2db9d653" src="https://github.com/user-attachments/assets/87b166c5-42a3-408c-bd00-d52e17a57634" /> |
| 33 | +本地指定端口: |
31 | 34 |
|
| 35 | +```powershell |
| 36 | +$env:PORT='8012' |
| 37 | +node server.js |
| 38 | +``` |
32 | 39 |
|
33 | | ---- |
| 40 | +## 配置 |
34 | 41 |
|
35 | | -## 快速开始 |
| 42 | +项目启动时按以下优先级读取配置: |
36 | 43 |
|
37 | | -确保已安装 Node.js(建议 ≥ 18)。 |
| 44 | +1. 环境变量 |
| 45 | +2. 根目录 `config.json` |
| 46 | +3. 代码默认值 |
38 | 47 |
|
39 | | -```sh |
40 | | -git clone https://github.com/laivv/doudizhu.git |
41 | | -cd doudizhu |
42 | | -npm install |
43 | | -npm start |
| 48 | +复制示例配置: |
| 49 | + |
| 50 | +```bash |
| 51 | +cp config.example.json config.json |
44 | 52 | ``` |
45 | 53 |
|
46 | | -默认监听 **8002** 端口,浏览器访问: |
| 54 | +`config.json` 已加入 `.gitignore`,不要提交真实密钥和数据库密码。 |
47 | 55 |
|
48 | | -``` |
49 | | -http://localhost:8002 |
50 | | -``` |
| 56 | +常用配置: |
| 57 | + |
| 58 | +| 字段 / 环境变量 | 说明 | 默认值 | |
| 59 | +| --- | --- | --- | |
| 60 | +| `PORT` | HTTP / Socket.IO 监听端口 | `8002` | |
| 61 | +| `JWT_SECRET` | Discuz SSO JWT 密钥,必须与论坛端一致 | `change_this_in_production` | |
| 62 | +| `DB_HOST` | MySQL 地址 | `127.0.0.1` | |
| 63 | +| `DB_PORT` | MySQL 端口 | `3306` | |
| 64 | +| `DB_USER` | MySQL 用户名 | 无 | |
| 65 | +| `DB_PASSWORD` | MySQL 密码 | 空 | |
| 66 | +| `DB_NAME` | MySQL 数据库名 | 无 | |
| 67 | +| `DB_TABLE_PREFIX` | 表前缀,建议与 Discuz 一致 | `pre_` | |
| 68 | +| `DB_DISABLE` | 设为 `1` 禁用数据库持久化 | 未启用 | |
| 69 | +| `SCORE_BASE` | 每个基础分对应的积分 | `1` | |
| 70 | +| `DISCUZ_AVATAR_BASE` | Discuz 头像 URL 模板,支持 `{uid}` | `https://zwwx.club/uc_server/avatar.php?uid={uid}&size=middle` | |
51 | 71 |
|
52 | | -输入「雅号」后即可进入大厅: |
| 72 | +## 玩法说明 |
53 | 73 |
|
54 | | -- 选择「斗地主」或「掼蛋」后点「快速入局」。 |
55 | | -- 点「开公开房」等待陌生玩家加入。 |
56 | | -- 点「开私密房」后把房号发给朋友。 |
57 | | -- 输入好友给你的房号可直接加入。 |
| 74 | +### 斗地主 |
58 | 75 |
|
59 | | ---- |
| 76 | +- 三人参与。 |
| 77 | +- 叫分后分为地主与农民两方。 |
| 78 | +- 地主获得底牌。 |
| 79 | +- 支持常见斗地主牌型,牌型识别由 `static/js/parser.js` 和 `game.js` 处理。 |
| 80 | +- 结算时地主按双倍基础分输赢,农民按单倍基础分输赢。 |
60 | 81 |
|
61 | | -## 操作指南 |
| 82 | +### 掼蛋 |
62 | 83 |
|
63 | | -### 自己回合的按钮顺序 |
| 84 | +- 四人参与,两副牌,每人 27 张。 |
| 85 | +- 座位 `0/2` 为一队,`1/3` 为一队。 |
| 86 | +- 当前级牌从 `2` 开始,红桃级牌为逢人配。 |
| 87 | +- 头游队伍升级:双下 `+3`,二三名 `+2`,其他胜局 `+1`。 |
64 | 88 |
|
65 | | -``` |
66 | | -[ 出 牌 ] [ 智 囊 ] [ 不 出 ] |
67 | | - ↑ 朱漆 ↑ 墨色 ↑ 玉绿 |
68 | | -``` |
| 89 | +第一类牌型: |
69 | 90 |
|
70 | | -- **出 牌**:将选中的牌打出(必须是合法牌型,且能压过上家)。 |
71 | | -- **智 囊**:让 AI 自动帮你选牌;若无可压制的牌会提示「建议不出」。 |
72 | | -- **不 出**:跳过本轮(仅当上家不是自己时可见)。 |
| 91 | +- 单张:任意一张牌。 |
| 92 | +- 对子:两张点数相同的牌,包括对大王或对小王。 |
| 93 | +- 三连对:三对连续对子,例如 `223344`。 |
| 94 | +- 三同张:三张点数相同的牌。 |
| 95 | +- 二连三:两组三同张,例如 `333444`。 |
| 96 | +- 三带二:三同张带一个对子,例如 `55522`。 |
| 97 | +- 顺子:五张连续单牌,例如 `23456`。 |
73 | 98 |
|
74 | | -### 房间与等待区 |
| 99 | +第一类牌型之间必须牌型相同才能压牌;三带二只比较三同张大小。 |
75 | 100 |
|
76 | | -- **准 备**:标记自己已就绪;三人全部就绪自动开局。 |
77 | | -- **召 唤 A I 对 手**:斗地主房内有空座时显示,把所有空位填上 AI。 |
78 | | -- **请 走 A I**:斗地主房内有 AI 时显示,清退所有 AI 等真人。 |
79 | | -- **房号**:房间顶部显示,私密房可复制房号给好友加入。 |
| 101 | +连续牌型中,`A` 可以作为最小值,也可以作为 `K+1`。例如 `A2345`、`23456`、`10JQKA`、`AA2233`、`QQKKAA` 都是合法连续牌型。 |
80 | 102 |
|
81 | | -### 叫分 |
| 103 | +第二类牌型: |
82 | 104 |
|
83 | | -听到「叫分」环节时,依次显示可叫分数(1/2/3)和「不叫」按钮,点击即可。 |
| 105 | +- 炸弹:四张或四张以上点数相同的牌。 |
| 106 | +- 同花顺:五张花色相同的顺子。 |
| 107 | +- 天王炸:大小王各两张。 |
84 | 108 |
|
85 | | -### 掼蛋 |
| 109 | +第二类可以压任意第一类。第二类内部顺序: |
86 | 110 |
|
87 | | -- 四人开局,两副牌,每人 27 张。 |
88 | | -- 0/2 与 1/3 为固定对家。 |
89 | | -- 当前级牌从 2 开始,红桃级牌为逢人配,可参与常规牌型组合。 |
90 | | -- 支持单张、对子、三张、三带二、顺子、连对、钢板、炸弹、同花顺、四王炸。 |
91 | | -- 头游队伍按名次升级:双下 +3,二三名 +2,其余 +1。 |
| 111 | +- 天王炸最大。 |
| 112 | +- 炸弹张数越多越大,张数相同比点数。 |
| 113 | +- 同花顺按顺子点数比较。 |
| 114 | +- 同花顺可以压五张及以下炸弹,六张及以上炸弹大于同花顺。 |
92 | 115 |
|
93 | | -### AI 让座规则 |
| 116 | +## 智囊与 AI |
94 | 117 |
|
95 | | -- 真人入座时若该位被 AI 占用且未在游戏中 → AI **拱手让座**。 |
96 | | -- 桌内最后一名真人离席 / 掉线 → 服务端自动清退该桌所有 AI 并重置牌局。 |
97 | | -- 一局结束后,留在桌上的 AI **自动重新就绪**;若全员就绪则立即开下一局。 |
| 118 | +斗地主智囊由 `static/js/ai-suggest.js` 提供。 |
98 | 119 |
|
99 | | ---- |
| 120 | +掼蛋智囊由 `static/js/guandan-suggest.js` 提供,服务端机器人与前端“智囊”共用同一套规则分析。策略原则: |
100 | 121 |
|
101 | | -## 技术栈 |
| 122 | +- 自由出牌时优先减少手数。 |
| 123 | +- 跟牌时尽量用最小可压牌。 |
| 124 | +- 队友出牌时通常不压,除非可以直接走完。 |
| 125 | +- 炸弹和逢人配会尽量保留,除非局势需要。 |
102 | 126 |
|
103 | | -| 层 | 选型 | |
| 127 | +## 积分系统 |
| 128 | + |
| 129 | +数据库持久化是可选能力。未配置数据库时,游戏仍可正常运行,但不会保存积分。 |
| 130 | + |
| 131 | +启动时自动创建两张表: |
| 132 | + |
| 133 | +```text |
| 134 | +pre_doudizhu_score |
| 135 | +pre_guandan_score |
| 136 | +``` |
| 137 | + |
| 138 | +表前缀由 `DB_TABLE_PREFIX` 决定。 |
| 139 | + |
| 140 | +HTTP 查询接口: |
| 141 | + |
| 142 | +| 接口 | 说明 | |
104 | 143 | | --- | --- | |
105 | | -| 服务端 | Node.js · Express · Socket.IO 4 · jsonwebtoken | |
106 | | -| 前端 | Vue 2(CDN 单文件)· jQuery · layer 弹层 | |
107 | | -| 通信 | WebSocket(事件:`CREATE_ROOM` / `JOIN_ROOM` / `QUICK_JOIN` / `SITDOWN` / `PREPARE` / `CALL_SCORE` / `PLAY_CARD` / `USER_MESSAGE` / `SPECTATE` / `ADD_BOTS` / `REMOVE_BOTS` …) | |
108 | | -| 音效 | 原生 Web Audio API(无第三方依赖) | |
109 | | -| 牌型校验 | `static/js/parser.js`(A / AA / AAA / AAAB / AAABB / ABCDE / AABBCC / AAABBB / AAAABC / AAAABBCC / AAAA / KING) | |
110 | | -| AI 决策 | `static/js/ai-suggest.js`(同时供前端「智囊」与服务端「机器人」使用) | |
| 144 | +| `GET /api/score/me?gameType=doudizhu&token=<JWT>` | 当前用户斗地主战绩 | |
| 145 | +| `GET /api/score/me?gameType=guandan&token=<JWT>` | 当前用户掼蛋战绩 | |
| 146 | +| `GET /api/score/top?gameType=doudizhu&limit=20` | 斗地主积分榜 | |
| 147 | +| `GET /api/score/top?gameType=guandan&limit=20` | 掼蛋积分榜 | |
| 148 | + |
| 149 | +只有通过 JWT 登录的真人玩家会计入积分。游客、AI、观战用户不记录。 |
111 | 150 |
|
112 | | ---- |
| 151 | +## Discuz SSO |
| 152 | + |
| 153 | +项目支持通过 Discuz 签发 JWT 进行单点登录。 |
| 154 | + |
| 155 | +- 论坛端示例代码在 `discuz-sso/`。 |
| 156 | +- 游戏端通过 Socket.IO `auth.token` 校验 JWT。 |
| 157 | +- 登录成功后可同步 Discuz 用户名和头像。 |
| 158 | + |
| 159 | +详细部署见 [discuz-sso/README.md](discuz-sso/README.md)。 |
113 | 160 |
|
114 | 161 | ## 项目结构 |
115 | 162 |
|
116 | | -``` |
117 | | -quege-card-room/ |
118 | | -├── server.js # Express + Socket.IO 入口;含 AI 机器人调度 |
119 | | -├── game.js # 游戏状态机(发牌 / 叫分 / 出牌 / 胜负) |
120 | | -├── guandan-game.js # 掼蛋状态机(两副牌 / 级牌 / 逢人配 / 升级) |
121 | | -├── core-ai.js # 服务端 AI 辅助 |
122 | | -├── core-validator.js # 服务端牌型校验 |
123 | | -├── package.json |
124 | | -├── discuz-sso/ # 可选:与 Discuz 论坛 SSO 对接示例 |
| 163 | +```text |
| 164 | +. |
| 165 | +├── server.js # Express + Socket.IO 入口、房间、AI、API |
| 166 | +├── game.js # 斗地主状态机 |
| 167 | +├── guandan-game.js # 掼蛋状态机与服务端判牌 |
| 168 | +├── db.js # 分玩法积分持久化 |
| 169 | +├── core-ai.js # 原斗地主 AI 辅助 |
| 170 | +├── core-validator.js # 原斗地主校验辅助 |
| 171 | +├── config.example.json # 本地配置示例 |
| 172 | +├── discuz-sso/ # Discuz JWT SSO 示例 |
125 | 173 | └── static/ |
126 | | - ├── index.html # Vue SPA 单页 |
| 174 | + ├── index.html # Vue 2 单页应用 |
127 | 175 | ├── css/ |
128 | | - │ ├── base.css |
129 | | - │ ├── style.css # 国风主题样式 |
130 | | - │ └── theme.css |
131 | | - ├── images/ |
132 | | - │ └── screenshots/ # 文档截图 |
| 176 | + │ ├── theme.css # 主题变量 |
| 177 | + │ └── style.css # 主要布局与组件样式 |
| 178 | + ├── images/ # 扑克图、桌面素材 |
133 | 179 | └── js/ |
134 | | - ├── parser.js # 牌型识别 |
135 | | - ├── ai-suggest.js # AI 选牌引擎(前后端共用) |
136 | | - ├── effects.js # 特效字幕 + Web Audio 音效 |
| 180 | + ├── parser.js # 斗地主牌型解析 |
| 181 | + ├── ai-suggest.js # 斗地主智囊 |
| 182 | + ├── guandan-suggest.js # 掼蛋智囊 |
| 183 | + ├── effects.js # 音效与特效 |
137 | 184 | ├── vue.min.js |
138 | 185 | ├── jquery.min.js |
139 | | - └── layer/ # layer 弹层组件 |
| 186 | + └── layer/ # 弹窗组件 |
140 | 187 | ``` |
141 | 188 |
|
142 | | ---- |
143 | | - |
144 | | -## 可选:Discuz SSO 对接 |
145 | | - |
146 | | -若要让论坛会员免登录进入游戏,可参考 [discuz-sso/README.md](discuz-sso/README.md):论坛侧颁发 JWT,前端在 `?token=` 中带入,服务端 `io.use` 中间件校验通过后建立连接。 |
| 189 | +## 常用 Socket 事件 |
| 190 | + |
| 191 | +客户端到服务端: |
| 192 | + |
| 193 | +- `LOGIN` |
| 194 | +- `CREATE_ROOM` |
| 195 | +- `QUICK_JOIN` |
| 196 | +- `JOIN_ROOM` |
| 197 | +- `SITDOWN` |
| 198 | +- `PREPARE` |
| 199 | +- `CALL_SCORE` |
| 200 | +- `PLAY_CARD` |
| 201 | +- `USER_MESSAGE` |
| 202 | +- `SPECTATE` |
| 203 | +- `ADD_BOTS` |
| 204 | +- `REMOVE_BOTS` |
| 205 | + |
| 206 | +服务端到客户端: |
| 207 | + |
| 208 | +- `LOGIN_SUCCESS` |
| 209 | +- `LOGIN_FAIL` |
| 210 | +- `REFRESH_LIST` |
| 211 | +- `POS_STATUS_CHANGE` |
| 212 | +- `GAME_START` |
| 213 | +- `CTX_USER_CHANGE` |
| 214 | +- `CTX_PLAY_CHANGE` |
| 215 | +- `SHOW_TOP_CARD` |
| 216 | +- `PLAY_CARD_SUCCESS` |
| 217 | +- `PLAY_CARD_ERROR` |
| 218 | +- `GAME_OVER` |
| 219 | +- `USER_MESSAGE` |
| 220 | +- `MY_SCORE` |
| 221 | + |
| 222 | +## 开发与验证 |
| 223 | + |
| 224 | +语法检查: |
| 225 | + |
| 226 | +```bash |
| 227 | +node --check server.js |
| 228 | +node --check db.js |
| 229 | +node --check game.js |
| 230 | +node --check guandan-game.js |
| 231 | +node --check static/js/guandan-suggest.js |
| 232 | +node --check static/js/effects.js |
| 233 | +``` |
147 | 234 |
|
148 | | ---- |
| 235 | +本地规则回归建议覆盖: |
| 236 | + |
| 237 | +- 掼蛋 `A2345`、`23456`、`10JQKA` |
| 238 | +- 掼蛋三连对、二连三、三带二 |
| 239 | +- 同花顺压五张炸,六张炸压同花顺 |
| 240 | +- 天王炸压所有牌型 |
| 241 | +- 斗地主叫分、底牌、出牌、结算 |
| 242 | + |
| 243 | +## 部署建议 |
| 244 | + |
| 245 | +- 使用 HTTPS,特别是启用 Discuz SSO 时。 |
| 246 | +- 生产环境必须设置强随机 `JWT_SECRET`。 |
| 247 | +- 建议用 systemd、pm2 或容器托管 Node 进程。 |
| 248 | +- 如在 Cloudflare 等代理后运行,保留 WebSocket 支持。 |
| 249 | +- 数据库账号只授予游戏积分表需要的权限。 |
| 250 | + |
| 251 | +systemd 示例: |
| 252 | + |
| 253 | +```ini |
| 254 | +[Unit] |
| 255 | +Description=Quege Card Room |
| 256 | +After=network.target |
| 257 | + |
| 258 | +[Service] |
| 259 | +WorkingDirectory=/var/www/quege-card-room |
| 260 | +ExecStart=/usr/bin/node server.js |
| 261 | +Restart=always |
| 262 | +Environment=PORT=8002 |
| 263 | +Environment=JWT_SECRET=replace-with-a-strong-secret |
| 264 | +Environment=DB_HOST=127.0.0.1 |
| 265 | +Environment=DB_USER=discuz |
| 266 | +Environment=DB_PASSWORD=replace-with-db-password |
| 267 | +Environment=DB_NAME=discuz |
| 268 | +Environment=DB_TABLE_PREFIX=pre_ |
| 269 | + |
| 270 | +[Install] |
| 271 | +WantedBy=multi-user.target |
| 272 | +``` |
149 | 273 |
|
150 | 274 | ## License |
151 | 275 |
|
152 | | -MIT — 详见 LICENSE。 |
| 276 | +代码以 [MIT License](LICENSE) 发布。 |
153 | 277 |
|
154 | | -> 注:`static/images/` 内的扑克 / 桌面贴图素材来源于网络,**不在 MIT 许可范围内**,仅作演示用途;如商业使用请自行替换。 |
| 278 | +`static/images/` 中的牌面、桌面等素材仅作为演示资源;商业使用请确认素材授权或自行替换。 |
0 commit comments