Skip to main content
Glama
bsim0927
by bsim0927
parser.js4.85 kB
/** * Parse poker range strings */ export class RangeParser { /** * Parse a range string into individual hands with weights * Format: "AA:1.0,KK:0.75,QQ,AKs:0.5" where weight defaults to 1.0 * @param {string} rangeString * @returns {Array<Object>} Array of { hand, weight } */ static parseRange(rangeString) { if (!rangeString || typeof rangeString !== 'string') { throw new Error('Range must be a non-empty string'); } const hands = []; const entries = rangeString.split(','); for (const entry of entries) { const trimmed = entry.trim(); if (!trimmed) continue; const [hand, weightStr] = trimmed.split(':'); const cleanHand = hand.trim(); const weight = weightStr ? parseFloat(weightStr) : 1.0; if (!cleanHand) { throw new Error(`Invalid range entry: "${entry}"`); } if (isNaN(weight) || weight < 0 || weight > 1) { throw new Error(`Invalid weight for ${cleanHand}: ${weightStr}. Weight must be between 0 and 1`); } hands.push({ hand: cleanHand, weight }); } if (hands.length === 0) { throw new Error('Range is empty'); } return hands; } /** * Expand a range notation to individual hands * "AA-KK" becomes ["AA", "KK"] * "AKs-AJs" becomes ["AKs", "AQs", "AJs"] * @param {string} notation - e.g., "AA-KK", "AKs-AJs", "22-99" * @returns {Array<string>} */ static expandRange(notation) { // Simple expansion for basic sequences const pairs = ['AA', 'KK', 'QQ', 'JJ', 'TT', '99', '88', '77', '66', '55', '44', '33', '22']; const ranks = ['A', 'K', 'Q', 'J', 'T', '9', '8', '7', '6', '5', '4', '3', '2']; if (notation.includes('-')) { const [start, end] = notation.split('-'); const expanded = []; // Check if it's a pair range like "AA-KK" if (pairs.includes(start) && pairs.includes(end)) { const startIdx = pairs.indexOf(start); const endIdx = pairs.indexOf(end); const [minIdx, maxIdx] = startIdx < endIdx ? [startIdx, endIdx] : [endIdx, startIdx]; return pairs.slice(minIdx, maxIdx + 1); } // Otherwise return as is return [notation]; } return [notation]; } /** * Calculate total hand combinations in a range * Assumes full deck (no blockers) * @param {Array<Object>} hands - Array of { hand, weight } * @returns {number} */ static calculateCombinations(hands) { let total = 0; for (const { hand, weight } of hands) { const combos = this.getHandCombinations(hand); total += combos * weight; } return total; } /** * Get number of combinations for a hand * @param {string} hand - e.g., "AA", "AKs", "AKo", "AK" * @returns {number} */ static getHandCombinations(hand) { if (hand.length < 2) { throw new Error(`Invalid hand notation: "${hand}"`); } const rank1 = hand[0]; const rank2 = hand[1]; const suit = hand[2]; // Pair if (rank1 === rank2) { return 6; // C(4,2) = 6 combinations } // Suited if (suit === 's') { return 4; // 4 suit combinations (each suit) } // Offsuit if (suit === 'o') { return 12; // 4 * 3 = 12 combinations } // Unspecified suit (assume all combinations) return 16; // 4 + 12 for any AK } /** * Validate hand notation * @param {string} hand * @returns {boolean} */ static isValidHand(hand) { if (!hand || hand.length < 2) return false; const ranks = ['A', 'K', 'Q', 'J', 'T', '9', '8', '7', '6', '5', '4', '3', '2']; const rank1 = hand[0]; const rank2 = hand[1]; const suit = hand[2]; const validRank1 = ranks.includes(rank1); const validRank2 = ranks.includes(rank2); if (!validRank1 || !validRank2) return false; // If there's a suit specifier, it must be 's' or 'o' if (suit && !['s', 'o'].includes(suit)) return false; // Pairs must be exactly 2 characters if (rank1 === rank2 && hand.length !== 2) return false; return true; } /** * Convert range to human-readable string * @param {Array<Object>} hands * @returns {string} */ static formatRange(hands) { return hands .map(({ hand, weight }) => weight < 1 ? `${hand}:${weight.toFixed(2)}` : hand) .join(','); } /** * Parse range file content * Range files can be single-line or multi-line format * @param {string} content - File content * @returns {Array<Object>} */ static parseRangeFile(content) { if (!content) { throw new Error('Empty range file'); } // Try to parse as comma-separated on single or multiple lines const cleanContent = content.trim().replace(/\n/g, ''); return this.parseRange(cleanContent); } } export default RangeParser;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bsim0927/texas-solver-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server