記分板新增隨機配對、計分人權限與換人計分,調整按鈕排法
根本原因: 每打完一輪都要人工決定誰上場、誰搭誰、誰負責記分,記分板也沒有「兩隊對換」和退回選先發球的操作,現場排場地或換人都得重開記分板。 影響: /記分 多一顆 🎲 隨機配對:勾選出席者(預設全選)後,依 tg_members.skill 與今天的 history 戰績排 2、3 號場地(休息最久優先、搭檔與對手不重複、實力平衡),預覽後一鍵推出各場地記分板;每場從休息者抽一位計分人(SCORER_EXCLUDE 不抽),只有他和管理員能按,休息人不夠則不鎖權限;開局可 🙋 換人計分、🔃 🅰️🅱️ 對換;計分鍵盤改為左欄 🅰️+1/🅱️+1,拿掉「重新開始」,0:0 時上一步可退回選先發球。 修法: - 新增 src/pairing.js:移植 badminton-match-hub V2 的配對規則,改成一次只排下一輪、以「休息輪數」取代平均場數;assignScorers 從休息者抽計分人 - history.js 新增 loadTodayGames 讀今日戰績;signup.js attendees() 帶 skill 與 user_id(權限靠 TG id 比對) - scoreboard.js 以 phase(pick → roster → paired)管理同一則訊息的選人/勾選/預覽流程,推出的記分板 ownerId 指向計分人;新增換人計分(ho / hoN / hoany / hocancel),候選排除場上、現任計分人與 SCORER_EXCLUDE - match.js 新增 swapTeams,setFirstServer 記入 history 讓 undo 可退回開局;render.js 重排鍵盤並新增勾選、預覽、換人面板與場地標題 - config 新增 SCORER_EXCLUDE;README、.env.example 與 37 個測試同步更新 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ Telegram bot「建喵打羽球 @JianMiauBadmintonBot」的 Node.js 版本,包
|
||||
| `/羽球名單` | `/bdlist` | 回今天的參加名單 |
|
||||
| `/羽球暱稱 名字` | `/bdname` | 設定報名顯示的名字(存 `tg_members`,綁 user_id) |
|
||||
| `/記分` | `/score`、`/new` | 列出今天出席的人(`attendance`),依 1→4 點選上場人員:1、2 一隊,3、4 一隊;點滿 4 人自動開局,選 2 人可按「單打開始」 |
|
||||
| `/記分` → `🎲 隨機配對` | | 勾選今天要排的人(預設全選)→ 依 `tg_members.skill` 與今天的 `history` 戰績自動排 2、3 號場地 → 預覽後一鍵推出各場地的記分板(見下方「隨機配對」) |
|
||||
| `/記分 小明 小華 vs 阿強 阿美` | `/score`、`/new` | 直接開一場雙打記分板(單打各 1 人;最後加數字可改目標分) |
|
||||
| `/help` | | 指令說明 |
|
||||
|
||||
@@ -30,19 +31,42 @@ Telegram bot「建喵打羽球 @JianMiauBadmintonBot」的 Node.js 版本,包
|
||||
|
||||
- **權限**:只有開局者(下 `/記分` 的人)或群組管理員(creator / administrator,查詢結果快取 5 分鐘)能按;其他人按了只跳提示「只有開局者或群組管理員可以操作記分板」。報名按鈕不受限。
|
||||
|
||||
- 選人(無參數開局):點名字依序標 1️⃣~4️⃣,`↩️ 取消上一位`、`▶️ 單打開始`(剛好 2 人時)、`✖️ 取消`
|
||||
- 開局:`🅰️ / 🅱️ 先發球`;雙打可 `🔀 換位` 決定誰站右區(誰先發/先接)
|
||||
- 進行中(三排):`🅰️ +1` `🅱️ +1` / `↩️ 上一步` `🔄 重新開始` / `⏱ 結算` `🏁 結束`
|
||||
- 選人(無參數開局):點名字依序標 1️⃣~4️⃣,`↩️ 取消上一位`、`▶️ 單打開始`(剛好 2 人時)、`🎲 隨機配對`(還沒點人時)、`✖️ 取消`
|
||||
- 開局:`🅰️ / 🅱️ 先發球`;雙打可 `🔀 換位` 決定誰站右區(誰先發/先接);`🔃 🅰️🅱️ 對換` 把兩隊上下對調(只能在 0:0);`🙋 換人計分` 轉交計分人(見下方「計分人」)
|
||||
- 進行中(左欄上下是加分):`🅰️ +1` `↩️ 上一步` / `🅱️ +1` `⏱ 結算` / `🏁 結束`;`↩️ 上一步` 在 0:0 時會退回「選先發球」(所以沒有「重新開始」)
|
||||
- `⏱ 結算`:時間到以目前比分定勝負(領先方 🏆、同分平手),可 `上一步` 復原
|
||||
- 分出勝負顯示 🏆;`🏁 結束` 需兩段確認(第一次按 → 出現 `✅ 確定結束 / ↩️ 取消`,按其他按鈕也會取消),確定後移除按鈕、鎖定
|
||||
- 規則:偶數分右區發、發球方得分同隊換位續發、失分換發不換位、21 分制、Deuce 領先 2 分、30 分封頂(與 badminton-scoreboard 一致)
|
||||
|
||||
### 隨機配對(`/記分` → `🎲 隨機配對`)
|
||||
|
||||
同一則訊息依序經過三個階段(`phase`:`pick` → `roster` → `paired`),權限同記分板(開局者/管理員):
|
||||
|
||||
1. **勾選名單**:今天出席的人全部預設 ✅,點名字切換,`✅ 全選 / ⬜ 全不選`;至少 4 人。`↩️ 返回選人` 回到 1→4 點選
|
||||
2. **配對預覽**:顯示 `2️⃣ 號場地 🅰️ … vs 🅱️ …`、`3️⃣ 號場地 …`、`😴 休息:…`;`🔁 重新配對` 再抽一次、`↩️ 返回勾選` 改名單
|
||||
3. **`✅ 開記分板`**:每個場地各推一則記分板(標題帶場地號、`📝 計分:某某`);預覽訊息鎖定
|
||||
|
||||
**計分人**(權限靠 `attendance.user_id` 對 Telegram 帳號):
|
||||
|
||||
- 每個場地從 **休息的人** 隨機抽一位當計分人,只有他和群組管理員能按那則記分板;`SCORER_EXCLUDE`(`.env`,逗號分隔暱稱,例如 `景涵`)裡的人不會被抽到
|
||||
- 休息人數不夠(一場一人)→ 該場顯示 `📝 計分:任何人`,不鎖權限
|
||||
- **`🙋 換人計分`**(開局鍵盤,只能在還沒選先發球前):由目前計分人或管理員操作,列出今天出席、不在場上、不是現任計分人、不在排除名單的人,點一下就轉交;也可改成「任何人」;已選先發球但還是 0:0 時,按 `↩️ 上一步` 退回就能換
|
||||
- `/記分 A B vs C D` 或 1→4 點選開的記分板仍是開局者持有,但一樣可用 `🙋 換人計分` 轉交
|
||||
|
||||
配對規則(`src/pairing.js`,移植自 badminton-match-hub V2 並改成一次只排下一輪):
|
||||
|
||||
- **誰上場**:不是平均場數,而是「每個人都要休息到」——依今天 `history` 戰績算「休息了幾輪」(一輪 = 場地數),休息最久的優先、剛打完的最後;同輪再比今天打的場數少者優先,最後隨機。沒打過的人一定上場
|
||||
- **搭檔**:今天沒搭過的優先(`16^搭檔次數` 加總最小),不重複的前提下各組實力總和最接近(強弱互補)
|
||||
- **對戰**:兩隊實力總和最接近優先,再挑今天對戰次數最少的組合;兩場隨機分到 2、3 號場地
|
||||
- **實力**:`tg_members.skill`(1~10,優先用 `user_id` 對,對不到用暱稱對,都沒有當 1),與 match-hub 相同;bot 只讀不寫這欄
|
||||
- 8 人以上排 2、3 號場地各一場,4~7 人只排 2 號場地;讀不到 `history` 時照配、預覽會標示未考慮戰績
|
||||
|
||||
## 安裝與啟動
|
||||
|
||||
```bash
|
||||
npm install
|
||||
cp .env.example .env # 填 BOT_TOKEN、DB_*、ALLOWED_CHAT_IDS
|
||||
npm test # 15 個單元測試(規則、報名流程、選人、指令解析)
|
||||
npm test # 35 個單元測試(規則、報名流程、選人、隨機配對、歷史戰績、指令解析)
|
||||
npm start # 或 npm run dev
|
||||
```
|
||||
|
||||
@@ -89,7 +113,7 @@ sudo docker compose up -d --build
|
||||
- `starter` 發球位置編號 0~3 = 畫面 1~4 號位減 1(🅰️ 上排:偶數分 0、奇數分 1;🅱️ 下排:偶數分 2、奇數分 3;只看位置不看人)
|
||||
- `winCount` 同隊連續得分數,第一分為 0
|
||||
- `winner` 得分隊 0 = 🅰️、1 = 🅱️
|
||||
- 上一步會一併回退;重新開始清空;結算不影響
|
||||
- 上一步會一併回退(退回選先發球時清空);再一局清空;結算不影響
|
||||
|
||||
## 專案結構
|
||||
|
||||
@@ -100,12 +124,14 @@ src/
|
||||
db.js mysql2 連線池
|
||||
util.js 共用小工具(HTML 跳脫、日期、指令 regex)
|
||||
signup.js 報名功能(移植自 Node-RED bd_sm 狀態機)
|
||||
scoreboard.js 記分板功能
|
||||
scoreboard.js 記分板功能(含選人 / 隨機配對流程)
|
||||
match.js 羽球規則(純邏輯)
|
||||
render.js 記分板文字 + 鍵盤
|
||||
pairing.js 隨機配對規則(純邏輯:休息輪數、搭檔 / 對手不重複、實力平衡)
|
||||
history.js history 表寫入 / 讀今日戰績
|
||||
render.js 記分板、選人、勾選、配對預覽的文字 + 鍵盤
|
||||
store.js 記分板狀態持久化
|
||||
scripts/
|
||||
nodered-switch.mjs 暫停 / 恢復 Node-RED 舊流程
|
||||
test/
|
||||
match.test.js signup.test.js
|
||||
match.test.js pairing.test.js scoreboard.test.js history.test.js signup.test.js
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user