import type { StudyProgress, DifficultyRating } from '../types/vocabulary'; interface SRSConfig { initialEase: number; minEase: number; maxInterval: number; learningStepInterval: number; } const DEFAULT_CONFIG: SRSConfig = { initialEase: 2.5, minEase: 1.3, maxInterval: 365, // 最大间隔 365 天 learningStepInterval: 10, // 学习步骤间隔(分钟) }; /** * 改进的 SM-2 算法实现 * 基于 Anki 和 SuperMemo 的研究 */ export function calculateNextReview( progress: StudyProgress, rating: DifficultyRating, config: SRSConfig = DEFAULT_CONFIG ): StudyProgress { const newProgress = { ...progress }; const { minEase, maxInterval } = config; // 如果是新单词(repetitions === 0),使用学习步骤 if (progress.repetitions === 0 && rating === 'again') { // 标记为"再次",保持在第一步 newProgress.interval = 0; newProgress.easeFactor = Math.max(minEase, progress.easeFactor - 0.2); newProgress.nextReviewDate = new Date(Date.now() + DEFAULT_CONFIG.learningStepInterval * 60 * 1000); newProgress.lastStudiedDate = new Date(); return newProgress; } switch (rating) { case 'again': // 完全重置,但保留一些学习历史 newProgress.interval = 1; newProgress.repetitions = 0; newProgress.easeFactor = Math.max(minEase, progress.easeFactor - 0.2); break; case 'hard': // 困难:间隔增长较慢 newProgress.interval = Math.max(1, Math.round(progress.interval * 1.2)); newProgress.repetitions += 1; newProgress.easeFactor = Math.max(minEase, progress.easeFactor - 0.15); break; case 'good': // 良好:标准 SM-2 算法 if (progress.repetitions === 0) { newProgress.interval = 1; } else if (progress.repetitions === 1) { newProgress.interval = 6; } else { newProgress.interval = Math.round(progress.interval * progress.easeFactor); } newProgress.repetitions += 1; break; case 'easy': // 简单:间隔增长更快 if (progress.repetitions === 0) { newProgress.interval = 4; } else { newProgress.interval = Math.round(progress.interval * progress.easeFactor * 1.3); } newProgress.repetitions += 1; newProgress.easeFactor += 0.15; break; } // 限制最大间隔 newProgress.interval = Math.min(newProgress.interval, maxInterval); // 确保 easeFactor 在合理范围内 newProgress.easeFactor = Math.max(minEase, Math.min(newProgress.easeFactor, 3.0)); // 计算下次复习日期 const now = new Date(); newProgress.nextReviewDate = new Date(now.getTime() + newProgress.interval * 24 * 60 * 60 * 1000); newProgress.lastStudiedDate = now; return newProgress; } /** * 计算单词的掌握程度 (0-100%) */ export function calculateMastery(progress: StudyProgress): number { if (progress.repetitions === 0) return 0; const baseScore = Math.min(progress.repetitions * 20, 80); const intervalBonus = Math.min(progress.interval / 30 * 20, 20); return Math.min(100, Math.round(baseScore + intervalBonus)); } /** * 获取复习优先级分数(越高越优先) */ export function getReviewPriority(progress: StudyProgress): number { const now = new Date(); const nextReview = new Date(progress.nextReviewDate); const overdue = now.getTime() - nextReview.getTime(); // 逾期的单词优先级更高 if (overdue > 0) { return 1000 + Math.min(overdue / (1000 * 60 * 60), 1000); // 每小时增加 1 点优先级 } // 即将到期的单词 const timeUntilDue = nextReview.getTime() - now.getTime(); const hoursUntilDue = timeUntilDue / (1000 * 60 * 60); if (hoursUntilDue < 24) { return 500 + (24 - hoursUntilDue) * 20; } return hoursUntilDue; }