dramaling-vocab-learning/複習算法簡化說明.md

8.4 KiB
Raw Blame History

複習算法簡化說明

🎯 核心問題

當前的 下次複習時間 = 2^成功複習次數 增長太快只需9次就達到365天。

📐 新算法設計(簡化版)

基本公式

新間隔 = 舊間隔 × 增長係數 × 表現係數

1. 增長係數表

根據當前間隔決定增長速度:

當前間隔範圍 增長係數 說明
1-7天 1.8 初期較快增長
8-30天 1.4 中期穩定增長
31-90天 1.2 後期緩慢增長
91天以上 1.1 維持長期記憶

2. 表現係數表

翻卡題(用戶自評)

用戶選擇 係數 說明
完全不記得 0.5 大幅縮短間隔
有印象但不確定 0.7 稍微縮短
記得但需思考 1.0 維持原間隔
清楚記得 1.2 稍微延長
非常熟悉 1.4 明顯延長

客觀題(對錯判斷)

結果 反應時間 係數 說明
答對 < 3秒 1.2 很熟悉
答對 3-8秒 1.1 正常
答對 > 8秒 1.0 緩慢
答錯 任何 0.6 需練習

🆕 初始間隔設計

新增詞卡的預設值

當用戶新增詞卡時,系統自動設定:

  • IntervalDays: 1天資料庫預設值
  • NextReviewDate: 今天(立即可復習)
  • Repetitions: 0尚未復習

第一次復習的間隔計算

當用戶第一次復習新詞卡時,使用相同的公式:

表現 計算過程 結果
答對 1天 × 1.8 × 1.1 = 1.98天 2天後復習
答錯 1天 × 1.8 × 0.6 = 1.08天 1天後復習

為什麼初始間隔是1天

  1. 符合直覺: 新學的詞彙需要快速復習
  2. 避免遺忘: 短間隔確保新記憶得到鞏固
  3. 資料庫一致: 與現有的 IntervalDays = 1 預設值保持一致

🔢 實際計算範例

範例:詞彙 "sophisticated" 的完整學習歷程

階段 當前間隔 表現 增長係數 表現係數 計算過程 新間隔 說明
新增 - - - - - 1天 系統預設初始間隔
第1次 1天 答對(正常) 1.8 1.1 1×1.8×1.1 2天 第一次復習成功
第2次 2天 答對(快速) 1.8 1.2 2×1.8×1.2 4天 反應快速,獎勵
第3次 4天 答錯 1.8 0.6 4×1.8×0.6 4天 答錯,間隔未增加
第4次 4天 答對(正常) 1.8 1.1 4×1.8×1.1 8天 重新開始增長
第5次 8天 答對(正常) 1.4 1.1 8×1.4×1.1 12天 進入中期階段
第6次 12天 答對(快速) 1.4 1.2 12×1.4×1.2 20天 反應快速,獎勵
第7次 20天 答對(正常) 1.4 1.1 20×1.4×1.1 31天 穩定增長
第8次 31天 答對(正常) 1.2 1.1 31×1.2×1.1 41天 進入後期階段
第9次 41天 答對(正常) 1.2 1.1 41×1.2×1.1 54天 緩慢增長
第10次 54天 答對(正常) 1.2 1.1 54×1.2×1.1 71天 長期記憶階段

📊 算法對比圖表

時間增長對比

天數
400 |
    |     ●─── 現有算法 (2^n)
300 |   
    | 
200 |
    |
100 |    ╭──●──●──●─── 新算法 (漸進式)
    |  
 50 |
    |
  0 +────────────────────→
    1  3  5  7  9  復習次數

現有算法: 1→2→4→8→16→32→64→128→256天
新算法:   1→2→4→8→12→20→31→41→54天

🎯 關鍵優勢

1. 更合理的學習曲線

  • 現有: 9次復習就達到256天
  • 新版: 10次復習才71天需要更多次數達到長間隔

2. 錯誤恢復機制

  • 現有: 錯誤後直接 ×0.6,可能重置太多進度
  • 新版: 錯誤後根據當前階段調整,避免過度懲罰

3. 階段性增長

  • 初期: 快速建立基礎記憶
  • 中期: 穩定鞏固
  • 後期: 維持長期記憶

🛠️ 實作的 C# 代碼

public class SpacedRepetitionService
{
    /// <summary>
    /// 計算下次復習間隔
    /// </summary>
    /// <param name="flashcard">詞卡實體(包含 IntervalDays 等欄位)</param>
    /// <param name="isCorrect">是否答對</param>
    /// <param name="confidenceLevel">信心程度1-5僅翻卡題使用</param>
    /// <returns>新的間隔天數</returns>
    public int CalculateNextInterval(Flashcard flashcard, bool isCorrect, double? confidenceLevel = null)
    {
        // 1. 取得當前間隔新詞卡預設為1天
        int currentInterval = flashcard.IntervalDays; // 資料庫欄位,預設值 = 1

        // 2. 決定增長係數(根據當前間隔階段)
        double growthFactor = currentInterval switch
        {
            <= 7 => 1.8,    // 初期階段(包含第一次復習)
            <= 30 => 1.4,   // 中期階段
            <= 90 => 1.2,   // 後期階段
            _ => 1.1         // 維持期
        };

        // 3. 決定表現係數
        double performanceFactor;
        if (confidenceLevel.HasValue) // 翻卡題(主觀評估)
        {
            performanceFactor = confidenceLevel.Value switch
            {
                1 => 0.5,  // 完全不記得
                2 => 0.7,  // 有印象但不確定
                3 => 1.0,  // 記得但需思考
                4 => 1.2,  // 清楚記得
                5 => 1.4,  // 非常熟悉
                _ => 1.0
            };
        }
        else // 客觀題(對錯判斷)
        {
            performanceFactor = isCorrect ? 1.1 : 0.6;
        }

        // 4. 計算新間隔
        double newInterval = currentInterval * growthFactor * performanceFactor;

        // 5. 限制範圍並四捨五入
        int result = Math.Max(1, Math.Min(365, (int)Math.Round(newInterval)));

        return result;
    }

    /// <summary>
    /// 更新詞卡的復習資訊
    /// </summary>
    public void UpdateFlashcardAfterReview(Flashcard flashcard, int newInterval, bool isCorrect)
    {
        // 更新間隔天數
        flashcard.IntervalDays = newInterval;

        // 更新下次復習日期
        flashcard.NextReviewDate = DateTime.Today.AddDays(newInterval);

        // 更新統計資料
        flashcard.TimesReviewed++;
        if (isCorrect)
        {
            flashcard.TimesCorrect++;
        }

        // 更新熟悉程度(簡化版)
        flashcard.MasteryLevel = Math.Min(100,
            (flashcard.TimesCorrect * 10) + (newInterval * 365 / 100));
    }
}

與現有資料庫的整合

// 在 FlashcardsController 中的使用範例
[HttpPost("{id}/review")]
public async Task<IActionResult> ReviewFlashcard(Guid id, ReviewRequest request)
{
    var flashcard = await _context.Flashcards.FindAsync(id);
    if (flashcard == null) return NotFound();

    // 使用新算法計算間隔
    var spacedRepetition = new SpacedRepetitionService();
    int newInterval = spacedRepetition.CalculateNextInterval(
        flashcard,
        request.IsCorrect,
        request.ConfidenceLevel
    );

    // 更新詞卡資訊
    spacedRepetition.UpdateFlashcardAfterReview(flashcard, newInterval, request.IsCorrect);

    await _context.SaveChangesAsync();

    return Ok(new {
        newInterval,
        nextReviewDate = flashcard.NextReviewDate,
        masteryLevel = flashcard.MasteryLevel
    });
}

🤔 為什麼這樣設計?

階段性增長的科學依據

  1. 初期 (1.8倍): 新記憶需要頻繁鞏固
  2. 中期 (1.4倍): 記憶開始穩定,可適度延長
  3. 後期 (1.2倍): 長期記憶,緩慢增長避免遺忘
  4. 維持期 (1.1倍): 微調保持長期記憶

表現係數的心理學依據

  • 主觀評估: 反映學習者真實感受5個等級提供細緻調整
  • 客觀測試: 簡單的對錯判斷,避免過度複雜化
  • 快速獎勵: 快速正確答題獲得額外係數獎勵

這個算法的核心思想:根據當前學習階段和表現,智能調整復習頻率,既避免遺忘,也不浪費時間。