give card types a more logical order

they are now 0=new, 1=learning, 2=due, to reflect the natural progression
This commit is contained in:
Damien Elmes 2011-03-18 11:01:26 +09:00
parent 6f5918e8cd
commit 22a72d82c6
4 changed files with 58 additions and 57 deletions

View file

@ -10,9 +10,9 @@ MAX_TIMER = 60
# Cards
##########################################################################
# Type: 0=learning, 1=due, 2=new
# Queue: 0=learning, 1=due, 2=new
# -1=suspended, -2=user buried, -3=sched buried
# Type: 0=new, 1=learning, 2=due
# Queue: same as above, and:
# -1=suspended, -2=user buried, -3=sched buried, -4=deleted
# Due is used differently for different queues.
# - new queue: fact id or random int
# - rev queue: integer day
@ -32,8 +32,8 @@ class Card(object):
self.id = None
self.gid = 1
self.crt = intTime()
self.type = 2
self.queue = 2
self.type = 0
self.queue = 0
self.ivl = 0
self.factor = 0
self.reps = 0

View file

@ -256,7 +256,7 @@ select id from facts where id not in (select distinct fid from cards)""")
if self.qconf['newCardOrder'] == NEW_CARDS_RANDOM:
# if this fact has existing new cards, use their due time
due = self.db.scalar(
"select due from cards where fid = ? and queue = 2", fact.id)
"select due from cards where fid = ? and queue = 0", fact.id)
due = due or random.randrange(1, 1000000)
else:
due = fact.id

View file

@ -42,13 +42,12 @@ class Scheduler(object):
def answerCard(self, card, ease):
if card.queue == 0:
self._answerLearnCard(card, ease)
elif card.queue == 1:
self._answerRevCard(card, ease)
elif card.queue == 2:
# put it in the learn queue
card.queue = 0
card.queue = 1
if card.queue == 1:
self._answerLearnCard(card, ease)
elif card.queue == 2:
self._answerRevCard(card, ease)
else:
raise Exception("Invalid queue")
card.mod = intTime()
@ -56,7 +55,7 @@ class Scheduler(object):
def counts(self):
"Does not include fetched but unanswered."
return (self.learnCount, self.revCount, self.newCount)
return (self.newCount, self.learnCount, self.revCount)
def cardQueue(self, card):
return card.queue
@ -110,14 +109,14 @@ class Scheduler(object):
else:
self.newCount = self.db.scalar("""
select count() from (select id from cards where
queue = 2 %s limit %d)""" % (self._groupLimit('new'), lim))
queue = 0 %s limit %d)""" % (self._groupLimit('new'), lim))
def _resetNew(self):
self._resetNewCount()
lim = min(self.queueLimit, self.newCount)
self.newQueue = self.db.all("""
select id, due from cards where
queue = 2 %s order by due limit %d""" % (self._groupLimit('new'),
queue = 0 %s order by due limit %d""" % (self._groupLimit('new'),
lim))
self.newQueue.reverse()
self._updateNewCardRatio()
@ -159,14 +158,14 @@ queue = 2 %s order by due limit %d""" % (self._groupLimit('new'),
def _resetLearnCount(self):
self.learnCount = self.db.scalar(
"select count() from cards where queue = 0 and due < ?",
"select count() from cards where queue = 1 and due < ?",
intTime() + self.deck.qconf['collapseTime'])
def _resetLearn(self):
self._resetLearnCount()
self.learnQueue = self.db.all("""
select due, id from cards where
queue = 0 and due < :lim order by due
queue = 1 and due < :lim order by due
limit %d""" % self.reportLimit, lim=self.dayCutoff)
def _getLearnCard(self, collapse=False):
@ -208,18 +207,18 @@ limit %d""" % self.reportLimit, lim=self.dayCutoff)
def _learnConf(self, card):
conf = self._cardConf(card)
if card.type == 2:
return conf['new']
else:
return conf['lapse']
else:
return conf['new']
def _rescheduleAsReview(self, card, conf, early):
if card.type == 1:
if card.type == 2:
# failed; put back entry due
card.due = card.edue
else:
self._rescheduleNew(card, conf, early)
card.queue = 1
card.type = 1
card.queue = 2
card.type = 2
def _graduatingIvl(self, card, conf, early):
if not early:
@ -258,8 +257,8 @@ limit %d""" % self.reportLimit, lim=self.dayCutoff)
"Remove failed cards from the learning queue."
self.deck.db.execute("""
update cards set
due = edue, queue = 1
where queue = 0 and type = 1
due = edue, queue = 2
where queue = 1 and type = 2
""")
# Reviews
@ -268,7 +267,7 @@ where queue = 0 and type = 1
def _resetReviewCount(self):
self.revCount = self.db.scalar("""
select count() from (select id from cards where
queue = 1 %s and due <= :lim limit %d)""" % (
queue = 2 %s and due <= :lim limit %d)""" % (
self._groupLimit("rev"), self.reportLimit),
lim=self.today)
@ -276,7 +275,7 @@ queue = 1 %s and due <= :lim limit %d)""" % (
self._resetReviewCount()
self.revQueue = self.db.list("""
select id from cards where
queue = 1 %s and due <= :lim order by %s limit %d""" % (
queue = 2 %s and due <= :lim order by %s limit %d""" % (
self._groupLimit("rev"), self._revOrder(), self.queueLimit),
lim=self.today)
if self.deck.qconf['revCardOrder'] == REV_CARDS_RANDOM:
@ -321,7 +320,7 @@ queue = 1 %s and due <= :lim order by %s limit %d""" % (
card.due = card.edue = self.today + card.ivl
# put back in the learn queue?
if conf['relearn']:
card.queue = 0
card.queue = 1
self.learnCount += 1
# leech?
self._checkLeech(card, conf)
@ -382,7 +381,7 @@ queue = 1 %s and due <= :lim order by %s limit %d""" % (
conf = self._cardConf(card)['rev']
# find sibling positions
dues = self.db.list(
"select due from cards where fid = ? and queue = 1"
"select due from cards where fid = ? and queue = 2"
" and id != ?", card.fid, card.id)
if not dues or idealDue not in dues:
card.ivl = idealIvl
@ -508,13 +507,13 @@ queue = 1 %s and due <= :lim order by %s limit %d""" % (
def lrnTomorrow(self):
"Number of cards in the learning queue due tomorrow."
return self.db.scalar(
"select count() from cards where queue = 0 and due < ?",
"select count() from cards where queue = 1 and due < ?",
self.dayCutoff+86400)
def revTomorrow(self):
"Number of reviews due tomorrow."
return self.db.scalar(
"select count() from cards where queue = 1 and due = ?"+
"select count() from cards where queue = 2 and due = ?"+
self._groupLimit("rev"),
self.today+1)
@ -523,7 +522,7 @@ queue = 1 %s and due <= :lim order by %s limit %d""" % (
lim = self.deck.qconf['newPerDay']
return self.db.scalar(
"select count() from (select id from cards where "
"queue = 2 limit %d)" % lim)
"queue = 0 limit %d)" % lim)
# Next time reports
##########################################################################
@ -535,7 +534,7 @@ queue = 1 %s and due <= :lim order by %s limit %d""" % (
def nextIvl(self, card, ease):
"Return the next interval for CARD, in seconds."
if card.queue in (0,2):
if card.queue in (0,1):
# in learning
return self._nextLrnIvl(card, ease)
elif ease == 1:

View file

@ -22,13 +22,13 @@ def test_new():
# fetch it
c = d.sched.getCard()
assert c
assert c.queue == 2
assert c.type == 2
assert c.queue == 0
assert c.type == 0
# if we answer it, it should become a learn card
t = intTime()
d.sched.answerCard(c, 1)
assert c.queue == 0
assert c.type == 2
assert c.queue == 1
assert c.type == 0
assert c.due >= t
# the default order should ensure siblings are not seen together, and
# should show all cards
@ -55,7 +55,7 @@ def test_learn():
f['Front'] = u"one"; f['Back'] = u"two"
f = d.addFact(f)
# set as a learn card and rebuild queues
d.db.execute("update cards set queue=0, type=2")
d.db.execute("update cards set queue=0, type=0")
d.reset()
# sched.getCard should return it, since it's due in the past
c = d.sched.getCard()
@ -90,46 +90,47 @@ def test_learn():
assert c.grade == 2
assert c.cycles == 3
# the next pass should graduate the card
assert c.queue == 0
assert c.type == 2
d.sched.answerCard(c, 2)
assert c.queue == 1
assert c.type == 1
assert c.type == 0
d.sched.answerCard(c, 2)
assert c.queue == 2
assert c.type == 2
# should be due tomorrow, with an interval of 1
assert c.due == d.sched.today+1
assert c.ivl == 1
# let's try early removal bonus
c.type = 2
c.queue = 0
c.type = 0
c.queue = 1
c.cycles = 0
d.sched.answerCard(c, 3)
assert c.type == 1
assert c.type == 2
assert c.ivl == 7
# or normal removal
c.type = 2
c.queue = 0
c.type = 0
c.queue = 1
c.cycles = 1
d.sched.answerCard(c, 3)
assert c.type == 1
assert c.type == 2
assert c.queue == 2
assert c.ivl == 4
# revlog should have been updated each time
d.db.scalar("select count() from revlog where type = 0") == 6
# now failed card handling
c.type = 1
c.queue = 0
c.type = 2
c.queue = 1
c.edue = 123
d.sched.answerCard(c, 3)
assert c.due == 123
assert c.type == 1
assert c.queue == 1
assert c.type == 2
assert c.queue == 2
# we should be able to remove manually, too
c.type = 1
c.queue = 0
c.type = 2
c.queue = 1
c.edue = 321
c.flush()
d.sched.removeFailed()
c.load()
assert c.queue == 1
assert c.queue == 2
assert c.due == 321
def test_reviews():
@ -140,8 +141,8 @@ def test_reviews():
d.addFact(f)
# set the card up as a review card, due yesterday
c = f.cards()[0]
c.type = 1
c.queue = 1
c.type = 2
c.queue = 2
c.due = d.sched.today - 8
c.factor = 2500
c.reps = 3
@ -156,7 +157,7 @@ def test_reviews():
# failing it should put it in the learn queue with the default options
##################################################
d.sched.answerCard(c, 1)
assert c.queue == 0
assert c.queue == 1
# it should be due tomorrow, with an interval of 1
assert c.due == d.sched.today + 1
assert c.ivl == 1
@ -171,6 +172,7 @@ def test_reviews():
c = copy.copy(cardcopy)
c.flush()
d.sched.answerCard(c, 2)
assert c.queue == 2
# the new interval should be (100 + 8/4) * 1.2 = 122
assert c.ivl == 122
assert c.due == d.sched.today + 122
@ -257,7 +259,7 @@ def test_nextIvl():
assert ni(c, 3) == 4*86400
# review cards
##################################################
c.queue = 1
c.queue = 2
c.ivl = 100
c.factor = 2500
# failing it puts it at tomorrow