mirror of
https://github.com/ankitects/anki.git
synced 2025-11-07 21:27:14 -05:00
Rather than use a combination of id lookups on the groups table and a group configuration cache in the scheduler, I've moved the groups and group config into json objects on the deck table. This results in a net saving of code and saves one or more DB lookups on each card answer, in exchange for a small increase in deck load/save work. I did a quick survey of AnkiWeb, and the vast majority of decks use less than 100 tags, and it's safe to assume groups will follow a similar pattern. All groups and group configs except the default one will use integer timestamps now, to simplify merging when syncing and importing. defaultGroup() has been removed in favour of keeping the models up to date (not yet done).
117 lines
3.4 KiB
Python
117 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 queue = 2 and due >= %d
|
|
%s
|
|
%s order by %s limit %d""" % (self.today+1+self.min,
|
|
maxlim,
|
|
self._groupLimit(),
|
|
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)
|