mirror of
https://github.com/ankitects/anki.git
synced 2025-09-25 01:06:35 -04:00
shift learning fuzz into answering stage in test scheduler
When shown on the answer buttons, it's too distracting
This commit is contained in:
parent
958823fd6d
commit
1f16ce2096
8 changed files with 35 additions and 29 deletions
|
@ -1,6 +1,8 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
|
use rand::{prelude::*, rngs::StdRng};
|
||||||
|
|
||||||
use super::{CardStateUpdater, RevlogEntryPartial};
|
use super::{CardStateUpdater, RevlogEntryPartial};
|
||||||
use crate::{
|
use crate::{
|
||||||
card::{CardQueue, CardType},
|
card::{CardQueue, CardType},
|
||||||
|
@ -35,7 +37,7 @@ impl CardStateUpdater {
|
||||||
match interval {
|
match interval {
|
||||||
IntervalKind::InSecs(secs) => {
|
IntervalKind::InSecs(secs) => {
|
||||||
self.card.queue = CardQueue::Learn;
|
self.card.queue = CardQueue::Learn;
|
||||||
self.card.due = TimestampSecs::now().0 as i32 + secs as i32;
|
self.card.due = self.fuzzed_next_learning_timestamp(secs);
|
||||||
}
|
}
|
||||||
IntervalKind::InDays(days) => {
|
IntervalKind::InDays(days) => {
|
||||||
self.card.queue = CardQueue::DayLearn;
|
self.card.queue = CardQueue::DayLearn;
|
||||||
|
@ -45,4 +47,24 @@ impl CardStateUpdater {
|
||||||
|
|
||||||
RevlogEntryPartial::maybe_new(current, next.into(), 0.0, self.secs_until_rollover())
|
RevlogEntryPartial::maybe_new(current, next.into(), 0.0, self.secs_until_rollover())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds secs + fuzz to current time
|
||||||
|
pub(super) fn fuzzed_next_learning_timestamp(&self, secs: u32) -> i32 {
|
||||||
|
TimestampSecs::now().0 as i32 + self.with_learning_fuzz(secs) as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add up to 25% increase to seconds, but no more than 5 minutes.
|
||||||
|
fn with_learning_fuzz(&self, secs: u32) -> u32 {
|
||||||
|
if let Some(seed) = self.fuzz_seed {
|
||||||
|
let mut rng = StdRng::seed_from_u64(seed);
|
||||||
|
let upper_exclusive = secs + ((secs as f32) * 0.25).min(300.0).floor() as u32;
|
||||||
|
if secs >= upper_exclusive {
|
||||||
|
secs
|
||||||
|
} else {
|
||||||
|
rng.gen_range(secs, upper_exclusive)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
secs
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ impl CardStateUpdater {
|
||||||
let interval = next.interval_kind();
|
let interval = next.interval_kind();
|
||||||
match interval {
|
match interval {
|
||||||
IntervalKind::InSecs(secs) => {
|
IntervalKind::InSecs(secs) => {
|
||||||
self.card.due = self.now.0 as i32 + secs as i32;
|
self.card.due = self.fuzzed_next_learning_timestamp(secs);
|
||||||
}
|
}
|
||||||
IntervalKind::InDays(_days) => {
|
IntervalKind::InDays(_days) => {
|
||||||
// unsupported
|
// unsupported
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
use super::{CardStateUpdater, RevlogEntryPartial};
|
use super::{CardStateUpdater, RevlogEntryPartial};
|
||||||
use crate::{
|
use crate::{
|
||||||
card::{CardQueue, CardType},
|
card::{CardQueue, CardType},
|
||||||
prelude::*,
|
|
||||||
scheduler::states::{CardState, IntervalKind, RelearnState},
|
scheduler::states::{CardState, IntervalKind, RelearnState},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,7 +24,7 @@ impl CardStateUpdater {
|
||||||
match interval {
|
match interval {
|
||||||
IntervalKind::InSecs(secs) => {
|
IntervalKind::InSecs(secs) => {
|
||||||
self.card.queue = CardQueue::Learn;
|
self.card.queue = CardQueue::Learn;
|
||||||
self.card.due = TimestampSecs::now().0 as i32 + secs as i32;
|
self.card.due = self.fuzzed_next_learning_timestamp(secs);
|
||||||
}
|
}
|
||||||
IntervalKind::InDays(days) => {
|
IntervalKind::InDays(days) => {
|
||||||
self.card.queue = CardQueue::DayLearn;
|
self.card.queue = CardQueue::DayLearn;
|
||||||
|
|
|
@ -32,14 +32,14 @@ impl LearnState {
|
||||||
fn answer_again(self, ctx: &StateContext) -> LearnState {
|
fn answer_again(self, ctx: &StateContext) -> LearnState {
|
||||||
LearnState {
|
LearnState {
|
||||||
remaining_steps: ctx.steps.remaining_for_failed(),
|
remaining_steps: ctx.steps.remaining_for_failed(),
|
||||||
scheduled_secs: ctx.with_learning_fuzz(ctx.steps.again_delay_secs_learn()),
|
scheduled_secs: ctx.steps.again_delay_secs_learn(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn answer_hard(self, ctx: &StateContext) -> CardState {
|
fn answer_hard(self, ctx: &StateContext) -> CardState {
|
||||||
if let Some(hard_delay) = ctx.steps.hard_delay_secs(self.remaining_steps) {
|
if let Some(hard_delay) = ctx.steps.hard_delay_secs(self.remaining_steps) {
|
||||||
LearnState {
|
LearnState {
|
||||||
scheduled_secs: ctx.with_learning_fuzz(hard_delay),
|
scheduled_secs: hard_delay,
|
||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
|
@ -56,7 +56,7 @@ impl LearnState {
|
||||||
if let Some(good_delay) = ctx.steps.good_delay_secs(self.remaining_steps) {
|
if let Some(good_delay) = ctx.steps.good_delay_secs(self.remaining_steps) {
|
||||||
LearnState {
|
LearnState {
|
||||||
remaining_steps: ctx.steps.remaining_for_good(self.remaining_steps),
|
remaining_steps: ctx.steps.remaining_for_good(self.remaining_steps),
|
||||||
scheduled_secs: ctx.with_learning_fuzz(good_delay),
|
scheduled_secs: good_delay,
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -121,21 +121,6 @@ impl<'a> StateContext<'a> {
|
||||||
.round() as u32
|
.round() as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add up to 25% increase to seconds, but no more than 5 minutes.
|
|
||||||
pub(crate) fn with_learning_fuzz(&self, secs: u32) -> u32 {
|
|
||||||
if let Some(seed) = self.fuzz_seed {
|
|
||||||
let mut rng = StdRng::seed_from_u64(seed);
|
|
||||||
let upper_exclusive = secs + ((secs as f32) * 0.25).min(300.0).floor() as u32;
|
|
||||||
if secs >= upper_exclusive {
|
|
||||||
secs
|
|
||||||
} else {
|
|
||||||
rng.gen_range(secs, upper_exclusive)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
secs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn fuzzed_graduating_interval_good(&self) -> u32 {
|
pub(crate) fn fuzzed_graduating_interval_good(&self) -> u32 {
|
||||||
self.with_review_fuzz(self.graduating_interval_good as f32)
|
self.with_review_fuzz(self.graduating_interval_good as f32)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,18 +18,18 @@ impl PreviewState {
|
||||||
NextCardStates {
|
NextCardStates {
|
||||||
current: self.into(),
|
current: self.into(),
|
||||||
again: PreviewState {
|
again: PreviewState {
|
||||||
scheduled_secs: ctx.with_learning_fuzz(ctx.preview_step * 60),
|
scheduled_secs: ctx.preview_step * 60,
|
||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
hard: PreviewState {
|
hard: PreviewState {
|
||||||
// ~15 minutes with the default setting
|
// ~15 minutes with the default setting
|
||||||
scheduled_secs: ctx.with_learning_fuzz(ctx.preview_step * 90),
|
scheduled_secs: ctx.preview_step * 90,
|
||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
good: PreviewState {
|
good: PreviewState {
|
||||||
scheduled_secs: ctx.with_learning_fuzz(ctx.preview_step * 120),
|
scheduled_secs: ctx.preview_step * 120,
|
||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
|
|
|
@ -36,7 +36,7 @@ impl RelearnState {
|
||||||
RelearnState {
|
RelearnState {
|
||||||
learning: LearnState {
|
learning: LearnState {
|
||||||
remaining_steps: ctx.relearn_steps.remaining_for_failed(),
|
remaining_steps: ctx.relearn_steps.remaining_for_failed(),
|
||||||
scheduled_secs: ctx.with_learning_fuzz(again_delay),
|
scheduled_secs: again_delay,
|
||||||
},
|
},
|
||||||
review: ReviewState {
|
review: ReviewState {
|
||||||
scheduled_days: self.review.failing_review_interval(ctx),
|
scheduled_days: self.review.failing_review_interval(ctx),
|
||||||
|
@ -57,7 +57,7 @@ impl RelearnState {
|
||||||
{
|
{
|
||||||
RelearnState {
|
RelearnState {
|
||||||
learning: LearnState {
|
learning: LearnState {
|
||||||
scheduled_secs: ctx.with_learning_fuzz(hard_delay),
|
scheduled_secs: hard_delay,
|
||||||
..self.learning
|
..self.learning
|
||||||
},
|
},
|
||||||
review: ReviewState {
|
review: ReviewState {
|
||||||
|
@ -78,7 +78,7 @@ impl RelearnState {
|
||||||
{
|
{
|
||||||
RelearnState {
|
RelearnState {
|
||||||
learning: LearnState {
|
learning: LearnState {
|
||||||
scheduled_secs: ctx.with_learning_fuzz(good_delay),
|
scheduled_secs: good_delay,
|
||||||
remaining_steps: ctx
|
remaining_steps: ctx
|
||||||
.relearn_steps
|
.relearn_steps
|
||||||
.remaining_for_good(self.learning.remaining_steps),
|
.remaining_for_good(self.learning.remaining_steps),
|
||||||
|
|
|
@ -86,7 +86,7 @@ impl ReviewState {
|
||||||
RelearnState {
|
RelearnState {
|
||||||
learning: LearnState {
|
learning: LearnState {
|
||||||
remaining_steps: ctx.relearn_steps.remaining_for_failed(),
|
remaining_steps: ctx.relearn_steps.remaining_for_failed(),
|
||||||
scheduled_secs: ctx.with_learning_fuzz(again_delay),
|
scheduled_secs: again_delay,
|
||||||
},
|
},
|
||||||
review: again_review,
|
review: again_review,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue