Switch hand ranges to Poker Skill's 6-max charts with 3bet/call frames
- Replace the Yokosawa ranges with the 6-max opening ranges (UTG, HJ, CO, SB, BTN). Colors keep the old order: navy (strong UTG), red UTG, yellow HJ, green CO, blue SB, white BTN. SB is narrower than BTN, so blue sits one tier above white; the purple-frame category is gone. - Show the "BTN vs CO open" chart on the range page as frames: light blue for 3bet, yellow for call. - Grade BTN facing an unlimped CO open by those frames in reviews; other spots keep the color-tier rule (BB defends down to green). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
680aa20d30
commit
3ddb0996e0
8 files changed
+187
-86
No files matched your search
+75
-32
@@ -11,7 +11,7 @@ const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const HandRange = require('../admin/range-data');
|
||||
const { Table } = require('../server/tables');
|
||||
const { judgePreflop, positionOf } = require('../server/review/preflop');
|
||||
const { judgePreflop, positionOf, describeSituation } = require('../server/review/preflop');
|
||||
const { analyzeHand } = require('../server/review/analyze');
|
||||
const { showdownShare } = require('../server/review/equity');
|
||||
const { summarize } = require('../server/review/summary');
|
||||
@@ -54,9 +54,20 @@ test('ハンドレンジ: 手札の表記と、後ろの人数で必要な色',
|
||||
assert.equal(HandRange.handKey(['9c', '9d']), '99');
|
||||
assert.equal(HandRange.categoryOf('AA'), 'navy');
|
||||
assert.equal(HandRange.categoryOf('72o'), 'gray');
|
||||
assert.equal(HandRange.tierOf('Q5s'), 1); // 紫枠は白の一つ下
|
||||
assert.equal(HandRange.tierOf('Q5s'), 1); // BTN だけで開く手は白(SB の青より下)
|
||||
// レイズを受けたときの対応(枠)
|
||||
assert.equal(HandRange.facingOf('A5s'), '3bet');
|
||||
assert.equal(HandRange.facingOf('TT'), 'call');
|
||||
assert.equal(HandRange.facingOf('ATo'), null);
|
||||
const share = (id) => {
|
||||
const combos = (h) => (h.length === 2 ? 6 : h[2] === 's' ? 4 : 12);
|
||||
const n = Object.keys(HandRange.FACING).filter((h) => HandRange.facingOf(h) === id).reduce((a, h) => a + combos(h), 0);
|
||||
return Math.round((n / 1326) * 1000) / 10;
|
||||
};
|
||||
assert.equal(share('3bet'), 5.7);
|
||||
assert.equal(share('call'), 14.0);
|
||||
const req = [0, 1, 2, 3, 4, 5, 6, 7, 8].map((b) => HandRange.categoryOfTier(HandRange.requiredTier(b)).id);
|
||||
assert.deepEqual(req, ['gray', 'purple', 'white', 'blue', 'green', 'green', 'yellow', 'yellow', 'red']);
|
||||
assert.deepEqual(req, ['gray', 'blue', 'white', 'green', 'yellow', 'red', 'red', 'red', 'red']);
|
||||
});
|
||||
|
||||
test('ポジションの呼び方', () => {
|
||||
@@ -71,9 +82,9 @@ test('ポジションの呼び方', () => {
|
||||
test('プリフロップ: 前に参加者がいなければ、後ろの人数の色以上でオープン', () => {
|
||||
// 6人: UTG〜CO が降りて BTN(後ろに2人 → 白以上)
|
||||
for (const [cards, action, verdict] of [
|
||||
[['Kh', '8h'], 'raise', 'good'], // 白でレイズ
|
||||
[['Qh', '5h'], 'raise', 'loose'], // 紫枠は BTN ではオープンできない
|
||||
[['Qh', '5h'], 'fold', 'good'],
|
||||
[['Kh', '3h'], 'raise', 'good'], // 白でレイズ
|
||||
[['Qh', '3h'], 'raise', 'loose'], // レンジ外
|
||||
[['Qh', '3h'], 'fold', 'good'],
|
||||
[['Ah', 'Kd'], 'call', 'passive'], // レイズできる手でコール
|
||||
[['Ah', 'Kd'], 'fold', 'tight'],
|
||||
]) {
|
||||
@@ -89,44 +100,47 @@ test('プリフロップ: 前に参加者がいなければ、後ろの人数の
|
||||
assert.equal(j.verdict, verdict, `${cards} ${action}`);
|
||||
}
|
||||
|
||||
// SB に全員降りて回ってきた(後ろに1人 → 紫枠以上)
|
||||
// SB に全員降りて回ってきた(後ろに1人 → 青以上。SB は BTN より狭い)
|
||||
const t = makeTable(4);
|
||||
act(t, 'fold');
|
||||
act(t, 'fold');
|
||||
const sb = t.hand.toAct;
|
||||
act(t, 'raise', 30);
|
||||
give(t, sb, ['Qs', '4s']);
|
||||
give(t, sb, ['Ks', '4s']);
|
||||
const j = judgePreflop(t.hand, sb).judgments[0];
|
||||
assert.equal(j.situation.behind, 1);
|
||||
assert.equal(j.verdict, 'good');
|
||||
give(t, sb, ['Qs', '4s']); // 白は BTN だけ
|
||||
assert.equal(judgePreflop(t.hand, sb).judgments[0].verdict, 'loose');
|
||||
});
|
||||
|
||||
test('プリフロップ: 前に参加者がいたら、その人の色の一つ上でコール、二つ上でレイズ', () => {
|
||||
// 6人: UTG(後ろに5人 → 緑と推定)がレイズ。次の人(hero)の判定
|
||||
// 6人: HJ(後ろに4人 → 黄と推定)がレイズ。次の人(hero、CO)の判定
|
||||
for (const [cards, action, verdict] of [
|
||||
[['Kh', 'Qd'], 'call', 'good'], // 黄 = 緑の一つ上 → コール
|
||||
[['Kh', 'Qd'], 'call', 'good'], // 赤 = 黄の一つ上 → コール
|
||||
[['Kh', 'Qd'], 'raise', 'aggressive'],
|
||||
[['Jh', 'Jd'], 'raise', 'good'], // 赤 = 二つ上 → レイズ
|
||||
[['Jh', 'Jd'], 'call', 'passive'],
|
||||
[['Kh', 'Jd'], 'call', 'loose'], // 緑 = 同じ → フォールド
|
||||
[['Kh', 'Jd'], 'fold', 'good'],
|
||||
[['Ah', 'Ad'], 'raise', 'good'], // 紺 = 二つ上 → レイズ
|
||||
[['Ah', 'Ad'], 'call', 'passive'],
|
||||
[['Kh', '9h'], 'call', 'loose'], // 黄 = 同じ → フォールド
|
||||
[['Kh', '9h'], 'fold', 'good'],
|
||||
]) {
|
||||
const t = makeTable(6);
|
||||
const utg = act(t, 'raise', 30);
|
||||
act(t, 'fold');
|
||||
const hj = act(t, 'raise', 30);
|
||||
const hero = t.hand.toAct;
|
||||
act(t, action, action === 'raise' ? 90 : 0);
|
||||
give(t, hero, cards);
|
||||
const { judgments, estimated } = judgePreflop(t.hand, hero);
|
||||
assert.equal(estimated.get(utg), 4); // 緑
|
||||
assert.equal(estimated.get(hj), 4); // 黄
|
||||
assert.equal(judgments[0].situation.refTier, 4);
|
||||
assert.equal(judgments[0].verdict, verdict, `${cards} ${action}`);
|
||||
}
|
||||
|
||||
// BB: リンプ(コール)に対してはチェックでよい。二つ上ならレイズ
|
||||
const t = makeTable(4);
|
||||
act(t, 'call'); // UTG(後ろに3人 → 青)
|
||||
act(t, 'call'); // UTG(後ろに3人 → 緑)
|
||||
act(t, 'fold');
|
||||
act(t, 'call'); // SB: 青の一つ上と推定
|
||||
act(t, 'call'); // SB: 緑の一つ上と推定
|
||||
const bb = t.hand.toAct;
|
||||
act(t, 'check');
|
||||
give(t, bb, ['7h', '2d']);
|
||||
@@ -135,14 +149,43 @@ test('プリフロップ: 前に参加者がいたら、その人の色の一つ
|
||||
assert.equal(j.verdict, 'good');
|
||||
});
|
||||
|
||||
test('プリフロップ: 自分のレイズにリレイズされたら、相手と同じ色でもコールできる', () => {
|
||||
// 6人: UTG(hero、後ろに5人 → 緑)がオープン、HJ が3bet(緑の二つ上 → 赤と推定)、ほかは降りて hero に戻る
|
||||
test('プリフロップ: BTN で CO のオープンを受けたら、レンジ表の枠(水色枠は3bet、黄枠はコール)のとおり', () => {
|
||||
const coOpen = (cards, action, limp = false) => {
|
||||
const t = makeTable(6);
|
||||
act(t, limp ? 'call' : 'fold'); // UTG
|
||||
act(t, 'fold');
|
||||
act(t, 'raise', 30); // CO
|
||||
const hero = t.hand.toAct;
|
||||
assert.equal(hero, t.hand.button);
|
||||
act(t, action, action === 'raise' ? 90 : 0);
|
||||
give(t, hero, cards);
|
||||
return judgePreflop(t.hand, hero).judgments[0];
|
||||
};
|
||||
for (const [cards, action, verdict] of [
|
||||
[['Jh', 'Jd'], 'call', 'good'], // 赤 = 同じ → コール
|
||||
[['Jh', 'Jd'], 'fold', 'tight'],
|
||||
[['Kh', 'Qd'], 'call', 'loose'], // 黄 = 一つ下 → フォールド
|
||||
[['Kh', 'Qd'], 'fold', 'good'],
|
||||
[['Ah', 'Ad'], 'call', 'good'], // 紺 = 一つ上 → コール(二つ上はない)
|
||||
[['Ah', '5h'], 'raise', 'good'], // 水色枠 → 3bet
|
||||
[['Ah', '5h'], 'call', 'passive'],
|
||||
[['Th', 'Td'], 'call', 'good'], // 黄枠 → コール(色の決まりなら赤でレイズ)
|
||||
[['Th', 'Td'], 'raise', 'aggressive'],
|
||||
[['Qh', 'Jd'], 'call', 'good'], // 黄枠(色は CO の緑)
|
||||
[['Ah', 'Td'], 'call', 'loose'], // 枠なし → フォールド(色は HJ の黄)
|
||||
[['Ah', 'Td'], 'fold', 'good'],
|
||||
]) {
|
||||
const j = coOpen(cards, action);
|
||||
assert.equal(j.situation.rule, 'vsCO');
|
||||
assert.equal(j.verdict, verdict, `${cards} ${action}`);
|
||||
}
|
||||
assert.match(describeSituation(coOpen(['Th', 'Td'], 'call').situation, () => 'CPU'), /黄枠でコール/);
|
||||
// 前にリンプした人がいたら CO のオープンではないので、色の決まりで判定する
|
||||
assert.equal(coOpen(['Th', 'Td'], 'call', true).situation.rule, 'normal');
|
||||
});
|
||||
|
||||
test('プリフロップ: 自分のレイズにリレイズされたら、相手と同じ色でもコールできる', () => {
|
||||
// 6人: UTG(hero、後ろに5人 → 赤)がオープン、HJ が3bet(赤の二つ上はないので紺と推定)、ほかは降りて hero に戻る
|
||||
for (const [cards, action, verdict] of [
|
||||
[['Ah', 'Ad'], 'call', 'good'], // 紺 = 同じ → コール(二つ上はない)
|
||||
[['Ah', 'Ad'], 'fold', 'tight'],
|
||||
[['Jh', 'Jd'], 'call', 'loose'], // 赤 = 一つ下 → フォールド
|
||||
[['Jh', 'Jd'], 'fold', 'good'],
|
||||
]) {
|
||||
const t = makeTable(6);
|
||||
const hero = act(t, 'raise', 30);
|
||||
@@ -160,7 +203,7 @@ test('プリフロップ: 自分のレイズにリレイズされたら、相手
|
||||
});
|
||||
|
||||
test('プリフロップ: BB は 4BB までのオープンに広くコールし、三つ上でレイズ', () => {
|
||||
// 6人: CO(後ろに3人 → 青)がオープンして BB(hero)まで降りる。白以上でコール、赤以上でレイズ
|
||||
// 6人: CO(後ろに3人 → 緑)がオープンして BB(hero)まで降りる。青以上でコール、紺でレイズ
|
||||
const coOpen = (to, cards, action) => {
|
||||
const t = makeTable(6);
|
||||
act(t, 'fold');
|
||||
@@ -175,22 +218,22 @@ test('プリフロップ: BB は 4BB までのオープンに広くコールし
|
||||
return judgePreflop(t.hand, bb).judgments[0];
|
||||
};
|
||||
for (const [cards, action, verdict] of [
|
||||
[['Kh', '8h'], 'call', 'good'], // 白 = 青の一つ下 → コール
|
||||
[['Qh', '5h'], 'call', 'loose'], // 紫枠 → フォールド
|
||||
[['Kh', 'Qd'], 'call', 'good'], // 黄 = 二つ上 → まだコール
|
||||
[['Kh', '4h'], 'call', 'good'], // 青 = 緑の一つ下 → コール
|
||||
[['Qh', '5h'], 'call', 'loose'], // 白 → フォールド
|
||||
[['Kh', 'Qd'], 'call', 'good'], // 赤 = 二つ上 → まだコール
|
||||
[['Kh', 'Qd'], 'raise', 'aggressive'],
|
||||
[['Jh', 'Jd'], 'raise', 'good'], // 赤 = 三つ上 → レイズ
|
||||
[['Ah', 'Ad'], 'raise', 'good'], // 紺 = 三つ上 → レイズ
|
||||
]) {
|
||||
const j = coOpen(30, cards, action);
|
||||
assert.equal(j.situation.rule, 'bb');
|
||||
assert.equal(j.verdict, verdict, `${cards} ${action}`);
|
||||
}
|
||||
// 4BB を超えるオープンには、ほかの席と同じく一つ上が必要
|
||||
const big = coOpen(50, ['Kh', '8h'], 'call');
|
||||
const big = coOpen(50, ['Kh', '4h'], 'call');
|
||||
assert.equal(big.situation.rule, 'normal');
|
||||
assert.equal(big.verdict, 'loose');
|
||||
|
||||
// BTN(後ろに2人 → 白)のオープンには紫枠からコールできる。コールした BB のレンジも紫枠と推定する
|
||||
// BTN(後ろに2人 → 白)のオープンには白からコールできる。コールした BB のレンジも白と推定する
|
||||
const t = makeTable(6);
|
||||
for (let k = 0; k < 3; k++) act(t, 'fold');
|
||||
act(t, 'raise', 25);
|
||||
|
||||
Reference in new issue
Block a user