implement cram

still to do:
- altering intervals at cram exit
- tidying up
This commit is contained in:
Damien Elmes 2011-03-18 13:21:11 +09:00
parent 308846aa93
commit bd477de1a9
5 changed files with 116 additions and 18 deletions

View file

@ -2,9 +2,12 @@
# Copyright: Damien Elmes <anki@ichi2.net>
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
from anki.utils import ids2str
from anki.utils import ids2str, intTime
from anki.sched import Scheduler
# The order arg should be the opposite of what you want. So if you want
# modified ascending, pass in 'mod desc'.
class CramScheduler(Scheduler):
name = "cram"
@ -14,11 +17,80 @@ class CramScheduler(Scheduler):
self.order = order
self.reset()
def counts(self):
return (self.newCount, self.lrnCount, 0)
def reset(self):
pass
self._resetConf()
self._resetLrn()
self._resetNew()
self._resetRev()
def getCard(self):
pass
def answerCard(self, card, ease):
if card.queue == 2:
card.queue = 1
card.edue = card.due
if card.queue == 1:
self._answerLrnCard(card, ease)
else:
raise Exception("Invalid queue")
card.mod = intTime()
card.flushSched()
def countIdx(self, card):
if card.queue == 2:
return 0
else:
return 1
# Fetching
##########################################################################
def _resetNew(self):
self.newQueue = self.db.list("""
select id from cards where queue = 2
and gid in %s order by %s limit %d""" % (ids2str(self.gids),
self.order,
self.reportLimit))
self.newCount = len(self.newQueue)
def _resetRev(self):
self.revQueue = []
self.revCount = 0
def _timeForNewCard(self):
return True
def _getNewCard(self):
if self.newQueue:
id = self.newQueue.pop()
self.newCount -= 1
return id
# Answering
##########################################################################
def _rescheduleAsRev(self, card, conf, early):
Scheduler._rescheduleAsRev(self, card, conf, early)
card.ivl = self._graduatingIvl(card, conf, early)
card.due = self.today + card.ivl
# temporarily suspend it
card.queue = -3
def _graduatingIvl(self, card, conf, early):
if conf['resched']:
print "fixme"
return card.ivl
else:
return card.ivl
def _lrnConf(self, card):
return self._cardConf(card)['cram']
# Next time reports
##########################################################################
def nextIvl(self, card, ease):
"Return the next interval for CARD, in seconds."
return self._nextLrnIvl(card, ease)
def answerCard(self):
pass

View file

@ -655,7 +655,7 @@ select conf from gconf where id = (select gcid from groups where id = ?)""",
self.sched.onClose()
self.sched = self._stdSched
def cramGroups(self, gids, order="mod"):
def cramGroups(self, gids, order="mod desc"):
self.stdSched()
self.sched = anki.cram.CramScheduler(self, gids, order)

View file

@ -23,11 +23,15 @@ defaultConf = {
# one of [suspend], [tagonly]
'leechAction': ["suspend"],
},
'cram': {
'delays': [0.5, 3, 10],
'resched': True,
},
'rev': {
'ease4': 1.3,
'fuzz': 0.05,
'minSpace': 1,
}
},
}
class GroupConfig(object):

View file

@ -57,7 +57,7 @@ class Scheduler(object):
"Does not include fetched but unanswered."
return (self.newCount, self.lrnCount, self.revCount)
def cardQueue(self, card):
def countIdx(self, card):
return card.queue
def onClose(self):

View file

@ -1,6 +1,6 @@
# coding: utf-8
import time
import time, copy
from tests.shared import assertException, getEmptyDeck
from anki.stdmodels import BasicModel
from anki.utils import stripHTML, intTime
@ -152,7 +152,6 @@ def test_reviews():
c.startTimer()
c.flush()
# save it for later use as well
import copy
cardcopy = copy.copy(c)
# failing it should put it in the learn queue with the default options
##################################################
@ -270,7 +269,7 @@ def test_nextIvl():
assert ni(c, 3) == 21600000
# (* 100 2.5 1.3 86400)28080000.0
assert ni(c, 4) == 28080000
print d.sched.nextIvlStr(c, 4) == "10.8 months"
assert d.sched.nextIvlStr(c, 4) == "10.8 months"
def test_misc():
d = getEmptyDeck()
@ -308,9 +307,32 @@ def test_cram():
f = d.newFact()
f['Front'] = u"one"
d.addFact(f)
f = d.newFact()
f['Front'] = u"two"
d.addFact(f)
d.cramGroups(1)
c = f.cards()[0]
c.ivl = 100
c.type = c.queue = 2
c.due = d.sched.today + 50
c.mod = 1
c.flush()
d.cramGroups([1])
assert d.sched.counts() == (1, 0, 0)
c = d.sched.getCard()
assert d.sched.counts() == (0, 0, 0)
# check that estimates work
assert d.sched.nextIvl(c, 1) == 30
assert d.sched.nextIvl(c, 2) == 180
print "fixme"
print d.sched.nextIvl(c, 3) == 86400*100
# answer it
d.sched.answerCard(c, 2)
delta = c.due - time.time()
assert delta > 175 and delta <= 180
# another two answers should reschedule it
assert c.queue == 1
d.sched.answerCard(c, 2)
d.sched.answerCard(c, 2)
assert c.queue == -3
print "fixme"
assert c.ivl == 100
# and if the queue is reset, it shouldn't appear in the new queue again
d.reset()
assert d.sched.counts() == (0, 0, 0)