export const SCORE_CATEGORIES = { upper: [ { id: 'ones', name: 'Ettor', maxCount: 5, multiple: 1, inputType: 'count' }, { id: 'twos', name: 'Tvåor', maxCount: 5, multiple: 2, inputType: 'count' }, { id: 'threes', name: 'Treor', maxCount: 5, multiple: 3, inputType: 'count' }, { id: 'fours', name: 'Fyror', maxCount: 5, multiple: 4, inputType: 'count' }, { id: 'fives', name: 'Femmor', maxCount: 5, multiple: 5, inputType: 'count' }, { id: 'sixes', name: 'Sexor', maxCount: 5, multiple: 6, inputType: 'count' } ], lower: [ { id: 'pair', name: 'Ett par', inputType: 'options', options: [2, 4, 6, 8, 10, 12] }, { id: 'twoPair', name: 'Två par', min: 6, max: 22, inputType: 'score' }, { id: 'threeOfAKind', name: 'Tretal', inputType: 'options', options: [3, 6, 9, 12, 15, 18] }, { id: 'fourOfAKind', name: 'Fyrtal', inputType: 'options', options: [4, 8, 12, 16, 20, 24] }, { id: 'smallStraight', name: 'Liten stege', fixed: 15, inputType: 'score' }, { id: 'largeStraight', name: 'Stor stege', fixed: 20, inputType: 'score' }, { id: 'fullHouse', name: 'Kåk', min: 7, max: 28, inputType: 'score' }, { id: 'chance', name: 'Chans', min: 5, max: 30, inputType: 'score' }, { id: 'yatzee', name: 'Yatzy', fixed: 50, inputType: 'score' } ] }; export const ALL_CATEGORIES = [...SCORE_CATEGORIES.upper, ...SCORE_CATEGORIES.lower]; // Hjälpfunktion för att räkna förekomsten av varje tärningsvärde function countDice(dice) { const counts = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0 }; dice.forEach(die => { counts[die]++; }); return counts; } // Hjälpfunktion för att beräkna poäng för en specifik kategori function calculateCategoryScore(dice, categoryId) { const counts = countDice(dice); switch (categoryId) { case 'ones': return counts[1] * 1; case 'twos': return counts[2] * 2; case 'threes': return counts[3] * 3; case 'fours': return counts[4] * 4; case 'fives': return counts[5] * 5; case 'sixes': return counts[6] * 6; case 'pair': for (let i = 6; i >= 1; i--) { if (counts[i] >= 2) return i * 2; } return 0; case 'twoPair': const pairs = []; for (let i = 6; i >= 1; i--) { if (counts[i] >= 2) pairs.push(i * 2); } if (pairs.length >= 2) { return pairs[0] + pairs[1]; } else if (pairs.length === 1) { // Om det bara finns ett par, ta det högsta möjliga paret och lägg till högsta enkeltärning const highestSingle = Math.max(...dice.filter(die => counts[die] === 1)); return pairs[0] + (highestSingle || 0); } return 0; case 'threeOfAKind': for (let i = 6; i >= 1; i--) { if (counts[i] >= 3) return i * 3; } return 0; case 'fourOfAKind': for (let i = 6; i >= 1; i--) { if (counts[i] >= 4) return i * 4; } return 0; case 'smallStraight': const hasSmallStraight = dice.some(die => { const has1234 = dice.includes(1) && dice.includes(2) && dice.includes(3) && dice.includes(4); const has2345 = dice.includes(2) && dice.includes(3) && dice.includes(4) && dice.includes(5); const has3456 = dice.includes(3) && dice.includes(4) && dice.includes(5) && dice.includes(6); return has1234 || has2345 || has3456; }); return hasSmallStraight ? 15 : 0; case 'largeStraight': const has12345 = dice.includes(1) && dice.includes(2) && dice.includes(3) && dice.includes(4) && dice.includes(5); const has23456 = dice.includes(2) && dice.includes(3) && dice.includes(4) && dice.includes(5) && dice.includes(6); return (has12345 || has23456) ? 20 : 0; case 'fullHouse': const hasThreeOfAKind = Object.values(counts).some(count => count >= 3); const hasPair = Object.values(counts).some(count => count >= 2); return (hasThreeOfAKind && hasPair) ? dice.reduce((sum, die) => sum + die, 0) : 0; case 'chance': return dice.reduce((sum, die) => sum + die, 0); case 'yatzee': return Object.values(counts).some(count => count === 5) ? 50 : 0; default: return 0; } } // Funktion för att beräkna möjliga poäng för en kategori export function calculatePossibleScores(gameData, playerId, categoryId) { // Hämta de senast kastade tärningarna för spelaren (detta måste implementeras i main.js) const currentDice = gameData.currentDice || [1, 1, 1, 1, 1]; // Exempelvärden, ersätt med riktiga tärningar const category = ALL_CATEGORIES.find(cat => cat.id === categoryId); if (!category) return []; const score = calculateCategoryScore(currentDice, categoryId); if (category.inputType === 'count') { return [score]; } else if (category.inputType === 'options') { return category.options.includes(score) ? [score] : [0]; } else if (category.inputType === 'score') { if (category.fixed) { return [category.fixed]; } else if (category.min !== undefined && category.max !== undefined) { return score >= category.min && score <= category.max ? [score] : [0]; } else { return [score]; } } return [score]; } export function calculateTotals(gameData) { const playerTotals = {}; gameData.players.forEach(p => { const pScores = gameData.scores[p.id] || {}; const upperSum = SCORE_CATEGORIES.upper.reduce((sum, cat) => sum + (pScores[cat.id] || 0), 0); const upperBonus = upperSum >= 63 ? 50 : 0; const upperTotal = upperSum + upperBonus; const lowerTotal = SCORE_CATEGORIES.lower.reduce((sum, cat) => sum + (pScores[cat.id] || 0), 0); const grandTotal = upperTotal + lowerTotal; playerTotals[p.id] = { upperSum, upperBonus, upperTotal, lowerTotal, grandTotal }; }); return playerTotals; } export function isGameComplete(gameData) { if (!gameData || !gameData.players || !gameData.scores) return false; return gameData.players.every(p => { return ALL_CATEGORIES.every(cat => { return gameData.scores[p.id]?.[cat.id] !== null && gameData.scores[p.id]?.[cat.id] !== undefined; }); }); }