mirror of
https://github.com/ankitects/anki.git
synced 2025-09-25 01:06:35 -04:00
fetch reviews in subdecks incrementally like new cards
- allows separate review order for different decks - makes new card and rev card handling consistent - for users who find it confusing to have cards from different decks mixed in and thus click on each deck in turn, they can now just select the parent deck and have it work as expected - for users who want their cards mixed together randomly, they can keep the cards in a single deck
This commit is contained in:
parent
d94f6d2011
commit
8c9c3489e5
4 changed files with 81 additions and 72 deletions
|
@ -23,12 +23,8 @@ defaultConf = {
|
|||
'activeDecks': [1],
|
||||
'topDeck': 1,
|
||||
'curDeck': 1,
|
||||
'revOrder': REV_CARDS_RANDOM,
|
||||
# other config
|
||||
'nextPos': 1,
|
||||
'fontFamilies': [
|
||||
[u'MS 明朝',u'ヒラギノ明朝 Pro W3',u'Kochi Mincho', u'東風明朝']
|
||||
],
|
||||
'sortType': "noteFld",
|
||||
'sortBackwards': False,
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ defaultDeck = {
|
|||
|
||||
# configuration only available to top level decks
|
||||
defaultTopConf = {
|
||||
'revLim': 100,
|
||||
'newSpread': NEW_CARDS_DISTRIBUTE,
|
||||
'collapseTime': 1200,
|
||||
'repLim': 0,
|
||||
|
@ -69,10 +68,12 @@ defaultConf = {
|
|||
'minInt': 1,
|
||||
},
|
||||
'rev': {
|
||||
'perDay': 100,
|
||||
'ease4': 1.3,
|
||||
'fuzz': 0.05,
|
||||
'minSpace': 1,
|
||||
'fi': [0.1, 0.1],
|
||||
'order': REV_CARDS_RANDOM,
|
||||
},
|
||||
'maxTaken': 60,
|
||||
'mod': 0,
|
||||
|
|
127
anki/sched.py
127
anki/sched.py
|
@ -119,6 +119,34 @@ order by due""" % self._deckLimit(),
|
|||
g[key][1] += cnt
|
||||
self.col.decks.save(g)
|
||||
|
||||
def _walkingCount(self, limFn=None, cntFn=None):
|
||||
tot = 0
|
||||
pcounts = {}
|
||||
# for each of the active decks
|
||||
for did in self.col.decks.active():
|
||||
# get the individual deck's limit
|
||||
lim = limFn(self.col.decks.get(did))
|
||||
if not lim:
|
||||
continue
|
||||
# check the parents
|
||||
parents = self.col.decks.parents(did)
|
||||
for p in parents:
|
||||
# add if missing
|
||||
if p['id'] not in pcounts:
|
||||
pcounts[p['id']] = limFn(p)
|
||||
# take minimum of child and parent
|
||||
lim = min(pcounts[p['id']], lim)
|
||||
# see how many cards we actually have
|
||||
cnt = cntFn(did, lim)
|
||||
# if non-zero, decrement from parent counts
|
||||
for p in parents:
|
||||
pcounts[p['id']] -= cnt
|
||||
# we may also be a parent
|
||||
pcounts[did] = lim - cnt
|
||||
# and add to running total
|
||||
tot += cnt
|
||||
return tot
|
||||
|
||||
# Deck list
|
||||
##########################################################################
|
||||
|
||||
|
@ -201,37 +229,14 @@ order by due""" % self._deckLimit(),
|
|||
##########################################################################
|
||||
|
||||
def _resetNewCount(self):
|
||||
self.newCount = 0
|
||||
pcounts = {}
|
||||
# for each of the active decks
|
||||
for did in self.col.decks.active():
|
||||
# get the individual deck's limit
|
||||
lim = self._deckNewLimitSingle(self.col.decks.get(did))
|
||||
if not lim:
|
||||
continue
|
||||
# check the parents
|
||||
parents = self.col.decks.parents(did)
|
||||
for p in parents:
|
||||
# add if missing
|
||||
if p['id'] not in pcounts:
|
||||
pcounts[p['id']] = self._deckNewLimitSingle(p)
|
||||
# take minimum of child and parent
|
||||
lim = min(pcounts[p['id']], lim)
|
||||
# see how many cards we actually have
|
||||
cnt = self.col.db.scalar("""
|
||||
cntFn = lambda did, lim: self.col.db.scalar("""
|
||||
select count() from (select 1 from cards where
|
||||
did = ? and queue = 0 limit ?)""", did, lim)
|
||||
# if non-zero, decrement from parent counts
|
||||
for p in parents:
|
||||
pcounts[p['id']] -= cnt
|
||||
# we may also be a parent
|
||||
pcounts[did] = lim - cnt
|
||||
# and add to running total
|
||||
self.newCount += cnt
|
||||
self.newCount = self._walkingCount(self._deckNewLimitSingle, cntFn)
|
||||
|
||||
def _resetNew(self):
|
||||
self._resetNewCount()
|
||||
self.newDids = self.col.decks.active()
|
||||
self._newDids = self.col.decks.active()
|
||||
self._newQueue = []
|
||||
self._updateNewCardRatio()
|
||||
|
||||
|
@ -240,8 +245,8 @@ did = ? and queue = 0 limit ?)""", did, lim)
|
|||
return True
|
||||
if not self.newCount:
|
||||
return False
|
||||
while self.newDids:
|
||||
did = self.newDids[0]
|
||||
while self._newDids:
|
||||
did = self._newDids[0]
|
||||
lim = min(self.queueLimit, self._deckNewLimit(did))
|
||||
if lim:
|
||||
# fill the queue with the current did
|
||||
|
@ -251,14 +256,14 @@ select id, due from cards where did = ? and queue = 0 limit ?""", did, lim)
|
|||
self._newQueue.reverse()
|
||||
return True
|
||||
# nothing left in the deck; move to next
|
||||
self.newDids.pop(0)
|
||||
self._newDids.pop(0)
|
||||
|
||||
def _getNewCard(self):
|
||||
if not self._fillNew():
|
||||
return
|
||||
(id, due) = self._newQueue.pop()
|
||||
# move any siblings to the end?
|
||||
conf = self.col.decks.conf(self.newDids[0])
|
||||
conf = self.col.decks.conf(self._newDids[0])
|
||||
if conf['new']['order'] == NEW_TODAY_ORD:
|
||||
n = len(self._newQueue)
|
||||
while self._newQueue and self._newQueue[-1][1] == due:
|
||||
|
@ -298,12 +303,14 @@ select id, due from cards where did = ? and queue = 0 limit ?""", did, lim)
|
|||
return self.col.db.scalar(
|
||||
"select 1 from cards where did = ? and queue = 0 limit 1", did)
|
||||
|
||||
def _deckNewLimit(self, did):
|
||||
def _deckNewLimit(self, did, fn=None):
|
||||
if not fn:
|
||||
fn = self._deckNewLimitSingle
|
||||
sel = self.col.decks.get(did)
|
||||
lim = -1
|
||||
# for the deck and each of its parents
|
||||
for g in [sel] + self.col.decks.parents(did):
|
||||
rem = self._deckNewLimitSingle(g)
|
||||
rem = fn(g)
|
||||
if lim == -1:
|
||||
lim = rem
|
||||
else:
|
||||
|
@ -465,39 +472,59 @@ where queue = 1 and type = 2
|
|||
# Reviews
|
||||
##########################################################################
|
||||
|
||||
def _deckRevLimit(self, did):
|
||||
return self._deckNewLimit(did, self._deckRevLimitSingle)
|
||||
|
||||
def _deckRevLimitSingle(self, d):
|
||||
c = self.col.decks.conf(d['id'])
|
||||
return max(0, c['rev']['perDay'] - d['revToday'][1])
|
||||
|
||||
def _deckHasRev(self, did):
|
||||
if not self._deckRevLimit(did):
|
||||
return False
|
||||
return self.col.db.scalar(
|
||||
"select 1 from cards where did = ? and queue = 2 "
|
||||
"and due <= ? limit 1",
|
||||
did, self.today)
|
||||
"and due <= ? limit 1", did, self.today)
|
||||
|
||||
def _resetRevCount(self):
|
||||
top = self.col.decks.top()
|
||||
lim = min(self.reportLimit,
|
||||
max(0, top['revLim'] - top['revToday'][1]))
|
||||
self.revCount = self.col.db.scalar("""
|
||||
def cntFn(did, lim):
|
||||
return self.col.db.scalar("""
|
||||
select count() from (select id from cards where
|
||||
did in %s and queue = 2 and due <= :day limit %d)""" % (
|
||||
self._deckLimit(), lim), day=self.today)
|
||||
did = ? and queue = 2 and due <= ? limit %d)""" % lim,
|
||||
did, self.today)
|
||||
self.revCount = self._walkingCount(
|
||||
self._deckRevLimitSingle, cntFn)
|
||||
|
||||
def _resetRev(self):
|
||||
self._resetRevCount()
|
||||
self._revQueue = []
|
||||
self._revDids = self.col.decks.active()
|
||||
|
||||
def _fillRev(self):
|
||||
if not self.revCount:
|
||||
return False
|
||||
if self._revQueue:
|
||||
return True
|
||||
if not self.revCount:
|
||||
return False
|
||||
while self._revDids:
|
||||
did = self._newDids[0]
|
||||
lim = min(self.queueLimit, self._deckRevLimit(did))
|
||||
order = self._revOrder(did)
|
||||
if lim:
|
||||
# fill the queue with the current did
|
||||
self._revQueue = self.col.db.list("""
|
||||
select id from cards where
|
||||
did in %s and queue = 2 and due <= :lim %s limit %d""" % (
|
||||
self._deckLimit(), self._revOrder(), self.queueLimit),
|
||||
lim=self.today)
|
||||
if not self.col.conf['revOrder']:
|
||||
did = ? and queue = 2 and due <= ? %s limit ?""" % order,
|
||||
did, self.today, lim)
|
||||
if self._revQueue:
|
||||
return True
|
||||
# nothing left in the deck; move to next
|
||||
self._newDids.pop(0)
|
||||
if not order:
|
||||
r = random.Random()
|
||||
r.seed(self.today)
|
||||
r.shuffle(self._revQueue)
|
||||
else:
|
||||
self._revQueue.reverse()
|
||||
return True
|
||||
|
||||
def _getRevCard(self):
|
||||
|
@ -505,9 +532,11 @@ did in %s and queue = 2 and due <= :lim %s limit %d""" % (
|
|||
self.revCount -= 1
|
||||
return self.col.getCard(self._revQueue.pop())
|
||||
|
||||
def _revOrder(self):
|
||||
if self.col.conf['revOrder']:
|
||||
return "order by %s" % ("ivl desc", "ivl")[self.col.conf['revOrder']-1]
|
||||
def _revOrder(self, did):
|
||||
d = self.col.decks.conf(did)
|
||||
o = d['rev']['order']
|
||||
if o:
|
||||
return "order by %s" % ("ivl desc", "ivl")[o-1]
|
||||
return ""
|
||||
|
||||
# Answering a review card
|
||||
|
|
|
@ -883,20 +883,3 @@ def test_resched():
|
|||
assert c.due == d.sched.today+1
|
||||
assert c.ivl == +1
|
||||
|
||||
def test_revlim():
|
||||
d = getEmptyDeck()
|
||||
for i in range(20):
|
||||
f = d.newNote()
|
||||
f['Front'] = str(i)
|
||||
d.addNote(f)
|
||||
d.db.execute("update cards set due = 0, queue = 2, type = 2")
|
||||
d.reset()
|
||||
assert d.sched.counts()[2] == 20
|
||||
for i in range(5):
|
||||
d.sched.answerCard(d.sched.getCard(), 3)
|
||||
assert d.sched.counts()[2] == 15
|
||||
t = d.decks.top()
|
||||
t['revLim'] = 10
|
||||
d.reset()
|
||||
assert d.sched.counts()[2] == 5
|
||||
|
||||
|
|
Loading…
Reference in a new issue