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
pub mod leitner_system;
pub mod super_memory_2;

// mod free_spaced_repetition_sheduled_4 {
//     use std::collections::HashSet;
//
//     use level::Level;
//     use serde::{Deserialize, Serialize};
//
//     type Weights = [f64; 17];
//     const _DEFAULT_PARAMETRS: Weights = [
//         0.4, 0.6, 2.4, 5.8, 4.93, 0.94, 0.86, 0.01, 1.49, 0.14, 0.94, 2.18, 0.05, 0.34, 1.26, 0.29,
//         2.61,
//     ];
//
//     mod level {
//         use serde::{Deserialize, Serialize};
//         use ssr_core::task::level::TaskLevel;
//         use std::time::{Duration, SystemTime};
//
//         use super::Weights;
//
//         const _DECAY: f64 = -0.5;
//         const _FACTOR: f64 = 19. / 81.;
//
//         #[derive(Default, Serialize, Deserialize)]
//         pub struct Level {
//             last_repetition: Option<SystemTime>,
//             stability: f64,
//             difficulty: f64,
//         }
//
//         #[derive(Clone, Copy)]
//         #[repr(u8)]
//         pub enum Grade {
//             Again = 1,
//             Hard = 2,
//             Good = 3,
//             Easy = 4,
//         }
//         impl TaskLevel for Level {
//             type Context = (Weights, SystemTime, Grade);
//
//             fn update(&mut self, (weights, now, grade): Self::Context) {
//                 const _DAY: Duration = Duration::new(60 * 60 * 24, 0);
//                 if self.last_repetition.is_none() {
//                     self.stability = weights[grade as usize - 1];
//                     self.difficulty = weights[4] - (grade as i64 - 3) as f64 * weights[5];
//                 } else {
//                     self.difficulty = weights[7] * weights[4]
//                         + (1. - weights[7])
//                             * (self.difficulty - weights[6] * (grade as i64 - 3) as f64);
//                     self.stability = match grade {
//                         Grade::Again => {
//                             weights[11]
//                                 * self.difficulty.powf(-weights[12])
//                                 * ((self.stability + 1.).powf(weights[13]))
//                                 * f64::exp(weights[14] * (1 - todo!()))
//                         }
//                         Grade::Hard => todo!(),
//                         Grade::Good => todo!(),
//                         Grade::Easy => todo!(),
//                     }
//                 }
//                 self.last_repetition = Some(now);
//             }
//
//             fn next_repetition(&self, retrievability_goal: f64) -> SystemTime {
//                 if let Some(last_repetition) = self.last_repetition {
//                     const DAY: Duration = Duration::new(60 * 60 * 24, 0);
//                     last_repetition
//                         + DAY.mul_f64(9. * self.stability * (1. / retrievability_goal - 1.))
//                 } else {
//                     SystemTime::now()
//                 }
//             }
//         }
//         impl Level {
//             pub fn retrievability(&self, duration: Duration) -> f64 {
//                 assert!(self.last_repetition.is_some());
//                 const DAY: Duration = Duration::new(60 * 60 * 24, 0);
//                 let t = duration.as_secs_f64() / DAY.as_secs_f64();
//                 (1. - t / (9. * self.stability)).powi(-1)
//             }
//         }
//     }
//
//     #[derive(Serialize, Deserialize)]
//     pub struct WriteAnswer {
//         level: Level,
//         description: String,
//         correct_answers: HashSet<String>,
//         explanation: Option<String>,
//     }
//
//     impl WriteAnswer {
//         pub fn new(
//             description: String,
//             correct_answers: impl IntoIterator<Item = String>,
//             explanation: Option<String>,
//         ) -> Self {
//             Self {
//                 level: Default::default(),
//                 description,
//                 correct_answers: correct_answers.into_iter().collect(),
//                 explanation,
//             }
//         }
//     }
// }