Skip to content

Instantly share code, notes, and snippets.

@nathanborror
Last active February 11, 2018 00:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nathanborror/cc2bb65513624f817f8afe0ed91f020e to your computer and use it in GitHub Desktop.
Save nathanborror/cc2bb65513624f817f8afe0ed91f020e to your computer and use it in GitHub Desktop.
SM-2 Algorithm
// 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