Files
werewolf/README.md
T

154 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 狼人杀 · Werewolf
一个 **网页联机狼人杀框架**:FastAPI + WebSocket 后端,React + TypeScript + Sass 前端,
支持 **真人玩家与 AI 玩家混合对局**,人数与板子可选,多人从不同浏览器/设备加入同一房间。
![技术栈](https://img.shields.io/badge/FastAPI-WebSocket-009688) ![前端](https://img.shields.io/badge/React-TypeScript Sass Vite-61dafb) ![环境](https://img.shields.io/badge/uv-pnpm-管理)
## 功能特性
- **人机混战**:真人玩家占座后,空位一键补满 AI;也可以全部由 AI 对战观战
- **真正的多人联机**:房间码制,局域网/公网多设备加入,断线自动重连不掉座
- **经典板子**:
- 经典 12 人局(4 狼 4 民 预言家/女巫/猎人/守卫)
- 标准 10 人局(3 狼 3 民 预女猎守)
- 快节奏 9 人局(3 狼 3 民 预女猎)
- **完整规则**:守卫守护(不可连守)→ 狼人刀人 → 预言家验人 → 女巫双药(首夜可自救、同守同救会死)
→ 警长竞选(警长 1.5 票、警徽流转、可撕徽)→ 白天发言 → 投票放逐 → 猎人开枪 → 屠边/屠城胜负判定
- **AI 玩家(LLM 驱动)**:接入任意 OpenAI 兼容大模型(DeepSeek / 智谱 / Kimi / OpenAI / 本地 Ollama …),
AI 有人设性格、第一人称发言、夜间决策与投票;**未配置密钥时自动回退内置启发式 AI,开箱即玩**
- **网页界面**:座位圈、阶段横幅与倒计时、个人私密信息面板(身份/狼队友/查验/药水)、公开+私密对局记录、
按阶段切换的行动面板、结算复盘弹窗
- **亮/暗主题**:默认清爽浅色(白底 + 靛蓝主色),右上角 🌙/☀️ 一键切换暗色(深蓝灰),选择自动记忆
## 快速开始
### 环境要求
- [uv](https://docs.astral.sh/uv/)(管理 Python 后端环境,会自动安装 Python 解释器)
- [pnpm](https://pnpm.io/) + Node.js 18+(管理前端)
### 方式一:单进程游玩(推荐)
```bash
# 1. 构建前端
cd frontend
pnpm install
pnpm build
# 2. 启动后端(自动托管前端构建产物)
cd ../backend
uv sync
uv run python run.py
```
打开 **http://127.0.0.1:8000** —— 填昵称、创建房间、把房间号发给朋友,
各自浏览器打开后输入房间号加入,空位补 AI,开始游戏。
> 局域网联机:同一 WiFi 下的朋友访问 `http://<你的IP>:8000` 即可。
### 方式二:前端开发模式(热更新)
```bash
# 终端 1:后端
cd backend && uv sync && uv run uvicorn app.main:app --port 8000
# 终端 2:前端(Vite 会把 /api 与 /ws 代理到 8000 端口)
cd frontend && pnpm install && pnpm dev
```
打开 http://127.0.0.1:5173。
## 接入大模型 AI(可选)
```bash
cd backend
cp config.example.json config.json # Windows: copy config.example.json config.json
```
编辑 `config.json`,填入任意 OpenAI 兼容服务:
```json
{
"llm": {
"base_url": "https://api.deepseek.com/v1",
"api_key": "sk-xxxx",
"model": "deepseek-chat",
"temperature": 0.8
}
}
```
常见服务商的 `base_url`:
| 服务商 | base_url | 模型示例 |
|---|---|---|
| DeepSeek | `https://api.deepseek.com/v1` | `deepseek-chat` |
| 智谱 GLM | `https://open.bigmodel.cn/api/paas/v4` | `glm-4-flash` |
| Moonshot Kimi | `https://api.moonshot.cn/v1` | `moonshot-v1-8k` |
| OpenAI | `https://api.openai.com/v1` | `gpt-4o-mini` |
| 本地 Ollama | `http://localhost:11434/v1` | `qwen2.5:7b` |
- 也可用环境变量覆盖:`WEREWOLF_LLM_BASE_URL` / `WEREWOLF_LLM_API_KEY` / `WEREWOLF_LLM_MODEL`
- **不配置或配置错误都不会影响游戏**:AI 自动回退到内置启发式逻辑(调用失败也会单次降级,不会卡局)
- 大厅页底部会显示当前 AI 状态(大模型已接入 / 启发式 AI)
## 房间操作说明
| 操作 | 说明 |
|---|---|
| 创建房间 | 大厅点击「创建房间」生成 4 位房间码,创建者成为房主 |
| 加入房间 | 输入房间号加入,自动分配空座位;对局中进入则为观战 |
| 补 AI | 房主可「+ 添加 AI」逐个加,或「⚡ 一键补满 AI」 |
| 开始游戏 | 座位满员后房主点击「开始游戏」,私发身份 |
| 断线重连 | 刷新/断网后重新进入同一房间自动回到原座位(对局中为观战) |
| 再来一局 | 结算后房主点击「回到房间」,全员身份重置回大厅 |
## 游戏规则细节
- **夜晚顺序**:守卫 → 狼人(狼队互相可见,先选的刀口生效)→ 预言家 → 女巫
- **女巫**:解药/毒药各一瓶,每夜限用一瓶;首夜可自救;同守同救会死
- **警长**:首日竞选,警长票计 1.5 票;警长死亡可移交警徽或撕徽
- **猎人**:被刀或被放逐时可开枪,被毒杀不能开枪
- **放逐**:平票无人出局,不翻牌
- **胜负**:默认屠边(狼人杀光全部神职或全部村民即获胜),房主可切换屠城(狼数 ≥ 好人数)
## 项目结构
```
├── backend/ # uv 管理的 FastAPI 后端
│ ├── pyproject.toml
│ ├── config.example.json # 复制为 config.json 接入大模型
│ ├── run.py # 启动入口
│ ├── smoke_test.py # 纯 AI 完整对局冒烟测试
│ ├── ws_test.py # 双真人 + AI 无头联机测试
│ ├── side_player.py # 加入指定房间自动玩的随从客户端
│ └── app/
│ ├── main.py # REST + WebSocket + 静态托管
│ ├── config.py # 配置加载
│ └── game/
│ ├── roles.py # 角色定义
│ ├── board.py # 板子预设
│ ├── player.py # 玩家实体
│ ├── room.py # 房间/连接管理/快照广播
│ ├── engine.py # 昼夜状态机引擎
│ └── ai/ # LLM 客户端、提示词、Agent、启发式兜底
└── frontend/ # pnpm + Vite + React + TS + Sass 前端
├── vite.config.ts # dev 代理 /api /ws
└── src/
├── pages/ # Lobby 大厅 / Room 房间
├── components/ # 座位圈/阶段横幅/行动面板/信息面板/日志/结算
├── api/ws.ts # WebSocket 封装(自动重连)
├── types.ts # 与后端对齐的消息协议类型
└── styles/ # Sass 主题变量与全局样式
```
## 开发测试
```bash
cd backend
uv run python smoke_test.py # 12 个内置 AI 完整对局
uv run python ws_test.py # 2 个程序化真人 + AI,覆盖建房/重连/重置
uv run python side_player.py 房间号 # 让一个自动玩家加入你的房间
```