diff --git a/rslib/src/scheduler/fsrs/memory_state.rs b/rslib/src/scheduler/fsrs/memory_state.rs index 4f1ea90c8..31d50b0bc 100644 --- a/rslib/src/scheduler/fsrs/memory_state.rs +++ b/rslib/src/scheduler/fsrs/memory_state.rs @@ -284,20 +284,7 @@ pub(crate) fn single_card_revlog_to_item( interval: f32, ease_factor: f32, } - let first_review = entries - .iter() - // ignore manual and rescheduled revlogs and revlogs before the cutoff - .find(|e| e.button_chosen > 0 && e.id.0 >= ignore_revlogs_before.0) - .map(|e| FirstReview { - interval: e.interval.max(1) as f32, - ease_factor: if e.ease_factor == 0 { - 2500 - } else { - e.ease_factor - } as f32 - / 1000.0, - }); - if let Some((mut items, revlogs_complete, _)) = + if let Some((mut items, revlogs_complete, _, filtered_entries)) = single_card_revlog_to_items(entries, next_day_at, false, ignore_revlogs_before) { let mut item = items.pop().unwrap(); @@ -306,7 +293,16 @@ pub(crate) fn single_card_revlog_to_item( item, starting_state: None, })) - } else if let Some(first_review) = first_review { + } else if let Some(first_non_manual_entry) = filtered_entries.first() { + let first_review = FirstReview { + interval: first_non_manual_entry.interval.max(1) as f32, + ease_factor: if first_non_manual_entry.ease_factor == 0 { + 2500 + } else { + first_non_manual_entry.ease_factor + } as f32 + / 1000.0, + }; // the revlog has been truncated, but not fully let mut starting_state = fsrs.memory_state_from_sm2( first_review.ease_factor, @@ -318,14 +314,10 @@ pub(crate) fn single_card_revlog_to_item( starting_state.difficulty = (first_review.ease_factor - 0.1) * 9.0 + 1.0; } item.reviews.remove(0); - if item.reviews.is_empty() { - Ok(None) - } else { - Ok(Some(FsrsItemWithStartingState { - item, - starting_state: Some(starting_state), - })) - } + Ok(Some(FsrsItemWithStartingState { + item, + starting_state: Some(starting_state), + })) } else { // only manual and rescheduled revlogs; treat like empty Ok(None) diff --git a/rslib/src/scheduler/fsrs/params.rs b/rslib/src/scheduler/fsrs/params.rs index 1c2bcbb7d..724bf0336 100644 --- a/rslib/src/scheduler/fsrs/params.rs +++ b/rslib/src/scheduler/fsrs/params.rs @@ -258,13 +258,17 @@ pub(crate) fn single_card_revlog_to_items( next_day_at: TimestampSecs, training: bool, ignore_revlogs_before: TimestampMillis, -) -> Option<(Vec, bool, usize)> { +) -> Option<(Vec, bool, usize, Vec)> { let mut first_of_last_learn_entries = None; + let mut first_relearn_entries = None; let mut non_manual_entries = None; let mut revlogs_complete = false; for (index, entry) in entries.iter().enumerate().rev() { if matches!(entry.button_chosen, 1..=4) { - non_manual_entries = Some(entry); + non_manual_entries = Some(index); + if entry.review_kind == RevlogReviewKind::Relearning { + first_relearn_entries = Some(index); + } } if matches!( (entry.review_kind, entry.button_chosen), @@ -295,18 +299,6 @@ pub(crate) fn single_card_revlog_to_items( } } } - if !revlogs_complete { - revlogs_complete = matches!( - entries.first(), - Some(RevlogEntry { - review_kind: RevlogReviewKind::Manual, - .. - }) | Some(RevlogEntry { - review_kind: RevlogReviewKind::Rescheduled, - .. - }) - ); - } if training { // While training ignore the entire card if the first learning step of the last // group of learning steps is before the ignore_revlogs_before date @@ -333,14 +325,7 @@ pub(crate) fn single_card_revlog_to_items( } } } - let first_relearn = entries - .iter() - .enumerate() - .find(|(_idx, e)| { - e.id.0 > ignore_revlogs_before.0 && e.review_kind == RevlogReviewKind::Relearning - }) - .map(|(idx, _)| idx); - if let Some(idx) = first_of_last_learn_entries.or(first_relearn) { + if let Some(idx) = first_of_last_learn_entries.or(first_relearn_entries) { // start from the (re)learning step if idx > 0 { entries.drain(..idx); @@ -348,6 +333,12 @@ pub(crate) fn single_card_revlog_to_items( } else if training { // when training, we ignore cards that don't have any learning steps return None; + } else if let Some(idx) = non_manual_entries { + // if there are no (re)learning entries but there are non-manual entries, + // we ignore all entries before the first non-manual entry + if idx > 0 { + entries.drain(..idx); + } } // Filter out unwanted entries @@ -393,7 +384,7 @@ pub(crate) fn single_card_revlog_to_items( if items.is_empty() { None } else { - Some((items, revlogs_complete, entries.len())) + Some((items, revlogs_complete, entries.len(), entries)) } }