const RANKS = {
STRAIGHT_FLUSH: 8,
FOUR_OF_A_KIND: 7,
FULL_HOUSE: 6,
FLUSH: 5,
STRAIGHT: 4,
THREE_OF_A_KIND: 3,
TWO_PAIR: 2,
ONE_PAIR: 1,
HIGH_CARD: 0
};
export const bestHands = (hands) => {
const scoredHands = hands.map(hand => ({ hand, score: scoreHand(hand) }));
const maxScore = scoredHands.reduce((max, h) => compareScores(h.score, max) > 0 ? h.score : max, scoredHands[0].score);
return scoredHands.filter(h => compareScores(h.score, maxScore) === 0).map(h => h.hand);
};
function scoreHand(handStr) {
const cards = handStr.split(' ').map(c => {
const v = c.slice(0, -1);
const s = c.slice(-1);
return { value: v === '10' ? 10 : (isNaN(v) ? (v === 'J' ? 11 : (v === 'Q' ? 12 : (v === 'K' ? 13 : 14))) : Number(v)), suit: s };
}).sort((a, b) => b.value - a.value);
const values = cards.map(c => c.value);
const suits = cards.map(c => c.suit);
const counts = values.reduce((acc, v) => (acc[v] = (acc[v] || 0) + 1, acc), {});
const sortedCounts = Object.entries(counts).sort((a, b) => b[1] - a[1] || Number(b[0]) - Number(a[0]));
const isFlush = new Set(suits).size === 1;
let isStraight = values.every((v, i) => i === 0 || v === values[i - 1] - 1);
if (!isStraight && values[0] === 14 && values[1] === 5 && values[2] === 4 && values[3] === 3 && values[4] === 2) {
isStraight = true;
values.push(values.shift());
}
if (isStraight && isFlush) return [RANKS.STRAIGHT_FLUSH, values];
if (sortedCounts[0][1] === 4) return [RANKS.FOUR_OF_A_KIND, [Number(sortedCounts[0][0]), Number(sortedCounts[1][0])]];
if (sortedCounts[0][1] === 3 && sortedCounts[1][1] === 2) return [RANKS.FULL_HOUSE, [Number(sortedCounts[0][0]), Number(sortedCounts[1][0])]];
if (isFlush) return [RANKS.FLUSH, values];
if (isStraight) return [RANKS.STRAIGHT, values];
if (sortedCounts[0][1] === 3) return [RANKS.THREE_OF_A_KIND, [Number(sortedCounts[0][0]), ...sortedCounts.slice(1).map(x => Number(x[0]))]];
if (sortedCounts[0][1] === 2 && sortedCounts[1][1] === 2) return [RANKS.TWO_PAIR, [Number(sortedCounts[0][0]), Number(sortedCounts[1][0]), Number(sortedCounts[2][0])]];
if (sortedCounts[0][1] === 2) return [RANKS.ONE_PAIR, [Number(sortedCounts[0][0]), ...sortedCounts.slice(1).map(x => Number(x[0]))]];
return [RANKS.HIGH_CARD, values];
}
function compareScores(s1, s2) {
if (s1[0] !== s2[0]) return s1[0] - s2[0];
for (let i = 0; i < s1[1].length; i++) {
if (s1[1][i] !== s2[1][i]) return s1[1][i] - s2[1][i];
}
return 0;
}