Last active
February 11, 2018 00:13
-
-
Save nathanborror/cc2bb65513624f817f8afe0ed91f020e to your computer and use it in GitHub Desktop.
SM-2 Algorithm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Based on the SuperMemo 2 Algorithm: | |
// https://www.supermemo.com/english/ol/sm2.htm | |
import UIKit | |
struct Item { | |
let id: UUID | |
let prompt: String | |
let explaination: String | |
var score: Score | |
init(prompt: String, explaination: String) { | |
self.id = UUID() | |
self.prompt = prompt | |
self.explaination = explaination | |
self.score = Score() | |
} | |
} | |
struct Score { | |
enum Grade: Int { | |
case i // 0 complete blackout | |
case f // 1 incorrect response; the correct one remembered | |
case d // 2 incorrect response; where the correct one seemed easy to recall | |
case c // 3 correct response recalled with serious difficulty | |
case b // 4 correct response after a hesitation | |
case a // 5 perfect response | |
static var maxRawValue = 5 | |
} | |
var easiness: Double // ≥ 1.3 as the hardest, defaults to 2.5 | |
var consecutiveCorrectAnswers: Int | |
var nextDate: Date | |
init(easiness: Double = 2.5, consecutiveCorrectAnswers: Int = 0) { | |
self.easiness = easiness | |
self.consecutiveCorrectAnswers = consecutiveCorrectAnswers | |
self.nextDate = Date() | |
} | |
mutating func calculate(grade: Grade, for date: Date) { | |
let isPassing = (grade.rawValue >= 3) | |
let quality = Double(Grade.maxRawValue - grade.rawValue) | |
// To calculate the Easiness Factor (EF), the viewer must assess the | |
// quality of their response to the question using a graded scale of 0-5, | |
// with 0 as failing: | |
// EF = EF + (0.1 - (5 - grade) * (0.08 + (5 - grade) * 0.02)) | |
self.easiness = easiness + (0.1 - quality * (0.08 + quality * 0.02)) | |
if isPassing { | |
self.consecutiveCorrectAnswers += 1 | |
let days = (6 * pow(easiness, Double(consecutiveCorrectAnswers - 1))) | |
self.nextDate = Calendar.current.date(byAdding: .day, value: Int(days), to: date)! | |
} else { | |
self.consecutiveCorrectAnswers = 0 | |
self.nextDate = Calendar.current.date(byAdding: .day, value: 1, to: date)! | |
} | |
} | |
} | |
var item = Item(prompt: "🏴", explaination: "Flag of England") | |
item.score.calculate(grade: .f, for: Date()) | |
print(item.score) | |
item.score.calculate(grade: .b, for: Date()) | |
print(item.score) | |
item.score.calculate(grade: .b, for: Date()) | |
print(item.score) | |
// Output | |
// Score(easiness: 1.7000000000000002, consecutiveCorrectAnswers: 0, nextDate: 2018-02-11 19:56:15 +0000) | |
// Score(easiness: 1.5600000000000003, consecutiveCorrectAnswers: 1, nextDate: 2018-02-16 19:56:15 +0000) | |
// Score(easiness: 1.4200000000000004, consecutiveCorrectAnswers: 2, nextDate: 2018-02-18 19:56:15 +0000) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment