1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
|
// Define a list of objects with "front" and "back" HTML content
const pages = [
{ front: "This is the front page!", back: "This is the back page!" },
{ front: "Another front page", back: "Another back page" }
];
// Select the first page from the list
let currentPage = pages[0];
let showFront = true;
// Replace the page with the front HTML initially
document.body.innerHTML = currentPage.front;
// Add an event listener for the spacebar press
window.addEventListener('keydown', (event) => {
if (event.code === 'Space') {
// Toggle between front and back content
if (showFront) {
document.body.innerHTML = currentPage.back;
} else {
document.body.innerHTML = currentPage.front;
}
showFront = !showFront;
}
});
// Constants: W as an array of f64 values
const W = [
0.40255, 1.18385, 3.173, 15.69105, 7.1949, 0.5345, 1.4604, 0.0046, 1.54575, 0.1192,
1.01925, 1.9395, 0.11, 0.29605, 2.2698, 0.2315, 2.9898, 0.51655, 0.6621
];
// Grade enum representation
const Grade = {
Forgot: 1.0,
Hard: 2.0,
Good: 3.0,
Easy: 4.0
};
// Helper to convert Grade to f64 (as in From<Grade> for f64)
function gradeToNumber(g) {
return Grade[g];
}
// Constants
const F = 19.0 / 81.0;
const C = -0.5;
// retrievability(t: T, s: S) -> R
function retrievability(t, s) {
return Math.pow(1.0 + F * (t / s), C);
}
// interval(r_d: R, s: S) -> T
function interval(rD, s) {
return (s / F) * (Math.pow(rD, 1.0 / C) - 1.0);
}
// s_0(g: Grade) -> S
function s0(g) {
switch (g) {
case Grade.Forgot: return W[0];
case Grade.Hard: return W[1];
case Grade.Good: return W[2];
case Grade.Easy: return W[3];
default: throw new Error("Invalid grade");
}
}
// s_success(d: D, s: S, r: R, g: Grade) -> S
function sSuccess(d, s, r, g) {
const tD = 11.0 - d;
const tS = Math.pow(s, -W[9]);
const tR = Math.exp(W[10] * (1.0 - r)) - 1.0;
const h = (g === Grade.Hard) ? W[15] : 1.0;
const b = (g === Grade.Easy) ? W[16] : 1.0;
const c = Math.exp(W[8]);
const alpha = 1.0 + tD * tS * tR * h * b * c;
return s * alpha;
}
// s_fail(d: D, s: S, r: R) => number
function sFail(d, s, r) {
return Math.exp(W[8]) - 1.0;
}
// Main function
function main() {
// All functions
}
const W = [
0.40255, 1.18385, 3.173, 15.69105, 7.1949, 0.5345, 1.4604, 0.0046, 1.54575, 0.1192, 1.01925,
1.9395, 0.11, 0.29605, 2.2698, 0.2315, 2.9898, 0.51655, 0.6621,
];
const F = 19.0 / 81.0;
const C = -0.5;
const Grade = {
Forgot: 1.0,
Hard: 2.0,
Good: 3.0,
Easy: 4.0
};
function retrievability(t, s) {
return Math.pow(1.0 + F * (t / s), C);
}
function interval(r_d, s) {
return (s / F) * (Math.pow(r_d, 1.0 / C) - 1.0);
}
function s_0(g) {
switch (g) {
case Grade.Forgot: return W[0];
case Grade.Hard: return W[1];
case Grade.Good: return W[2];
case Grade.Easy: return W[3];
}
}
function s_success(d, s, r, g) {
const t_d = 11.0 - d;
const t_s = Math.pow(s, -W[9]);
const t_r = Math.exp(W[10] * (1.0 - r)) - 1.0;
const h = g === Grade.Hard ? W[15] : 1.0;
const b = g === Grade.Easy ? W[16] : 1.0;
const c = Math.exp(W[8]);
const alpha = 1.0 + t_d * t_s * t_r * h * b * c;
return s * alpha;
}
function s_fail(d, s, r) {
const d_f = Math.pow(d, -W[12]);
const s_f = Math.pow(s + 1.0, W[13]) - 1.0;
const r_f = Math.exp(W[14] * (1.0 - r));
const c_f = W[11];
const result = d_f * s_f * r_f * c_f;
return Math.min(result, s);
}
function stability(d, s, r, g) {
return g === Grade.Forgot ? s_fail(d, s, r) : s_success(d, s, r, g);
}
function clamp_d(d) {
return Math.min(10.0, Math.max(1.0, d));
}
function d_0(g) {
const g_value = Grade[g];
return clamp_d(W[4] - Math.exp(W[5] * (g_value - 1.0)) + 1.0);
}
function difficulty(d, g) {
return clamp_d(W[7] * d_0('Easy') + (1.0 - W[7]) * dp(d, g));
}
function dp(d, g) {
return d + delta_d(g) * ((10.0 - d) / 9.0);
}
function delta_d(g) {
const g_value = Grade[g];
return -W[6] * (g_value - 3.0);
}
function sim(grades) {
let t = 0.0;
const r_d = 0.9;
const steps = [];
// Initial review
if (grades.length === 0) {
throw new Error("Grades cannot be empty");
}
let gradesCopy = [...grades];
let g = gradesCopy.shift(); // Remove the first grade
let s = s_0(g);
let d = d_0(g);
let i = Math.max(Math.round(interval(r_d, s)), 1.0);
steps.push({ t, s, d, i });
// n-th review
for (let g of gradesCopy) {
t += i;
const r = retrievability(i, s);
s = stability(d, s, r, g);
d = difficulty(d, g);
i = Math.max(Math.round(interval(r_d, s)), 1.0);
steps.push({ t, s, d, i });
}
return steps;
}
|