若烹小鲜
基于python+html的桂林跑牌

桂林跑牌
一个使用 Flask 编写的桂林跑牌网页游戏。项目包含大厅、多人房间、牌桌界面、
出牌规则、局内轮转、自动过牌、跨小局积分和整局结束结算。
功能概览
- 创建 4 位房间号,其他玩家可输入房间号加入。
- 支持 2 到 4 人开局,每名玩家每小局发 13 张牌。
- 支持单张、对子、三张、四张、四连张牌型。
- 按桂林跑牌规则实现“有牌可管必须出”,无牌可管时允许过牌。
- 当前玩家无牌可管时,前端 5 秒后自动过牌,避免牌局卡住。
- 记录最近出牌历史,并展示每名玩家最近出的牌堆。
- 每小局结束后结算剩余牌分数,累计达到 100 分结束整局。
- 房主退出会释放房间;整局结束后房间保留短暂倒计时再释放。
技术栈
- 后端:Python + Flask
- 前端:原生 HTML/CSS/JavaScript
- 存储:单进程内存存储,无数据库依赖
- 依赖:见
requirements.txt
目录结构
.
├── app/
│ ├── init.py # Flask 应用工厂
│ ├── cardgame/
│ │ ├── routes.py # 页面路由和 JSON API
│ │ ├── store.py # 内存房间、成员、积分和继续投票
│ │ ├── engine.py # 单局牌局状态机
│ │ ├── rules.py # 牌、牌型、大小比较和可出牌枚举
│ │ └── crypto.py # MD4 摘要工具,用于生成短房间号
│ ├── static/
│ │ ├── css/guilin_paopai.css # 大厅、牌桌和响应式样式
│ │ └── js/
│ │ ├── guilin_paopai_lobby.js
│ │ └── guilin_paopai.js
│ └── templates/
│ ├── guilin_paopai_lobby.html
│ └── guilin_paopai.html
├── docs/
│ ├── API.md # 接口说明
│ └── GAME_RULES.md # 详细游戏规则
├── config.py # Flask 配置
├── run.py # 本地开发启动入口
└── requirements.txt
本地运行
建议使用虚拟环境运行:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python run.py
默认监听地址:
http://127.0.0.1:5001/cardgame/guilin-paopai
run.py 使用 host="0.0.0.0",同一局域网设备也可以通过主机 IP 访问:
http://<你的主机IP>:5001/cardgame/guilin-paopai
基本玩法流程
- 打开大厅页,点击“建房”创建房间。
- 把页面中的 4 位房间号告诉其他玩家。
- 其他玩家在大厅输入房间号并加入。
- 房主点击“开始”后进入第一小局。
- 轮到自己时选择手牌并点击“出牌”;如果无牌可管,可以点击“过牌”。
- 某名玩家先出完手牌后,本小局结束并展示结算。
- 所有人点击“继续”后开始下一小局。
- 任一玩家累计分达到 100 分,整局结束并展示最终积分。
规则摘要
- 人数:2 到 4 人。
- 发牌:每人 13 张,剩余牌保留但当前不会摸牌。
- 首出:每小局随机一名玩家首出。
- 牌型:单张、对子、三张、四张、四连张。
- 大小:单张/对子/三张/四张按
3 < 4 < ... < K < A < 2。 - 四连张:最大
AKQJ,最小432A;KA2不算连续。 - 管牌:必须同牌型且点数更大;当前实现中四张不跨牌型压制其他牌型。
- 过牌:首出不能过;有牌可管时必须出,只有无牌可管时可以过。
- 直接胜利:起手拿到 4 个 2,或起手全小,立即赢得本小局。
- 小局结束:任一玩家先出完手牌。
- 计分:胜者本局不加分,其他玩家按剩余牌数量和倍率加分。
完整规则见 docs/GAME_RULES.md。
计分方式
| 剩余张数 | 倍率 |
|---|---|
| 0 到 7 张 | x1 |
| 8 到 9 张 | x2 |
| 10 到 12 张 | x3 |
| 13 张 | x4 |
本局加分:
胜者:0
其他玩家:剩余张数 * 倍率
当前实现把累计分视为剩余牌惩罚分;任一玩家累计达到 100 分时整局结束,界面
保留积分列表供玩家查看最终结果。
API 文档
接口说明见 docs/API.md。常用接口包括:
POST /cardgame/api/guilin-paopai/rooms:创建房间POST /cardgame/api/guilin-paopai/rooms//join:加入房间GET /cardgame/api/guilin-paopai/rooms/:轮询房间状态POST /cardgame/api/guilin-paopai/rooms//start:房主开始POST /cardgame/api/guilin-paopai/rooms//play:出牌POST /cardgame/api/guilin-paopai/rooms//pass:过牌POST /cardgame/api/guilin-paopai/rooms//continue:继续下一小局
设计说明
rules.py是纯规则层,不依赖 Flask,也不保存房间状态。engine.py管一小局内的发牌、出牌、过牌、轮转和胜负。store.py管多人房间、成员、积分、继续投票和房间释放。routes.py只做 HTTP 请求解析和错误响应转换。- 前端通过
localStorage保存playerId,刷新页面后可回到原座位。 - 房间状态通过轮询同步,默认约 1.6 秒请求一次。
开发注意事项
- 当前房间和牌局都存放在 Python 进程内存中,服务重启后全部丢失。
- Flask 开发服务器适合本地调试,不建议直接作为生产服务。
- 如果要多进程或多实例部署,需要把
_ROOMS、_GAMES和锁替换为共享存储。 config.py中的SECRET_KEY是开发值,正式部署应改为环境变量注入。- 房主开局当前只要求人数不少于 2 人,不强制所有玩家准备。
基础检查
修改 Python 代码后可以先运行语法检查:
python -m compileall app config.py run.py
目前项目没有自动化测试套件;规则层和引擎层已经拆开,后续可优先补充
rules.py 和 engine.py 的单元测试。
桂林跑牌规则说明
本文档描述当前代码实现的桂林跑牌规则。不同地区规则可能有差异,以下内容以
本项目代码为准。
人数与发牌
- 支持 2 到 4 名玩家。
- 每名玩家每小局发 13 张牌。
- 2 人或 3 人局会有剩余牌,当前实现中剩余牌不参与摸牌,只在状态中保留数量。
- 每小局重新洗牌和发牌,积分跨小局累计。
点数大小
单张、对子、三张、四张都使用同一套点数顺序:
3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 < J < Q < K < A < 2
花色不参与大小比较,只用于展示和稳定排序。
合法牌型
单张
任意 1 张牌。
示例:
A
对子
2 张相同点数的牌。
示例:
88
三张
3 张相同点数的牌。
示例:
KKK
四张
4 张相同点数的牌。
示例:
2222
当前实现中四张只是一个普通牌型,只能管更小的四张,不会跨牌型压制单张、对子、
三张或四连张。
四连张
4 个不同点数组成的连续牌型。当前实现支持的四连张从大到小为:
AKQJ
KQJ10
QJ109
J1098
10987
9876
8765
7654
6543
5432
432A
注意:
AKQJ最大。432A最小。KA2不算连续。- 四连张之间只比较上表顺序,不按普通扑克牌顺子规则推导。
出牌与管牌
- 每小局随机一个玩家首出。
- 本轮首出时可以选择任意合法牌型。
- 后续玩家必须出相同牌型,并且大小严格大于桌面当前牌。
- 如果没有牌能管,可以过牌。
- 如果有牌能管,必须出牌,不能主动过牌。
- 当其他玩家都无法管住当前牌时,本轮结束,最后成功出牌的玩家获得下一轮首出权。
起手直接胜利
发牌后会先检查两个直接胜利条件:
- 玩家起手拿到 4 个
2。 - 玩家起手全小,即手牌中没有
2、A、K、Q、J。
如果满足条件,本小局立即结束并进入计分。若多人同时满足,当前实现按座位顺序
先检查到的玩家获胜。
小局结束
任意玩家出完最后一张手牌后,本小局结束。界面会展示:
- 本局胜者。
- 每名玩家剩余张数。
- 每名玩家倍率。
- 本局加分。
- 累计总分。
计分
胜者本局加 0 分。其他玩家按剩余牌数量计算惩罚分:
本局加分 = 剩余张数 * 倍率
倍率规则:
| 剩余张数 | 倍率 |
|---|---|
| 0 到 7 张 | x1 |
| 8 到 9 张 | x2 |
| 10 到 12 张 | x3 |
| 13 张 | x4 |
任一玩家累计达到 100 分时整局结束。当前实现没有额外的排名算法,最终以积分板
展示的累计分作为结果参考;分数来自剩余牌惩罚,通常越低越好。
房间规则
- 房间号为 4 位十六进制字符。
- 房主创建房间后自动进入等待区。
- 玩家加入房间时会自动获得昵称。
- 同一浏览器刷新页面会复用本地
playerId,不会重复占座。 - 房主退出会释放房间。
- 普通玩家只能在等待区退出;牌局开始后暂不支持中途退出。
- 每小局结束后,所有玩家都点击“继续”才会开始下一小局。
- 整局结束后房间会保留短暂倒计时,方便查看结算,然后释放。
前端交互规则
- “提示”会选择后端返回的第一手可出牌。
- “出牌”按钮只在轮到自己且已选择手牌时可用。
- “过牌”按钮只在轮到自己且无牌可管时可用。
- 无牌可管时,前端会提示并在 5 秒后自动过牌。
- 手牌和桌面状态通过轮询同步,其他玩家出牌后会自动刷新界面。