removing cram decks, estimates, failure handling

This commit is contained in:
Damien Elmes 2012-03-09 06:56:07 +09:00
parent 01404fafaa
commit ffaf7ffc66
3 changed files with 68 additions and 29 deletions

View file

@ -122,6 +122,12 @@ class DeckManager(object):
# do nothing else if doesn't exist
if not str(did) in self.decks:
return
deck = self.get(did)
if deck.get('cram'):
# deleting a cramming deck returns cards to their previous deck
# rather than deleting the cards
self.col.sched.remCram(did)
else:
# delete children first
if childrenToo:
# we don't want to delete children when syncing

View file

@ -64,10 +64,7 @@ class Scheduler(object):
# cramming?
if self._cramming and card.type == 2:
# reviews get their ivl boosted on first sight
elapsed = card.ivl - card.odue - self.today
assert card.factor
factor = ((card.factor/1000.0)+1.2)/2.0
card.ivl = int(max(card.ivl, elapsed * factor, 1))+1
card.ivl = self._cramIvlBoost(card)
card.odue = self.today + card.ivl
self._updateStats(card, 'new')
if card.queue == 1:
@ -437,6 +434,10 @@ limit %d""" % (self._deckLimit(), self.reportLimit), lim=self.dayCutoff)
# failed
else:
card.left = self._startingLeft(card)
if self._cramming:
print "fixme: configurable failure handling"
card.ivl = 1
card.odue = self.today + 1
self.lrnCount += card.left
delay = self._delayForGrade(conf, card.left)
if card.due < time.time():
@ -485,6 +486,8 @@ limit %d""" % (self._deckLimit(), self.reportLimit), lim=self.dayCutoff)
def _graduatingIvl(self, card, conf, early, adj=True):
if card.type == 2:
# lapsed card being relearnt
if self._cramming:
return self._cramIvlBoost(card)
return card.ivl
if not early:
# graduate
@ -739,6 +742,11 @@ did = ? and queue = 2 and due <= ? %s limit ?""" % order,
# and change to our new deck
self.col.decks.select(did)
def remCram(self, did):
self.col.db.execute("""
update cards set did = odid, queue = type, due = odue, odue = 0, odid = 0,
usn = ?, mod = ? where did = ?""", self.col.usn(), intTime(), did)
def _cramOrder(self, order):
if order == "due":
return "order by c.due"
@ -770,6 +778,13 @@ did = ? and queue = 2 and due <= ? %s limit ?""" % order,
update cards set odid = did, odue = due, did = ?, queue = 0, due = ?,
mod = ?, usn = ? where id = ?""", data)
def _cramIvlBoost(self, card):
assert self._cramming and card.type == 2
assert card.factor
elapsed = card.ivl - card.odue - self.today
factor = ((card.factor/1000.0)+1.2)/2.0
return int(max(card.ivl, elapsed * factor, 1))
# Leeches
##########################################################################
@ -893,7 +908,6 @@ your short-term review workload will become."""))
# this isn't easily extracted from the learn code
def _nextLrnIvl(self, card, ease):
if card.queue == 0:
card.type = 1
card.left = self._startingLeft(card)
conf = self._lrnConf(card)
if ease == 1:

View file

@ -453,33 +453,52 @@ def test_cram():
assert sorted(d.sched.deckDueList())[0][3] == 1
# and should appear in the counts
assert d.sched.counts() == (1,0,0)
# grab it and make one step
# grab it and check estimates
c = d.sched.getCard()
assert d.sched.nextIvl(c, 1) == 60
assert d.sched.nextIvl(c, 2) == 600
assert d.sched.nextIvl(c, 3) == 138*60*60*24
d.sched.answerCard(c, 2)
# elapsed time was 75 days
# factor = 2.5+1.2/2 = 1.85
# int(75*1.85)+1 = 139
assert c.ivl == 139
assert c.odue == 139
# int(75*1.85) = 138
assert c.ivl == 138
assert c.odue == 138
assert c.queue == 1
# check ivls again
assert d.sched.nextIvl(c, 1) == 60
assert d.sched.nextIvl(c, 2) == 138*60*60*24
assert d.sched.nextIvl(c, 3) == 138*60*60*24
# when it graduates, due is updated
c = d.sched.getCard()
d.sched.answerCard(c, 2)
assert c.ivl == 139
assert c.due == 139
assert c.ivl == 138
assert c.due == 138
assert c.queue == 2
# and it will have moved back to the previous deck
assert c.did == 1
# card will have moved b
#assert sorted(d.sched.deckDueList())[0][3] == 1
return
# check that estimates work
assert d.sched.nextIvl(c, 1) == 30
assert d.sched.nextIvl(c, 2) == 180
assert d.sched.nextIvl(c, 3) == 86400*100
# cram the deck again
d.sched.cram("")
d.reset()
c = d.sched.getCard()
# check ivls again - passing should be idempotent
assert d.sched.nextIvl(c, 1) == 60
assert d.sched.nextIvl(c, 2) == 600
assert d.sched.nextIvl(c, 3) == 138*60*60*24
d.sched.answerCard(c, 2)
assert c.ivl == 138
assert c.odue == 138
# fail
d.sched.answerCard(c, 1)
assert d.sched.nextIvl(c, 1) == 60
assert d.sched.nextIvl(c, 2) == 600
assert d.sched.nextIvl(c, 3) == 86400
# delete the deck, returning the card mid-study
d.decks.rem(d.decks.selected())
assert len(d.sched.deckDueList()) == 1
c.load()
assert c.ivl == 1
assert c.due == d.sched.today+1
def test_adjIvl():
d = getEmptyDeck()