Fsrs #12
No files matched your search
+9
-13
@@ -1,5 +1,5 @@
|
||||
use crate::app::AppState;
|
||||
use crate::core::srs::OrderModule::{WorstWordsSRS, FSRS, RandomSRS, SemiRandomSRS};
|
||||
use crate::core::srs::OrderModule::{Fsrs, RandomSRS, SemiRandomSRS, WorstWordsSRS};
|
||||
use crate::core::srs::{
|
||||
FsrsModule, OrderMode, OrderModule, RandomSRSModule, SRSModule, SemiRandomSRSModule,
|
||||
WordOpenMode, WorstWordsSRSModule,
|
||||
@@ -48,7 +48,7 @@ impl DeckData {
|
||||
words,
|
||||
current_word_index: None,
|
||||
state: state_for,
|
||||
order_module: FSRS(FsrsModule::new()),
|
||||
order_module: Fsrs(FsrsModule::new()),
|
||||
open_mode: settings.open_mode,
|
||||
settings: settings.clone(),
|
||||
})
|
||||
@@ -75,7 +75,7 @@ impl DeckData {
|
||||
}
|
||||
module.next(self.set.as_slice())
|
||||
}
|
||||
FSRS(ref mut module) => {
|
||||
Fsrs(ref mut module) => {
|
||||
if !module.initialized {
|
||||
module.init(self.set.as_slice())
|
||||
}
|
||||
@@ -103,24 +103,20 @@ impl DeckData {
|
||||
WorstWordsSRS(ref mut module) => {
|
||||
module.open(status, index, word);
|
||||
}
|
||||
FSRS(ref mut module) => {
|
||||
Fsrs(ref mut module) => {
|
||||
module.open(status, index, word);
|
||||
}
|
||||
}
|
||||
|
||||
if let FSRS(ref fsrs) = self.order_module {
|
||||
if fsrs.finished() {
|
||||
if let Fsrs(ref fsrs) = self.order_module
|
||||
&& fsrs.finished()
|
||||
{
|
||||
self.order_module = match self.open_mode {
|
||||
OrderMode::Default => {
|
||||
SemiRandomSRS(SemiRandomSRSModule::new())
|
||||
}
|
||||
OrderMode::TrainWorstFirst => {
|
||||
WorstWordsSRS(WorstWordsSRSModule::new())
|
||||
}
|
||||
OrderMode::Default => SemiRandomSRS(SemiRandomSRSModule::new()),
|
||||
OrderMode::TrainWorstFirst => WorstWordsSRS(WorstWordsSRSModule::new()),
|
||||
OrderMode::FullRandom => RandomSRS(RandomSRSModule::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
update_stat_score(word, &self.state.lock().connection)?;
|
||||
let _ = push_note(
|
||||
self.settings.id,
|
||||
|
||||
+39
-18
@@ -1,10 +1,10 @@
|
||||
use crate::data::entities::CardStatistics;
|
||||
use chrono::Local;
|
||||
use chrono::{Local, TimeDelta};
|
||||
use fsrs::FSRS;
|
||||
use rand::distr::weighted::WeightedIndex;
|
||||
use rand::prelude::ThreadRng;
|
||||
use rand::prelude::{Distribution, SliceRandom};
|
||||
use rand::rng;
|
||||
use rand::{RngExt, rng};
|
||||
|
||||
const MAX_HISTORY_LEN: usize = 20;
|
||||
const MAX_HISTORY_LEN_PART: f32 = 0.33;
|
||||
@@ -28,7 +28,7 @@ pub enum OrderModule {
|
||||
SemiRandomSRS(SemiRandomSRSModule),
|
||||
RandomSRS(RandomSRSModule),
|
||||
WorstWordsSRS(WorstWordsSRSModule),
|
||||
FSRS(FsrsModule),
|
||||
Fsrs(FsrsModule),
|
||||
}
|
||||
pub trait SRSModule {
|
||||
fn next(&mut self, set: &[CardStatistics]) -> usize;
|
||||
@@ -183,12 +183,12 @@ pub struct FsrsModule {
|
||||
queue: Vec<usize>,
|
||||
rng: ThreadRng,
|
||||
fsrs: FSRS,
|
||||
pub(crate) initialized: bool
|
||||
pub(crate) initialized: bool,
|
||||
}
|
||||
|
||||
impl SRSModule for FsrsModule {
|
||||
fn next(&mut self, set: &[CardStatistics]) -> usize {
|
||||
if self.solved.len() == self.current_group.len() {
|
||||
fn next(&mut self, _: &[CardStatistics]) -> usize {
|
||||
if self.current_group.is_empty() {
|
||||
self.fill_partial_pool();
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ impl SRSModule for FsrsModule {
|
||||
self.queue.shuffle(&mut self.rng);
|
||||
}
|
||||
|
||||
self.queue.pop().expect("empty queue")
|
||||
self.queue.pop().unwrap_or(0)
|
||||
}
|
||||
|
||||
fn open(&mut self, status: WordOpenMode, index: usize, updated_word: &mut CardStatistics) {
|
||||
@@ -205,8 +205,31 @@ impl SRSModule for FsrsModule {
|
||||
let delta = today - updated_word.fsrs_opened;
|
||||
let delta_days = delta.num_days();
|
||||
|
||||
let memory = self
|
||||
.fsrs
|
||||
.next_states(updated_word.fsrs_memory, 0.9, delta_days as u32)
|
||||
.expect("Wrong next stage calculation");
|
||||
|
||||
let next = match status {
|
||||
WordOpenMode::Easy => memory.easy,
|
||||
WordOpenMode::Ok => memory.good,
|
||||
WordOpenMode::Hard => memory.hard,
|
||||
WordOpenMode::None => memory.again,
|
||||
};
|
||||
|
||||
let mut next_day = today + TimeDelta::days(next.interval.round() as i64);
|
||||
if (next_day - today).num_days() >= 5 {
|
||||
let offset = ((rng().random::<f32>() - 0.5) * 3.0).round() as i32;
|
||||
next_day += TimeDelta::days(offset as i64);
|
||||
}
|
||||
updated_word.fsrs_memory = Some(next.memory);
|
||||
updated_word.fsrs_open_day = next_day;
|
||||
updated_word.fsrs_opened = updated_word.last_open.date_naive();
|
||||
|
||||
if updated_word.fsrs_open_day != today {
|
||||
self.solved.push(index);
|
||||
let index = self.current_group.iter().position(|x| *x == index).unwrap();
|
||||
self.current_group.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,21 +261,19 @@ impl FsrsModule {
|
||||
}
|
||||
}
|
||||
fn fill_partial_pool(&mut self) {
|
||||
self.current_group.clear();
|
||||
self.current_group
|
||||
.extend(self.today_set.iter().take(PARTIAL_POOL_SIZE));
|
||||
self.current_group.iter().for_each(|_| {
|
||||
self.today_set.remove(0);
|
||||
});
|
||||
self.current_group.extend(
|
||||
self.today_set
|
||||
.iter()
|
||||
.filter(|x| !self.solved.contains(*x))
|
||||
.take(PARTIAL_POOL_SIZE),
|
||||
);
|
||||
|
||||
self.queue.clear();
|
||||
self.queue
|
||||
.extend(self.current_group.clone());
|
||||
self.solved.clear();
|
||||
self.queue.extend(self.current_group.clone());
|
||||
}
|
||||
|
||||
fn fill_queue(&mut self) {
|
||||
self.queue.clear();
|
||||
self.queue.extend(self.current_group.iter().filter(|c| !self.today_set.contains(*c)));
|
||||
self.queue.extend(self.current_group.clone());
|
||||
}
|
||||
|
||||
pub fn finished(&self) -> bool {
|
||||
|
||||
+2
-26
@@ -1,10 +1,9 @@
|
||||
use crate::app::AppState;
|
||||
use crate::core::srs::{FADE_PER_DAY, MAX_SCORE, OrderMode, WordOpenMode};
|
||||
use crate::data::{INVALID_ID, Id};
|
||||
use chrono::{DateTime, Local, NaiveDate, Utc};
|
||||
use fsrs::{FSRS, MemoryState};
|
||||
use chrono::{DateTime, NaiveDate, Utc};
|
||||
use fsrs::MemoryState;
|
||||
use log::info;
|
||||
use rand::{RngExt, random, rng};
|
||||
use rayon::prelude::*;
|
||||
use rhai::{Engine, Scope};
|
||||
use std::collections::HashMap;
|
||||
@@ -162,29 +161,6 @@ impl CardStatistics {
|
||||
self.last_open = Utc::now();
|
||||
}
|
||||
|
||||
pub fn update_fsrs(&mut self, status: WordOpenMode, by_fsrs: bool, fsrs: FSRS)
|
||||
{
|
||||
let today = Local::now().date_naive().to_epoch_days();
|
||||
let written = self.fsrs_opened.to_epoch_days();
|
||||
let memory = fsrs
|
||||
.next_states(self.fsrs_memory, 0.9, (today - written) as u32)
|
||||
.expect("Wrong next stage calculation");
|
||||
let next = match status {
|
||||
WordOpenMode::Easy => memory.easy,
|
||||
WordOpenMode::Ok => memory.good,
|
||||
WordOpenMode::Hard => memory.hard,
|
||||
WordOpenMode::None => memory.again,
|
||||
};
|
||||
|
||||
let mut next_day = today + next.interval.round() as i32;
|
||||
if next_day - today >= 5 {
|
||||
let offset = ((rng().random::<f32>() - 0.5) * 3.0).round() as i32;
|
||||
next_day += offset;
|
||||
}
|
||||
self.fsrs_memory = Some(next.memory);
|
||||
self.fsrs_open_day = NaiveDate::from_epoch_days(next_day).unwrap();
|
||||
self.fsrs_opened = self.last_open.date_naive();
|
||||
}
|
||||
pub fn calculated_score(&self) -> f32 {
|
||||
let time = Utc::now() - self.last_open;
|
||||
let days = time.num_days();
|
||||
|
||||
@@ -4,7 +4,6 @@ use crate::notification::{MaybeError, NotificationData};
|
||||
use chrono::NaiveDate;
|
||||
use fsrs::MemoryState;
|
||||
use log::info;
|
||||
use reqwest::get;
|
||||
use rusqlite::{Connection, params};
|
||||
use std::time::Instant;
|
||||
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
use crate::core::srs::OrderMode;
|
||||
use crate::data::Id;
|
||||
use crate::data::entities::DeckSettings;
|
||||
use crate::notification::NotificationData::{DbLoadError, DbSaveError};
|
||||
use crate::notification::{MaybeError, NotificationData};
|
||||
use chrono::{Datelike, Local, NaiveDate};
|
||||
use fsrs::Card;
|
||||
use iced::futures::StreamExt;
|
||||
use rusqlite::Connection;
|
||||
|
||||
pub fn load_sets(connection: &Connection) -> Result<Vec<DeckSettings>, NotificationData> {
|
||||
|
||||
@@ -5,13 +5,16 @@ use crate::fs::*;
|
||||
use crate::notification::NotificationData::PermissionDenied;
|
||||
use crate::notification::{MaybeError, NotificationData};
|
||||
use chrono::{DateTime, NaiveDate};
|
||||
use rusqlite::Connection;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Write;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::path::PathBuf;
|
||||
use rusqlite::Connection;
|
||||
|
||||
pub fn get_open_count_of_set(id: Id, connection: &Connection) -> Result<Vec<(NaiveDate, u32)>, NotificationData>{
|
||||
pub fn get_open_count_of_set(
|
||||
id: Id,
|
||||
connection: &Connection,
|
||||
) -> Result<Vec<(NaiveDate, u32)>, NotificationData> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
pub(crate) mod decks;
|
||||
pub(crate) mod card_states;
|
||||
pub(crate) mod decks;
|
||||
pub(crate) mod history;
|
||||
pub(crate) mod import;
|
||||
pub(crate) mod settings;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::app::AppState;
|
||||
use crate::data::entities::DeckSettings;
|
||||
use crate::data_provider::decks::{delete_set, update_deck};
|
||||
use crate::data_provider::card_states::{delete_stats, load_stats_of_deck};
|
||||
use crate::data_provider::decks::{delete_set, update_deck};
|
||||
use crate::navigation::Page::PreviousPage;
|
||||
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
||||
use crate::notification::MaybeError;
|
||||
|
||||
@@ -2,8 +2,8 @@ use crate::app::AppState;
|
||||
use crate::core::srs::{AppendMode, OrderMode};
|
||||
use crate::data::Id;
|
||||
use crate::data::entities::{CardStatistics, DeckSettings};
|
||||
use crate::data_provider::decks::update_deck;
|
||||
use crate::data_provider::card_states::{add_stat_list, load_stats_of_deck};
|
||||
use crate::data_provider::decks::update_deck;
|
||||
use crate::navigation::Page::{History, PreviousPage, Repetition, RepetitionSettings};
|
||||
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
||||
use crate::notification::{MaybeError, NotificationRequest};
|
||||
|
||||
Reference in new issue
Block a user