Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- **多平台记录**:集中查看 AC 记录、题目与逐次练习历史。
- **练习数据**:年度热力图、今日时间线、提交趋势和题目分布。
- **题友圈**:关注题友,查看他们在不同平台的做题动态。
- **随机抽题与段位認定**:按档位抽题(初级/中级/上级/超上级)或**自定义条件**(难度范围 + 标签),只看得到难度;点「开始做题」才揭题并起计时。也可以连做 4 道走一轮挑战,或者走不分段的**小随机**/**大随机**段位。**每日一题按你的水平定难度带**(等效 Rating ±200)。
- **本地优先**:数据保存在自己的电脑;零第三方运行依赖,无需构建。

## 功能预览
Expand Down Expand Up @@ -103,6 +104,7 @@ DX Rating 是本项目的娱乐向练习指标,不是 Codeforces 官方 Rating
- [平台接入与数据边界](docs/platforms.md)
- [DX Rating 与 B50 计分说明](docs/dx-rating.md)
- [练习历史与离线回测](docs/backtesting.md)
- [随机抽题与段位認定](docs/dan.md)
- [目录、数据模型与 API](docs/development.md)
- [Codeforces × maimai 统计实验](docs/cf-maimai-study.md)

Expand Down
237 changes: 237 additions & 0 deletions docs/dan.md

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ data/backups/ npm run backup 生成的快照目录
- `problem_times`(v5):用户手填的**每题完成用时**,`(user_id, platform, problem_id)` 唯一。与 `submissions.execution_time`(平台给的判题毫秒数)完全是两回事,所以单独一张表,不混用。只存原始秒数,不存换算后的 rating —— 曲线一改(`npm run study:export-dx`)所有读数都得跟着变,落库就会多出一个真相来源。
- `contests`(v6):`(platform, contest_id)` 主键,存比赛名与**开始时间**,也就是题目的「出题日期」。b35/b15 的分板看它,不看 AC 时间。数据来自 CF 的 `contest.list?gym=false`,同步时按 6 小时 TTL upsert 写入;`problem_id` 的前缀(`339:A` → 339)就是比赛 id。不按 `type` 过滤 —— `contest.list` 的 `type='ICPC'` 并不是「ICPC 赛制」,Div.3 与 Educational 全是它。v8 加了 `duration_seconds`(比赛时长):判定「比赛内提交」靠它 —— 首页的最快用时只认比赛窗口内的 AC,时长缺失的比赛一律不判,宁可不算也不猜。

- `dan_sessions` / `dan_stages`(v18,v19/v20 各加了一列):随机抽题与段位認定。一轮认定一行(档位、`kind` ∈ `challenge`/`single`/`daily`、题数、单题限时、rating 区间、状态),每道题一行(**抽题时快照下来的难度与限时**、`claimed_at`、计时器 id、结果)。难度快照进 `dan_stages` 而不是结算时回查题库,否则题库缓存过期或 CF 修订题目 rating 会让历史记录跟着变;`settlement_json` 同样在结束时冻结。v19 给 `dan_stages` 加了 `limit_seconds`:两个随机段位(`small_random` / `big_random`)rating 不分段、抽到的题横跨 800–2600,限时得随题走,NULL 表示沿用 session 的档位统一限时。v20 给 `dan_sessions` 加了 `tags_json`:自定义单题抽题(`tier='custom'`)的标签条件,NULL 表示无条件;难度范围复用本来就有的 `min_rating` / `max_rating`。随机段位沿用 `kind='challenge'`、自定义沿用 `kind='single'`,都靠 `tier` 区分 —— 加 `kind` 值要重建整张表(SQLite 改不了 `CHECK`)。一个用户同时只能有一轮 `active`,由 partial unique index `one_active_dan_per_user` 兜底。题号与链接在 `claimed_at` 之前不写入响应,详见 [随机抽题与段位認定](dan.md)。

时间统一存 UTC Unix 秒;执行时间为毫秒,内存为字节;缺失值为 NULL。删除用户或账号会级联删除相关提交,未来 UI 必须明确告知这一行为。

Schema 以 `PRAGMA user_version` 标记,当前版本由 `src/db/database.ts` 的迁移列表决定。初始化可重复运行;升级通过增量迁移保留记录。`openDatabase()` 在版本高于代码支持时拒绝打开、低于时按顺序补齐;只读面板则要求版本完全一致,并提示所需命令。
Expand Down Expand Up @@ -107,6 +109,12 @@ Schema 以 `PRAGMA user_version` 标记,当前版本由 `src/db/database.ts`
| `GET /api/sync/status` | 后台同步任务的当前进度与结果 |
| `GET /api/dx` | DX Rating 榜:曲线元信息、旧题 35 格 + 本年度新题 15 格(按**出题日期**分)、待填写清单(含未评定的题,`problemRating` 为 null)、缺出题日期的题数 |
| `POST /api/dx/time` · `POST /api/dx/time/clear` | 填写 / 清除某道题的完成用时(只接受已 AC 的 Codeforces 题) |
| `GET /api/dan` | 抽题面板与记录页:档位表、题库缓存是否就绪、每日一题的**难度**、进行中的一轮、历史记录。只读,冷缓存时返回 `poolReady: false` |
| `POST /api/dan/start` | 开一轮随机抽题 / 挑战 / 每日一题;已有一轮没结束时回 **409 `SESSION_ACTIVE`** |
| `POST /api/dan/claim` | 起计时并**唯一一次**下发题号与链接;幂等,重复点击返回同一道题。未 claim 的题只含难度,见 [dan.md](dan.md#口径-a开始做题之前链接不下发) |
| `POST /api/dan/settle` | **只结算、不抽题**。轮询走这条,所以出了成绩会停在结算页上;抽下一道要用户点「抽选下一题」走 `next` |
| `POST /api/dan/next` | 结算已同步到的 AC 并抽下一道;区间里没题了回 `poolEmpty` |
| `POST /api/dan/abandon` | 放弃进行中的一轮,释放进行中的计时器 |
| `POST /api/accounts` | 绑定账号;可选带凭据,直接写进 `.env`,值不回显 |
| `POST /api/accounts/unbind` | 解绑账号,必须带显式确认;回报连带删掉的提交条数 |
| `POST /api/accounts/replace` | 换绑同一用户的新账号,要求 `confirm: true`,旧账号归档、新账号从空记录开始 |
Expand Down
1 change: 1 addition & 0 deletions public/circle.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<a class="btn btn-ghost" href="/">AC 记录</a>
<a class="btn btn-primary" href="/circle.html" aria-current="page">题友圈</a>
<a class="btn btn-ghost" href="/dx.html">DX Rating</a>
<a class="btn btn-ghost" href="/dan.html">随机抽题</a>
<a class="btn btn-ghost" href="/stats.html">练习数据</a>
<a class="btn btn-ghost" href="/?admin=1">账号管理</a>
<a class="btn btn-ghost" href="/help.html">使用指南</a>
Expand Down
Loading