Skip to content

Instantly share code, notes, and snippets.

@marcmartino
Last active November 4, 2018 21:13
Show Gist options
  • Save marcmartino/f1cd567ec2e74301dc8765d72ca11c76 to your computer and use it in GitHub Desktop.
Save marcmartino/f1cd567ec2e74301dc8765d72ca11c76 to your computer and use it in GitHub Desktop.
typescript implementation of the supermemo 2 algorithm
interface CardAnswer {
[key: string]: (boolean | number | date)
hesitationDetected: boolean;
correct: boolean;
timeSpent: number;
date: date;
ef?: number;
interval?: number;
}
const calcInt = (rep: number, ef: number /* 1.3 <= easinessFactor <= 2.5 */): number =>
rep === 1 ? 1
: rep === 2 ? 6
: calcInt(rep - 1, ef) * ef;
const deriveEf = (prevEf: number, q: 0|1|2|3|4|5): number =>
Math.max(1.3, Math.min(2.5,
prevEf + (0.1 - (5 - q) * (0.08 + (5 - q) * 0.02))))
const calcEf = (as: CardAnswer[]) =>
as.length > 1
? deriveEf(calcEf(as.slice(0, as.length - 1)), calcQual(as[as.length - 1]))
: 2.5;
const calcQual = (a: CardAnswer) =>
a.correct
? (!a.hesitationDetected && a.timeSpent < 5000
? 5
: !a.hesitationDetected || a.timeSpent < 5000
? 4
: 3)
: (!a.hesitationDetected && a.timeSpent < 5000
? 2
: !a.hesitationDetected || a.timeSpent < 5000
? 1
: 0);
const answers: CardAnswer[] = [
{
"hesitationDetected": true,
"correct": true,
"timeSpent": 5000,
"date": new Date("2018-11-01T15:13:00.000Z")
},
{
"hesitationDetected": false,
"correct": false,
"timeSpent": 10000,
"date": new Date("2018-11-02T06:30:00.000Z")
},
{
"hesitationDetected": true,
"correct": true,
"timeSpent": 1000,
"date": new Date("2018-11-02T07:01:00.000Z")
}
];
console.log(
answers
.reduce((as, a, i) => [...as, {...a, ef: calcEf([...as, a]) }], [])
.map((answer: CardAnswer, i: number) => ({ ...answer, interval: calcInt(i + 1, answer.ef)}))
.map(({ef, interval}) => ({ef, interval}))
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment