Files
Poker/server/cards.js
T
agomizi1cmandClaude Opus 5.5 d92953a270 Use @pokertools/engine and evaluator for poker rules and hand ranking
Replace the hand-rolled betting rules, side pots, showdown and hand
evaluator with the published @pokertools/engine and @pokertools/evaluator
libraries (MIT, pinned to 2.1.0).

- server/hand.js now wraps a PokerEngine per hand: it maps seats,
  mirrors stacks, staggers the all-in runout, and pays host-chosen
  winners on cash-only tables.
- server/cards.js and server/ai.js use the library evaluator.
- Out-of-turn folds go through the engine's stand; all-in hands stay
  live when the player leaves; uncalled bets return to a leaver.
- The engine refuses some check-able folds that would leave a side pot
  without eligible players; those now return a message (or check for
  a leaving player) instead of crashing.
- BB must be greater than SB (engine requirement); Node >= 24.
- Tests rig cards via engine snapshots and cover the new edge cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 17:25:15 +09:00

51 lines
2.0 KiB
JavaScript
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.
'use strict';
// 役の判定は @pokertools/evaluator(@pokertools/engine のショーダウンと同じ判定器)を使う。
// ここでは表示用に、最強の5枚と日本語の役名を求める。
// カードは "As"(スペードのA), "Td"(ダイヤの10)のような2文字
const { evaluate, getCardCodes, rank, HandRank } = require('@pokertools/evaluator');
const HAND_NAMES = {
[HandRank.HighCard]: 'ハイカード',
[HandRank.OnePair]: 'ワンペア',
[HandRank.TwoPair]: 'ツーペア',
[HandRank.ThreeOfAKind]: 'スリーカード',
[HandRank.Straight]: 'ストレート',
[HandRank.Flush]: 'フラッシュ',
[HandRank.FullHouse]: 'フルハウス',
[HandRank.FourOfAKind]: 'フォーカード',
[HandRank.StraightFlush]: 'ストレートフラッシュ',
};
const ROYAL_FLUSH = 1; // 判定器のスコアは小さいほど強く、1 がロイヤルフラッシュ
// 5〜7枚の中で最も強い役。score は小さいほど強い
function bestHand(cards) {
const codes = getCardCodes(cards);
const score = evaluate(codes);
const name = score === ROYAL_FLUSH ? 'ロイヤルフラッシュ' : HAND_NAMES[rank(codes)];
// 役を作っている5枚(7枚から5枚を選ぶ21通りで、全体と同じ強さになる組)
let five = cards.slice(0, 5);
if (cards.length > 5) {
const n = cards.length;
const pick = (start, chosen) => {
if (chosen.length === 5) return evaluate(chosen.map((i) => codes[i])) === score ? chosen.slice() : null;
for (let i = start; i <= n - (5 - chosen.length); i++) {
chosen.push(i);
const found = pick(i + 1, chosen);
chosen.pop();
if (found) return found;
}
return null;
};
five = pick(0, []).map((i) => cards[i]);
}
return { score, cards: five, name };
}
// a が強ければ正、b が強ければ負、同じ強さなら 0
function compareScore(a, b) {
return b - a;
}
module.exports = { bestHand, compareScore };