Created
November 5, 2018 01:30
-
-
Save marcmartino/a4d2b9109f91305cf2d64241d77bac3f to your computer and use it in GitHub Desktop.
attempt at sm4, likely inconsistent but sm5 is significantly different so no dwelling
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
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") | |
} | |
]; | |
interface CardAnswer { | |
[key: string]: (boolean | number | date) | |
hesitationDetected: boolean; | |
correct: boolean; | |
timeSpent: number; | |
date: date; | |
ef?: EasinessFactor; | |
interval?: Interval; | |
oi: OptimalInterval; | |
} | |
type Quality = 0|1|2|3|4|5; | |
type EasinessFactor = number; | |
type Interval = number; | |
type OptimalInterval = number; | |
const interv = (rep: number, ef: EasinessFactor /* 1.3 <= easinessFactor <= 2.5 */): Interval => | |
rep === 1 ? 1 | |
: rep === 2 ? 6 | |
: interv(rep - 1, ef) * ef; | |
const ef = (prevEf: EasinessFactor, q: Quality): EasinessFactor => | |
Math.max(1.3, Math.min(2.5, | |
prevEf + (0.1 - (5 - q) * (0.08 + (5 - q) * 0.02)))) | |
const efFromCards = (as: CardAnswer[]): EasinessFactor => | |
as.length > 1 | |
? ef(efFromCards(as.slice(0, as.length - 1)), qual(as[as.length - 1])) | |
: 2.5; | |
const qual = (a: CardAnswer): Quality => | |
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 nextOI = (prevOI: OptimalInterval, interimOI: OptimalInterval, frac: number): OptimalInterval => | |
(1 - frac) * prevOI + frac * interimOI; | |
const primeOI = (i: interval, ef: EasinessFactor, q: Quality): OptimalInterval => | |
i * i * (1 - 1 / ef) / 2 * (0.2 * q - 1); | |
const calcOI = (as: CardAnswers[]): OptimalInterval => | |
as.length > 1 | |
? nextOI( | |
calcOI(as.slice(0, as.length - 1)), | |
primeOI(as[as.length - 1].interval, as[as.length - 1].ef, qual(as[as.length - 1])), | |
.5) | |
: 2.5; | |
console.log( | |
answers | |
.reduce((as: CardAnswer[], a: CardAnswer): CardAnswer[] => | |
[...as, {...a, ef: efFromCards([...as, a, ]) }], []) | |
.map((a: CardAnswer, x: number): CardAnswer => | |
({ ...a, interval: interv(x + 1, a.ef, qual(a))})) | |
.reduce((as: CardAnswer[], a: CardAnswer): CardAnswer => | |
[...as, {...a, oi: calcOI([...as, a, ])}], []) | |
.map(({ef, interval, oi}) => ({ ef, interval, oi,})), | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment