Files

120 lines
2.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package engine
import (
"math"
"time"
)
// 记忆引擎 - 基于艾宾浩斯遗忘曲线
type MemoryEngine struct {
// 基础间隔(小时)
baseInterval float64
// 最大间隔(天)
maxInterval float64
}
// 记忆级别
const (
Level0 = iota // 完全忘记
Level1
Level2
Level3
Level4
Level5 // 永久记住
)
func NewMemoryEngine() *MemoryEngine {
return &MemoryEngine{
baseInterval: 1, // 1小时
maxInterval: 30 * 24, // 30天
}
}
// CalculateNextReview 计算下次复习时间
// correct: 回答是否正确
// currentLevel: 当前掌握程度 0-5
func (e *MemoryEngine) CalculateNextReview(correct bool, currentLevel int) time.Duration {
var interval float64
if !correct {
// 回答错误重置到Level11小时后复习
interval = e.baseInterval
} else {
// 根据当前级别计算间隔
switch currentLevel {
case 0:
interval = 1 // 1小时后
case 1:
interval = 12 // 12小时后
case 2:
interval = 24 // 1天后
case 3:
interval = 72 // 3天后
case 4:
interval = 168 // 7天后
case 5:
interval = 360 // 15天后
default:
interval = e.baseInterval
}
// 增加难度系数
interval = interval * 1.2
}
// 限制最大间隔
interval = math.Min(interval, e.maxInterval)
return time.Duration(interval) * time.Hour
}
// GetMasteryLevel 计算掌握程度
// correctCount: 正确次数
// totalCount: 总次数
func (e *MemoryEngine) GetMasteryLevel(correctCount, totalCount int) int {
if totalCount == 0 {
return 0
}
// 正确率
rate := float64(correctCount) / float64(totalCount)
// 根据正确率和次数计算级别
if totalCount < 3 {
if rate >= 0.8 {
return 1
}
return 0
}
if rate >= 0.9 {
return 5
} else if rate >= 0.8 {
return 4
} else if rate >= 0.7 {
return 3
} else if rate >= 0.5 {
return 2
} else {
return 1
}
}
// IsDueForReview 是否应该复习
func (e *MemoryEngine) IsDueForReview(lastReview *time.Time, nextReview *time.Time) bool {
now := time.Now()
// 没有复习记录,需要复习
if lastReview == nil {
return true
}
// 有计划复习时间
if nextReview != nil {
return now.After(*nextReview)
}
// 默认超过1天没复习需要复习
return now.Sub(*lastReview) > 24*time.Hour
}