基于python+html的桂林跑牌




2026-04-30

blog_main_img

基于python做的web端桂林跑牌

项目地址:桂林跑牌

# 桂林跑牌

一个使用 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
## 基本玩法流程 1. 打开大厅页,点击“建房”创建房间。 2. 把页面中的 4 位房间号告诉其他玩家。 3. 其他玩家在大厅输入房间号并加入。 4. 房主点击“开始”后进入第一小局。 5. 轮到自己时选择手牌并点击“出牌”;如果无牌可管,可以点击“过牌”。 6. 某名玩家先出完手牌后,本小局结束并展示结算。 7. 所有人点击“继续”后开始下一小局。 8. 任一玩家累计分达到 100 分,整局结束并展示最终积分。 ## 规则摘要 - 人数:2 到 4 人。 - 发牌:每人 13 张,剩余牌保留但当前不会摸牌。 - 首出:每小局随机一名玩家首出。 - 牌型:单张、对子、三张、四张、四连张。 - 大小:单张/对子/三张/四张按 `3 < 4 < ... < K < A < 2`。 - 四连张:最大 `AKQJ`,最小 `432A`;`KA2` 不算连续。 - 管牌:必须同牌型且点数更大;当前实现中四张不跨牌型压制其他牌型。 - 过牌:首出不能过;有牌可管时必须出,只有无牌可管时可以过。 - 直接胜利:起手拿到 4 个 2,或起手全小,立即赢得本小局。 - 小局结束:任一玩家先出完手牌。 - 计分:胜者本局不加分,其他玩家按剩余牌数量和倍率加分。 完整规则见 [docs/GAME_RULES.md](docs/GAME_RULES.md)。 ## 计分方式 | 剩余张数 | 倍率 | | --- | --- | | 0 到 7 张 | x1 | | 8 到 9 张 | x2 | | 10 到 12 张 | x3 | | 13 张 | x4 | 本局加分:
胜者:0
其他玩家:剩余张数 * 倍率
当前实现把累计分视为剩余牌惩罚分;任一玩家累计达到 100 分时整局结束,界面 保留积分列表供玩家查看最终结果。 ## API 文档 接口说明见 [docs/API.md](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 秒后自动过牌。 - 手牌和桌面状态通过轮询同步,其他玩家出牌后会自动刷新界面。

效果预览