// 登録してあるハンドレンジ(ハンドレンジ学習ページとレビュー付きCPU戦で共用・管理者専用) (function (root, factory) { if (typeof module === 'object' && module.exports) module.exports = factory(); else root.HandRange = factory(); })(typeof self !== 'undefined' ? self : this, function () { 'use strict'; const RANKS = ['A', 'K', 'Q', 'J', 'T', '9', '8', '7', '6', '5', '4', '3', '2']; // 強い順。tier が大きいほど強い(レビューでは「一つ上」「二つ上」をこの段階で数える) // 人数は「自分を含めず、まだ行動していない人の数」(自分より前に誰もコール・レイズしていないとき)。 // 紫枠は後ろが1人(SB で全員が降りて回ってきた)ときだけオープンできる手として、白の一つ下に置く const CATEGORIES = [ { id: 'navy', name: '紺', label: '8人(強)', tier: 7 }, { id: 'red', name: '赤', label: '8人(弱)', tier: 6 }, { id: 'yellow', name: '黄', label: '6〜7人', tier: 5 }, { id: 'green', name: '緑', label: '4〜5人', tier: 4 }, { id: 'blue', name: '青', label: '3人', tier: 3 }, { id: 'white', name: '白', label: '2人', tier: 2 }, { id: 'purple', name: '紫枠', label: '紫枠', tier: 1 }, { id: 'gray', name: 'グレー', label: 'フォールド', tier: 0 }, ]; // 全169ハンドの分類(載っていないハンドはフォールド)。紫枠はクイズ上の独立した回答 const RANGE = { AA: 'navy', AKs: 'navy', AQs: 'red', AJs: 'red', ATs: 'red', A9s: 'green', A8s: 'green', A7s: 'green', A6s: 'green', A5s: 'green', A4s: 'green', A3s: 'green', A2s: 'green', AKo: 'navy', KK: 'navy', KQs: 'red', KJs: 'yellow', KTs: 'green', K9s: 'green', K8s: 'white', K7s: 'white', K6s: 'white', K5s: 'white', K4s: 'white', K3s: 'white', K2s: 'white', AQo: 'red', KQo: 'yellow', QQ: 'navy', QJs: 'yellow', QTs: 'green', Q9s: 'blue', Q8s: 'white', Q7s: 'white', Q6s: 'white', Q5s: 'purple', Q4s: 'purple', Q3s: 'purple', Q2s: 'purple', AJo: 'yellow', KJo: 'green', QJo: 'blue', JJ: 'red', JTs: 'yellow', J9s: 'blue', J8s: 'white', J7s: 'white', J6s: 'purple', ATo: 'green', KTo: 'blue', QTo: 'white', JTo: 'blue', TT: 'red', T9s: 'green', T8s: 'blue', T7s: 'purple', A9o: 'blue', K9o: 'white', Q9o: 'white', J9o: 'white', T9o: 'white', 99: 'red', '98s': 'blue', '97s': 'white', '96s': 'purple', A8o: 'white', '98o': 'purple', 88: 'yellow', '87s': 'white', '86s': 'purple', A7o: 'white', 77: 'yellow', '76s': 'white', '75s': 'purple', A6o: 'purple', 66: 'green', '65s': 'white', '64s': 'purple', 55: 'green', '54s': 'purple', 44: 'blue', 33: 'blue', 22: 'blue', }; const BY_ID = new Map(CATEGORIES.map((c) => [c.id, c])); // 13×13 の表の (行, 列) のハンド。右上がスーテッド、左下がオフスート const handAt = (r, c) => (r === c ? RANKS[r] + RANKS[c] : r < c ? RANKS[r] + RANKS[c] + 's' : RANKS[c] + RANKS[r] + 'o'); const categoryOf = (hand) => RANGE[hand] || 'gray'; const category = (id) => BY_ID.get(id) || BY_ID.get('gray'); const labelOf = (id) => category(id).label; const tierOf = (hand) => category(categoryOf(hand)).tier; const categoryOfTier = (tier) => CATEGORIES.find((c) => c.tier === tier) || BY_ID.get('gray'); // ["As", "Kd"] → "AKo" function handKey(cards) { const [a, b] = cards; const ia = RANKS.indexOf(a[0]); const ib = RANKS.indexOf(b[0]); const hi = ia <= ib ? a : b; const lo = ia <= ib ? b : a; if (hi[0] === lo[0]) return hi[0] + lo[0]; return hi[0] + lo[0] + (hi[1] === lo[1] ? 's' : 'o'); } // 自分より前に誰もコール・レイズしていないとき、後ろの人数(自分を含めず、まだ行動していない人)で // 参加してよい一番弱い段階。8人以上は赤(紺は赤の一つ上)。0人(全員降りてBBに回った)は無し function requiredTier(behind) { if (behind >= 8) return 6; if (behind >= 6) return 5; if (behind >= 4) return 4; if (behind === 3) return 3; if (behind === 2) return 2; if (behind === 1) return 1; return 0; } return { RANKS, CATEGORIES, RANGE, handAt, handKey, categoryOf, category, labelOf, tierOf, categoryOfTier, requiredTier }; });