Files
mcm-26-b/referee/README.md
T
2026-09-11 11:36:08 +08:00

66 lines
5.6 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.
# mcm26b-referee — CUMCM 2026 B 题独立评测机
自建的官方模拟器复现:**模拟器引擎 + 机器狗 HTTP 接口 + 官方流程 WebUI**,
作为一个**独立包**发布(本目录),零第三方依赖,且**不导入任何参赛队代码**。
与参赛队实现(仓库根的 `mcm26b` 包)完全解耦:双方只通过附件2 定义的
HTTP 协议耦合——评测机换任何客户端都成立,参赛队代码对接官方模拟器也无需改动。
```bash
uv sync # 根工作区会同时挂载本包(dev 依赖)
uv run python -m referee # WebUI http://127.0.0.1:8026,接口 :2026
uv run pytest referee/tests # 本包测试
```
- 浏览器打开 `http://127.0.0.1:8026`:选择测试模块 → 确认开始 → 5 秒倒计时 →
接口开放,地图/状态/指令与反馈实时可见;
- **回放器**("回放"Tab):按案例加载存档回放,也可**手动选定 JSONL 文件**(点击
选择或拖拽导入,纯前端解析;兼容评测机行为日志与参赛队客户端会话日志两种格式),
支持播放/暂停、逐步±、倍速快进、缩放/平移、进度条定位;
- 机器狗程序照常对接 `http://127.0.0.1:2026`(如 `uv run mcm26b run --robot-id 2026001 --base-url http://127.0.0.1:2026`,
或一键 `uv run mcm26b run --robot-id 2026001 --local-judge`)。
## 包结构
```
referee/src/referee/
├── spec.py # 题面常量:目标区域/频道/半径/限时/耗时模型([题面] 逐条标注)
├── rules.py # 服务端字段表、结果码与 HTTP 语义(附件2 §5-9 的可执行表格)
├── timing.py # 纯计时模型:移动+换频道+动作,整数微秒累计(105/111/194/199 锚点)
├── simulator.py # 评测引擎:观测判定、状态机、幂等、并发 409、截止与断连
├── jsonio.py # 请求严格解析(BOM/重复键/NaN/深度)+ 响应规范化序列化
├── interface.py # 机器狗接口完整边界(与传输无关;HTTP 服务器与内存直连共用)
├── server.py # 接口 HTTP 承载:仅回环、仅窗口期监听、关闭即断连
├── session.py # 官方流程状态机:四模块/次数/倒计时/窗口/中止/结束原因/日志
├── scenes.py # 一局真值的数据准备(q3 全向 / q4 混合,可固定种子)
├── webui.py # 界面服务器与 /ui/api/*
└── static/ # 单页前端(原生 HTML/CSS/JS,离线可用)
```
## 题意符合性对照(附件1《模拟器使用说明》/附件2《通信接口说明》)
| 题意条款 | 实现 | 固化测试 |
| --- | --- | --- |
| 表1 动作与耗时(移动=距离/5、换频道 1s、检测 5s、清除 5s/3s,逐段整数微秒累计) | `timing.py` + `simulator.py` | `test_timing_examples.py`(105/111/194/199) |
| 观测判定:no_signal/near(≤5m)/direction(±1° 误差、两位小数、[0,360) 归一化);定向 ±90° 含边界;清除 ≤20m 与朝向无关、仅一次 | `simulator.py` | `test_simulator_conformance.py` |
| 协议边界:路径精确/仅 POST/415/413/严格 JSON/未知字段 accepted=false/幂等回放/409/并发 409 | `interface.py` + `simulator.py` | `test_interface_boundary.py`、`test_http_server.py`(真实 HTTP) |
| 时限:5s 倒计时、25min 窗口、/enter 后 20min(取早)、虚拟 100h;截止后接口关闭、已登记动作允许完成 | `session.py` 看门狗 + `simulator.py` | `test_session_flow.py` |
| 四个测试模块;演练不限次;正式各 3 次、启动成功即占用、中止仍占用;正式开始前再次确认 | `session.py` + WebUI | `test_session_flow.py` |
| 指令与反馈:默认最新 1000 条、可调 100..5000、不限请求总数、完整行为入日志 | `session.py` + WebUI 设置 | `test_session_flow.py` |
| 中止测试需两次确认;结束后不能复位或继续,只能开始新一局;结束原因显示 | WebUI + `session.py` | `test_session_flow.py` |
| 测试案例编码;演练结束显示 总数/全向/定向;正式任何界面不显示真值 | `session.py` 真值策略 + WebUI | `test_session_flow.py` |
| 接口地址默认 127.0.0.1:2026、只监听回环、空闲可改端口;非开放期连接失败属正常 | `server.py` + WebUI 设置 | `test_http_server.py` |
| robot_id/request_id 格式(1..64/128 字节、无控制/格式字符);arena_id="default" | `simulator.py` + `session.py` | `test_simulator_conformance.py` |
| 响应 virtual_time_s 微秒累计、最多 6 位小数去尾零;accepted=false 时恒为 0 | `jsonio.py` + `simulator.py` | `test_jsonio.py` |
| 行为日志可导出;加密上传上限 2MB 提示 | WebUI 日志导出 + 大小告警 | `test_session_flow.py` |
### 自建差异声明(题面未规定,均为 [工程] 假设,不代表官方实现)
- **联网登录/官方校时/17:30 启动截止/加密上传队列**:属官方服务器侧策略,本地评测机
不实现;robot_id 由界面填写并照常参与逐字节校验。
- **示向度误差场**:同一(频道,位置)误差由种子确定性决定(重复测量不变,
题面仅要求"同一地点误差不变"),不同位置独立白噪声;分布不代表官方。
- **场景分布**:源位置在目标圆域内均匀、r_eff 在 [1000,1500] 均匀、频道无重复抽样;
q4 定向源数量默认 3;均可用种子复现。
- **429 流量保护/幂等记录上限**:正常串行合法请求无速率上限 [题面],本地不设限。
- **案例编码格式**:4×4 大写字母数字(去易混字符),格式自拟。