kaboot/constants.ts

115 lines
3.3 KiB
TypeScript

import { Triangle, Diamond, Circle, Square } from 'lucide-react';
import type { GameConfig, Player, PointsBreakdown } from './types';
export const COLORS = {
red: 'bg-red-600',
blue: 'bg-blue-600',
yellow: 'bg-yellow-600',
green: 'bg-green-600',
purple: 'bg-theme-primary',
purpleLight: 'bg-theme-primary/70',
};
export const SHAPES = {
triangle: Triangle,
diamond: Diamond,
circle: Circle,
square: Square,
};
export const BOT_NAMES = [
"QuizWiz", "FastFinger", "Brainiac", "KnowItAll", "Guesser",
"LuckyStrike", "OwlFan", "Kahootie", "ZigZag", "Pixel"
];
export const QUESTION_TIME = 20; // seconds
export const QUESTION_TIME_MS = 20000; // milliseconds
export const POINTS_PER_QUESTION = 1000;
export const calculateBasePoints = (timeLeftMs: number, questionTimeMs: number, maxPoints: number = POINTS_PER_QUESTION): number => {
const responseTimeMs = questionTimeMs - timeLeftMs;
const responseTimeSec = responseTimeMs / 1000;
const questionTimeSec = questionTimeMs / 1000;
if (responseTimeSec < 0.5) {
return maxPoints;
}
return Math.round((1 - (responseTimeSec / questionTimeSec) / 2) * maxPoints);
};
interface PointsCalculationParams {
isCorrect: boolean;
timeLeftMs: number;
questionTimeMs: number;
streak: number;
playerRank: number;
isFirstCorrect: boolean;
config: GameConfig;
}
export const calculatePointsWithBreakdown = (params: PointsCalculationParams): PointsBreakdown => {
const { isCorrect, timeLeftMs, questionTimeMs, streak, playerRank, isFirstCorrect, config } = params;
const breakdown: PointsBreakdown = {
basePoints: 0,
streakBonus: 0,
comebackBonus: 0,
firstCorrectBonus: 0,
penalty: 0,
total: 0,
};
if (!isCorrect) {
if (config.penaltyForWrongAnswer) {
breakdown.penalty = Math.round(POINTS_PER_QUESTION * (config.penaltyPercent / 100));
breakdown.total = -breakdown.penalty;
}
return breakdown;
}
breakdown.basePoints = calculateBasePoints(timeLeftMs, questionTimeMs);
let pointsAfterStreak = breakdown.basePoints;
if (config.streakBonusEnabled && streak >= config.streakThreshold) {
const streakCount = streak - config.streakThreshold;
const multiplier = config.streakMultiplier + (streakCount * (config.streakMultiplier - 1));
pointsAfterStreak = Math.round(breakdown.basePoints * multiplier);
breakdown.streakBonus = pointsAfterStreak - breakdown.basePoints;
}
if (config.comebackBonusEnabled && playerRank > 3) {
breakdown.comebackBonus = config.comebackBonusPoints;
}
if (config.firstCorrectBonusEnabled && isFirstCorrect) {
breakdown.firstCorrectBonus = config.firstCorrectBonusPoints;
}
breakdown.total = pointsAfterStreak + breakdown.comebackBonus + breakdown.firstCorrectBonus;
return breakdown;
};
export const calculatePoints = (params: PointsCalculationParams): number => {
return calculatePointsWithBreakdown(params).total;
};
export const getPlayerRank = (playerId: string, players: Player[]): number => {
const sorted = [...players].sort((a, b) => b.score - a.score);
return sorted.findIndex(p => p.id === playerId) + 1;
};
export const PLAYER_COLORS = [
'#2563eb',
'#e21b3c',
'#26890c',
'#ffa602',
'#d89e00',
'#0aa3a3',
'#b8008a',
'#6a4c93',
'#ff6b6b',
'#4ecdc4',
'#45b7d1',
'#8b5cf6',
];