mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
add rescheduling and interval reset to cram; don't include already due cards
This commit is contained in:
parent
be045d451c
commit
9b70af678c
4 changed files with 61 additions and 12 deletions
21
anki/cram.py
21
anki/cram.py
|
@ -34,6 +34,13 @@ class CramScheduler(Scheduler):
|
||||||
self._answerLrnCard(card, ease)
|
self._answerLrnCard(card, ease)
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid queue")
|
raise Exception("Invalid queue")
|
||||||
|
if ease == 1:
|
||||||
|
conf = self._lrnConf(card)
|
||||||
|
if conf['reset']:
|
||||||
|
# reset interval
|
||||||
|
card.ivl = max(1, int(card.ivl * conf['mult']))
|
||||||
|
# mark card as due today so that it doesn't get rescheduled
|
||||||
|
card.due = card.edue = self.today
|
||||||
card.mod = intTime()
|
card.mod = intTime()
|
||||||
card.flushSched()
|
card.flushSched()
|
||||||
|
|
||||||
|
@ -47,9 +54,11 @@ class CramScheduler(Scheduler):
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def _resetNew(self):
|
def _resetNew(self):
|
||||||
|
"All review cards that are not due yet."
|
||||||
self.newQueue = self.db.list("""
|
self.newQueue = self.db.list("""
|
||||||
select id from cards where queue = 2
|
select id from cards where queue = 2 and due > %d
|
||||||
and gid in %s order by %s limit %d""" % (ids2str(self.gids),
|
and gid in %s order by %s limit %d""" % (self.today,
|
||||||
|
ids2str(self.gids),
|
||||||
self.order,
|
self.order,
|
||||||
self.reportLimit))
|
self.reportLimit))
|
||||||
self.newCount = len(self.newQueue)
|
self.newCount = len(self.newQueue)
|
||||||
|
@ -72,15 +81,15 @@ and gid in %s order by %s limit %d""" % (ids2str(self.gids),
|
||||||
|
|
||||||
def _rescheduleAsRev(self, card, conf, early):
|
def _rescheduleAsRev(self, card, conf, early):
|
||||||
Scheduler._rescheduleAsRev(self, card, conf, early)
|
Scheduler._rescheduleAsRev(self, card, conf, early)
|
||||||
card.ivl = self._graduatingIvl(card, conf, early)
|
ivl = self._graduatingIvl(card, conf, early)
|
||||||
card.due = self.today + card.ivl
|
card.due = self.today + ivl
|
||||||
# temporarily suspend it
|
# temporarily suspend it
|
||||||
card.queue = -3
|
card.queue = -3
|
||||||
|
|
||||||
def _graduatingIvl(self, card, conf, early):
|
def _graduatingIvl(self, card, conf, early):
|
||||||
if conf['resched']:
|
if conf['resched']:
|
||||||
print "fixme"
|
# shift card by the time it was delayed
|
||||||
return card.ivl
|
return card.ivl - card.edue - self.today
|
||||||
else:
|
else:
|
||||||
return card.ivl
|
return card.ivl
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright: Damien Elmes <anki@ichi2.net>
|
# Copyright: Damien Elmes <anki@ichi2.net>
|
||||||
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
|
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
|
||||||
|
|
||||||
import simplejson, time
|
import simplejson
|
||||||
from anki.utils import intTime
|
from anki.utils import intTime
|
||||||
|
|
||||||
# maybe define a random cutoff at say +/-30% which controls exit interval
|
# maybe define a random cutoff at say +/-30% which controls exit interval
|
||||||
|
@ -26,6 +26,8 @@ defaultConf = {
|
||||||
'cram': {
|
'cram': {
|
||||||
'delays': [0.5, 3, 10],
|
'delays': [0.5, 3, 10],
|
||||||
'resched': True,
|
'resched': True,
|
||||||
|
'reset': True,
|
||||||
|
'mult': 0,
|
||||||
},
|
},
|
||||||
'rev': {
|
'rev': {
|
||||||
'ease4': 1.3,
|
'ease4': 1.3,
|
||||||
|
|
|
@ -160,6 +160,7 @@ If the same name exists, compare checksums."""
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def downloadMissing(self):
|
def downloadMissing(self):
|
||||||
|
raise Exception()
|
||||||
urlbase = self.deck.getVar("mediaURL")
|
urlbase = self.deck.getVar("mediaURL")
|
||||||
if not urlbase:
|
if not urlbase:
|
||||||
return None
|
return None
|
||||||
|
@ -189,6 +190,7 @@ If the same name exists, compare checksums."""
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def downloadRemote(self):
|
def downloadRemote(self):
|
||||||
|
raise Exception()
|
||||||
mdir = self.deck.dir(create=True)
|
mdir = self.deck.dir(create=True)
|
||||||
refs = {}
|
refs = {}
|
||||||
for (question, answer) in self.deck.db.all(
|
for (question, answer) in self.deck.db.all(
|
||||||
|
|
|
@ -310,19 +310,29 @@ def test_cram():
|
||||||
c = f.cards()[0]
|
c = f.cards()[0]
|
||||||
c.ivl = 100
|
c.ivl = 100
|
||||||
c.type = c.queue = 2
|
c.type = c.queue = 2
|
||||||
c.due = d.sched.today + 50
|
# due in 25 days, so it's been waiting 75 days
|
||||||
|
c.due = d.sched.today + 25
|
||||||
c.mod = 1
|
c.mod = 1
|
||||||
|
c.startTimer()
|
||||||
c.flush()
|
c.flush()
|
||||||
|
cardcopy = copy.copy(c)
|
||||||
d.cramGroups([1])
|
d.cramGroups([1])
|
||||||
|
# first, test with initial intervals preserved
|
||||||
|
conf = d.sched._lrnConf(c)
|
||||||
|
conf['reset'] = False
|
||||||
|
conf['resched'] = False
|
||||||
assert d.sched.counts() == (1, 0, 0)
|
assert d.sched.counts() == (1, 0, 0)
|
||||||
c = d.sched.getCard()
|
c = d.sched.getCard()
|
||||||
assert d.sched.counts() == (0, 0, 0)
|
assert d.sched.counts() == (0, 0, 0)
|
||||||
# check that estimates work
|
# check that estimates work
|
||||||
assert d.sched.nextIvl(c, 1) == 30
|
assert d.sched.nextIvl(c, 1) == 30
|
||||||
assert d.sched.nextIvl(c, 2) == 180
|
assert d.sched.nextIvl(c, 2) == 180
|
||||||
print "fixme"
|
assert d.sched.nextIvl(c, 3) == 86400*100
|
||||||
print d.sched.nextIvl(c, 3) == 86400*100
|
# failing it should not reset ivl
|
||||||
# answer it
|
assert c.ivl == 100
|
||||||
|
d.sched.answerCard(c, 1)
|
||||||
|
assert c.ivl == 100
|
||||||
|
# reset ivl for exit test, and pass card
|
||||||
d.sched.answerCard(c, 2)
|
d.sched.answerCard(c, 2)
|
||||||
delta = c.due - time.time()
|
delta = c.due - time.time()
|
||||||
assert delta > 175 and delta <= 180
|
assert delta > 175 and delta <= 180
|
||||||
|
@ -331,8 +341,34 @@ def test_cram():
|
||||||
d.sched.answerCard(c, 2)
|
d.sched.answerCard(c, 2)
|
||||||
d.sched.answerCard(c, 2)
|
d.sched.answerCard(c, 2)
|
||||||
assert c.queue == -3
|
assert c.queue == -3
|
||||||
print "fixme"
|
|
||||||
assert c.ivl == 100
|
assert c.ivl == 100
|
||||||
# and if the queue is reset, it shouldn't appear in the new queue again
|
# and if the queue is reset, it shouldn't appear in the new queue again
|
||||||
d.reset()
|
d.reset()
|
||||||
assert d.sched.counts() == (0, 0, 0)
|
assert d.sched.counts() == (0, 0, 0)
|
||||||
|
# now try again with ivl rescheduling
|
||||||
|
c = copy.copy(cardcopy)
|
||||||
|
c.flush()
|
||||||
|
d.cramGroups([1])
|
||||||
|
conf = d.sched._lrnConf(c)
|
||||||
|
conf['reset'] = False
|
||||||
|
conf['resched'] = True
|
||||||
|
# failures shouldn't matter
|
||||||
|
d.sched.answerCard(c, 1)
|
||||||
|
# graduating the card will keep the same interval, but shift the card
|
||||||
|
# forward the number of days it had been waiting (75)
|
||||||
|
assert d.sched.nextIvl(c, 3) == 75*86400
|
||||||
|
d.sched.answerCard(c, 3)
|
||||||
|
assert c.ivl == 100
|
||||||
|
assert c.due == d.sched.today + 75
|
||||||
|
# try with ivl reset
|
||||||
|
c = copy.copy(cardcopy)
|
||||||
|
c.flush()
|
||||||
|
d.cramGroups([1])
|
||||||
|
conf = d.sched._lrnConf(c)
|
||||||
|
conf['reset'] = True
|
||||||
|
conf['resched'] = True
|
||||||
|
d.sched.answerCard(c, 1)
|
||||||
|
assert d.sched.nextIvl(c, 3) == 1*86400
|
||||||
|
d.sched.answerCard(c, 3)
|
||||||
|
assert c.ivl == 1
|
||||||
|
assert c.due == d.sched.today + 1
|
||||||
|
|
Loading…
Reference in a new issue