Anki/anki/cram.py
Damien Elmes 024c42fef8 group scheduling refactor
see the following for background discussion:
http://groups.google.com/group/ankisrs-users/browse_thread/thread/4db5e82f7dff74fb

- change sched index to the more efficient gid, queue, due
- drop the dynamic index support. as there's no no q/a cache anymore, it's
  cheap enough to hit the cards table directly, and we can't use the index in
  its new form.
- drop order by clauses (see todo)
- ensure there's always an active group. if users want to study all groups at
  once, they need to create a top level group. we do this because otherwise
  the 'top level group' that's active when everything is selected is not
  clear.

to do:

- new cards will appear in gid order, but the gid numbers don't reflect
  alphabetical sorting. we need to change the scheduling code so that it steps
  through each group in turn
- likewise for the learn queue
2011-09-22 11:54:01 +09:00

116 lines
3.4 KiB
Python

# -*- coding: utf-8 -*-
# Copyright: Damien Elmes <anki@ichi2.net>
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from anki.utils import ids2str, intTime
from anki.sched import Scheduler
# fixme: set log type for cram
class CramScheduler(Scheduler):
name = "cram"
def __init__(self, deck, order, min=0, max=None):
Scheduler.__init__(self, deck)
# should be the opposite order of what you want
self.order = order
# days to limit cram to, where tomorrow=0. Max is inclusive.
self.min = min
self.max = max
self.reset()
def counts(self):
return (self.newCount, self.lrnCount, 0)
def reset(self):
self._updateCutoff()
self._resetLrnCount()
self._resetLrn()
self._resetNew()
self._resetRev()
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")
if ease == 1:
conf = self._lrnConf(card)
if conf['reset']:
# reset interval
card.ivl = max(1, int(card.ivl * conf['mult']))
# mark card as due today so that it doesn't get rescheduled
card.due = card.edue = self.today
card.mod = intTime()
card.flushSched()
def countIdx(self, card):
if card.queue == 2:
return 0
else:
return 1
def answerButtons(self, card):
return 3
# Fetching
##########################################################################
def _resetNew(self):
"All review cards that are not due yet."
if self.max is not None:
maxlim = "and due <= %d" % (self.today+1+self.max)
else:
maxlim = ""
self.newQueue = self.deck.db.list("""
select id from cards where gid in %s and queue = 2 and due >= %d
%s order by %s limit %d""" % (self._groupLimit(),
self.today+1+self.min,
maxlim,
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)
ivl = self._graduatingIvl(card, conf, early)
card.due = self.today + ivl
# temporarily suspend it
self.deck.setDirty()
card.queue = -3
def _graduatingIvl(self, card, conf, early):
if conf['resched']:
# shift card by the time it was delayed
return card.ivl - card.edue - self.today
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)