forked from admin/french-vocab
47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
|
|
import type { StudyProgress, DifficultyRating } from '../types/vocabulary';
|
||
|
|
|
||
|
|
export function calculateNextReview(
|
||
|
|
progress: StudyProgress,
|
||
|
|
rating: DifficultyRating
|
||
|
|
): StudyProgress {
|
||
|
|
const newProgress = { ...progress };
|
||
|
|
|
||
|
|
switch (rating) {
|
||
|
|
case 'again':
|
||
|
|
newProgress.interval = 1;
|
||
|
|
newProgress.repetitions = 0;
|
||
|
|
newProgress.easeFactor = Math.max(1.3, progress.easeFactor - 0.2);
|
||
|
|
break;
|
||
|
|
case 'hard':
|
||
|
|
newProgress.interval = Math.round(progress.interval * 1.2);
|
||
|
|
newProgress.repetitions += 1;
|
||
|
|
newProgress.easeFactor = Math.max(1.3, progress.easeFactor - 0.15);
|
||
|
|
break;
|
||
|
|
case 'good':
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
|
||
|
|
const now = new Date();
|
||
|
|
newProgress.nextReviewDate = new Date(now.getTime() + newProgress.interval * 24 * 60 * 60 * 1000);
|
||
|
|
newProgress.lastStudiedDate = now;
|
||
|
|
|
||
|
|
return newProgress;
|
||
|
|
}
|