space exiting new cards; fix 1 fact freeze

This commit is contained in:
Damien Elmes 2011-03-21 08:52:37 +09:00
parent 8b2971f91c
commit da0fb0c555
2 changed files with 103 additions and 6 deletions

View file

@ -126,8 +126,13 @@ queue = 0 %s order by due limit %d""" % (self._groupLimit('new'),
(id, due) = self.newQueue.pop() (id, due) = self.newQueue.pop()
# move any siblings to the end? # move any siblings to the end?
if self.deck.qconf['newTodayOrder'] == NEW_TODAY_ORD: if self.deck.qconf['newTodayOrder'] == NEW_TODAY_ORD:
n = len(self.newQueue)
while self.newQueue and self.newQueue[-1][1] == due: while self.newQueue and self.newQueue[-1][1] == due:
self.newQueue.insert(0, self.newQueue.pop()) self.newQueue.insert(0, self.newQueue.pop())
n -= 1
if not n:
# we only have one fact in the queue; stop rotating
break
self.newCount -= 1 self.newCount -= 1
return id return id
@ -219,13 +224,14 @@ limit %d""" % self.reportLimit, lim=self.dayCutoff)
def _graduatingIvl(self, card, conf, early): def _graduatingIvl(self, card, conf, early):
if not early: if not early:
# graduate # graduate
return conf['ints'][0] ideal = conf['ints'][0]
elif card.cycles: elif card.cycles:
# remove # remove
return conf['ints'][2] ideal = conf['ints'][2]
else: else:
# first time bonus # first time bonus
return conf['ints'][1] ideal = conf['ints'][1]
return self._adjRevIvl(card, ideal)
def _rescheduleNew(self, card, conf, early): def _rescheduleNew(self, card, conf, early):
card.ivl = self._graduatingIvl(card, conf, early) card.ivl = self._graduatingIvl(card, conf, early)
@ -374,6 +380,10 @@ queue = 2 %s and due <= :lim order by %s limit %d""" % (
def _updateRevIvl(self, card, ease): def _updateRevIvl(self, card, ease):
"Update CARD's interval, trying to avoid siblings." "Update CARD's interval, trying to avoid siblings."
idealIvl = self._nextRevIvl(card, ease) idealIvl = self._nextRevIvl(card, ease)
card.ivl = self._adjRevIvl(card, idealIvl)
def _adjRevIvl(self, card, idealIvl):
"Given IDEALIVL, return an IVL away from siblings."
idealDue = self.today + idealIvl idealDue = self.today + idealIvl
conf = self._cardConf(card)['rev'] conf = self._cardConf(card)['rev']
# find sibling positions # find sibling positions
@ -381,12 +391,12 @@ queue = 2 %s and due <= :lim order by %s limit %d""" % (
"select due from cards where fid = ? and queue = 2" "select due from cards where fid = ? and queue = 2"
" and id != ?", card.fid, card.id) " and id != ?", card.fid, card.id)
if not dues or idealDue not in dues: if not dues or idealDue not in dues:
card.ivl = idealIvl return idealIvl
else: else:
leeway = max(conf['minSpace'], int(idealIvl * conf['fuzz'])) leeway = max(conf['minSpace'], int(idealIvl * conf['fuzz']))
fudge = 0
# do we have any room to adjust the interval? # do we have any room to adjust the interval?
if leeway: if leeway:
fudge = 0
# loop through possible due dates for an empty one # loop through possible due dates for an empty one
for diff in range(1, leeway+1): for diff in range(1, leeway+1):
# ensure we're due at least tomorrow # ensure we're due at least tomorrow
@ -396,7 +406,7 @@ queue = 2 %s and due <= :lim order by %s limit %d""" % (
elif (idealDue + diff) not in dues: elif (idealDue + diff) not in dues:
fudge = diff fudge = diff
break break
card.ivl = idealIvl + fudge return idealIvl + fudge
# Leeches # Leeches
########################################################################## ##########################################################################

View file

@ -409,3 +409,90 @@ def test_cramLimits():
assert d.sched.counts()[0] == 1 assert d.sched.counts()[0] == 1
d.cramGroups([1], min=0, max=1) d.cramGroups([1], min=0, max=1)
assert d.sched.counts()[0] == 2 assert d.sched.counts()[0] == 2
def test_adjIvl():
d = getEmptyDeck()
# add two more templates and set second active
m = d.currentModel()
m.templates[1]['actv'] = True
t = m.newTemplate()
t['name'] = "f2"
t['qfmt'] = "{{Front}}"
t['afmt'] = "{{Back}}"
m.addTemplate(t)
t = m.newTemplate()
t['name'] = "f3"
t['qfmt'] = "{{Front}}"
t['afmt'] = "{{Back}}"
m.addTemplate(t)
m.flush()
# create a new fact; it should have 4 cards
f = d.newFact()
f['Front'] = "1"; f['Back'] = "1"
d.addFact(f)
assert d.cardCount() == 4
d.reset()
# immediately remove first; it should get ideal ivl
c = d.sched.getCard()
d.sched.answerCard(c, 3)
assert c.ivl == 7
# with the default settings, second card should be -1
c = d.sched.getCard()
d.sched.answerCard(c, 3)
assert c.ivl == 6
# and third +1
c = d.sched.getCard()
d.sched.answerCard(c, 3)
assert c.ivl == 8
# fourth exceeds default settings, so gets ideal again
c = d.sched.getCard()
d.sched.answerCard(c, 3)
assert c.ivl == 7
# try again with another fact
f = d.newFact()
f['Front'] = "2"; f['Back'] = "2"
d.addFact(f)
d.reset()
# set a minSpacing of 0
conf = d.sched._cardConf(c)
conf['rev']['minSpace'] = 0
# first card gets ideal
c = d.sched.getCard()
d.sched.answerCard(c, 3)
assert c.ivl == 7
# and second too, because it's below the threshold
c = d.sched.getCard()
d.sched.answerCard(c, 3)
assert c.ivl == 7
# if we increase the ivl minSpace isn't needed
conf['new']['ints'][1] = 20
# ideal..
c = d.sched.getCard()
d.sched.answerCard(c, 3)
assert c.ivl == 20
# adjusted
c = d.sched.getCard()
d.sched.answerCard(c, 3)
assert c.ivl == 19
def test_ordcycle():
d = getEmptyDeck()
# add two more templates and set second active
m = d.currentModel()
m.templates[1]['actv'] = True
t = m.newTemplate()
t['name'] = "f2"
t['qfmt'] = "{{Front}}"
t['afmt'] = "{{Back}}"
m.addTemplate(t)
m.flush()
# create a new fact; it should have 4 cards
f = d.newFact()
f['Front'] = "1"; f['Back'] = "1"
d.addFact(f)
assert d.cardCount() == 3
d.reset()
# ordinals should arrive in order
assert d.sched.getCard().ord == 0
assert d.sched.getCard().ord == 1
assert d.sched.getCard().ord == 2