Livre US-FLASHCARDS avec decks, session de révision, stats et migration Prisma. Finalise le Web Clipper (i18n 15 langues) et corrige les erreurs ESLint bloquant la CI. Co-authored-by: Cursor <cursoragent@cursor.com>
40 lines
902 B
TypeScript
40 lines
902 B
TypeScript
export type Sm2Grade = 1 | 2 | 3 | 4
|
||
|
||
export interface Sm2State {
|
||
easinessFactor: number
|
||
interval: number
|
||
}
|
||
|
||
export interface Sm2UpdateResult extends Sm2State {
|
||
nextReviewAt: Date
|
||
}
|
||
|
||
/** SM-2 update per US-FLASHCARDS spec (grades 1–4). */
|
||
export function computeSm2Update(
|
||
grade: number,
|
||
previous: Sm2State,
|
||
): Sm2UpdateResult {
|
||
const g = Math.min(4, Math.max(1, Math.round(grade))) as Sm2Grade
|
||
const ef = previous.easinessFactor
|
||
const newEF = Math.max(
|
||
1.3,
|
||
ef + 0.1 - (5 - g) * (0.08 + (5 - g) * 0.02),
|
||
)
|
||
|
||
const nextInterval =
|
||
g <= 2 ? 1 : Math.max(1, Math.round(previous.interval * newEF))
|
||
|
||
const nextReviewAt = new Date()
|
||
nextReviewAt.setDate(nextReviewAt.getDate() + nextInterval)
|
||
|
||
return {
|
||
easinessFactor: newEF,
|
||
interval: nextInterval,
|
||
nextReviewAt,
|
||
}
|
||
}
|
||
|
||
export function isCardMastered(interval: number): boolean {
|
||
return interval >= 21
|
||
}
|