mirror of
https://github.com/ankitects/anki.git
synced 2025-09-20 15:02:21 -04:00
add alternative failed card handling
This commit is contained in:
parent
2b9344d87c
commit
8ec77ebd53
1 changed files with 102 additions and 94 deletions
196
anki/deck.py
196
anki/deck.py
|
@ -34,7 +34,6 @@ PRIORITY_NORM = 2
|
|||
PRIORITY_LOW = 1
|
||||
PRIORITY_NONE = 0
|
||||
MATURE_THRESHOLD = 21
|
||||
NEW_INTERVAL = 0
|
||||
NEW_CARDS_LAST = 1
|
||||
NEW_CARDS_DISTRIBUTE = 0
|
||||
|
||||
|
@ -45,7 +44,7 @@ decksTable = Table(
|
|||
Column('created', Float, nullable=False, default=time.time),
|
||||
Column('modified', Float, nullable=False, default=time.time),
|
||||
Column('description', UnicodeText, nullable=False, default=u""),
|
||||
Column('version', Integer, nullable=False, default=14),
|
||||
Column('version', Integer, nullable=False, default=15),
|
||||
Column('currentModelId', Integer, ForeignKey("models.id")),
|
||||
# syncing
|
||||
Column('syncName', UnicodeText),
|
||||
|
@ -61,8 +60,8 @@ decksTable = Table(
|
|||
Column('easyIntervalMax', Float, nullable=False, default=9.0),
|
||||
# delays on failure
|
||||
Column('delay0', Integer, nullable=False, default=600),
|
||||
Column('delay1', Integer, nullable=False, default=600),
|
||||
Column('delay2', Integer, nullable=False, default=28800),
|
||||
Column('delay1', Integer, nullable=False, default=0),
|
||||
Column('delay2', Float, nullable=False, default=0),
|
||||
# collapsing future cards
|
||||
Column('collapseTime', Integer, nullable=False, default=1),
|
||||
# priorities & postponing
|
||||
|
@ -323,6 +322,101 @@ where id != :id and factId = :factId""",
|
|||
entry.writeSQL(self.s)
|
||||
self.modified = now
|
||||
|
||||
# Interval management
|
||||
##########################################################################
|
||||
|
||||
def nextInterval(self, card, ease):
|
||||
"Return the next interval for CARD given EASE."
|
||||
delay = self._adjustedDelay(card, ease)
|
||||
return self._nextInterval(card.interval, card.factor, delay, ease)
|
||||
|
||||
def _nextInterval(self, interval, factor, delay, ease):
|
||||
# if interval is less than mid interval, use presets
|
||||
if ease == 1:
|
||||
interval *= self.delay2
|
||||
if interval < self.hardIntervalMin:
|
||||
interval = 0
|
||||
elif interval == 0:
|
||||
if ease == 2:
|
||||
interval = random.uniform(self.hardIntervalMin,
|
||||
self.hardIntervalMax)
|
||||
elif ease == 3:
|
||||
interval = random.uniform(self.midIntervalMin,
|
||||
self.midIntervalMax)
|
||||
elif ease == 4:
|
||||
interval = random.uniform(self.easyIntervalMin,
|
||||
self.easyIntervalMax)
|
||||
else:
|
||||
# if not cramming, boost initial 2
|
||||
if (interval < self.hardIntervalMax and
|
||||
interval > 0.166):
|
||||
interval = self.hardIntervalMax * 3.5
|
||||
# multiply last interval by factor
|
||||
if ease == 2:
|
||||
interval = (interval + delay/4) * 1.2
|
||||
elif ease == 3:
|
||||
interval = (interval + delay/2) * factor
|
||||
elif ease == 4:
|
||||
interval = (interval + delay) * factor * self.factorFour
|
||||
fuzz = random.uniform(0.95, 1.05)
|
||||
interval *= fuzz
|
||||
if self.maxScheduleTime:
|
||||
interval = min(interval, self.maxScheduleTime)
|
||||
return interval
|
||||
|
||||
def nextIntervalStr(self, card, ease, short=False):
|
||||
"Return the next interval for CARD given EASE as a string."
|
||||
int = self.nextInterval(card, ease)
|
||||
return anki.utils.fmtTimeSpan(int*86400, short=short)
|
||||
|
||||
def nextDue(self, card, ease, oldState):
|
||||
"Return time when CARD will expire given EASE."
|
||||
if ease == 1:
|
||||
if oldState == "mature":
|
||||
due = self.delay1
|
||||
else:
|
||||
due = self.delay0
|
||||
else:
|
||||
due = card.interval * 86400.0
|
||||
return due + time.time()
|
||||
|
||||
def updateFactor(self, card, ease):
|
||||
"Update CARD's factor based on EASE."
|
||||
card.lastFactor = card.factor
|
||||
if not card.reps:
|
||||
# card is new, inherit beginning factor
|
||||
card.factor = self.averageFactor
|
||||
if self.cardIsBeingLearnt(card) and ease in [0, 1, 2]:
|
||||
# only penalize failures after success when starting
|
||||
if card.successive and ease != 2:
|
||||
card.factor -= 0.20
|
||||
elif ease in [0, 1]:
|
||||
card.factor -= 0.20
|
||||
elif ease == 2:
|
||||
card.factor -= 0.15
|
||||
elif ease == 4:
|
||||
card.factor += 0.10
|
||||
card.factor = max(1.3, card.factor)
|
||||
|
||||
def _adjustedDelay(self, card, ease):
|
||||
"Return an adjusted delay value for CARD based on EASE."
|
||||
if self.cardIsNew(card):
|
||||
return 0
|
||||
return max(0, (time.time() - card.due) / 86400.0)
|
||||
|
||||
def resetCards(self, ids):
|
||||
"Reset progress on cards in IDS."
|
||||
self.s.statement("""
|
||||
update cards set interval = :new, lastInterval = 0, lastDue = 0,
|
||||
factor = 2.5, reps = 0, successive = 0, averageTime = 0, reviewTime = 0,
|
||||
youngEase0 = 0, youngEase1 = 0, youngEase2 = 0, youngEase3 = 0,
|
||||
youngEase4 = 0, matureEase0 = 0, matureEase1 = 0, matureEase2 = 0,
|
||||
matureEase3 = 0,matureEase4 = 0, yesCount = 0, noCount = 0,
|
||||
spaceUntil = 0, isDue = 0, type = 2,
|
||||
combinedDue = created, modified = :now, due = created
|
||||
where id in %s""" % ids2str(ids), now=time.time(), new=0)
|
||||
self.flushMod()
|
||||
|
||||
# Queue/cache management
|
||||
##########################################################################
|
||||
|
||||
|
@ -411,96 +505,6 @@ strftime("%s", "now")+1 from decks)"""))
|
|||
if genToday(self) != self._dailyStats.day:
|
||||
self._dailyStats = dailyStats(self)
|
||||
|
||||
# Interval management
|
||||
##########################################################################
|
||||
|
||||
def nextInterval(self, card, ease):
|
||||
"Return the next interval for CARD given EASE."
|
||||
delay = self._adjustedDelay(card, ease)
|
||||
return self._nextInterval(card.interval, card.factor, delay, ease)
|
||||
|
||||
def _nextInterval(self, interval, factor, delay, ease):
|
||||
# if interval is less than mid interval, use presets
|
||||
if ease == 1:
|
||||
interval = NEW_INTERVAL
|
||||
elif interval == 0:
|
||||
if ease == 2:
|
||||
interval = random.uniform(self.hardIntervalMin,
|
||||
self.hardIntervalMax)
|
||||
elif ease == 3:
|
||||
interval = random.uniform(self.midIntervalMin,
|
||||
self.midIntervalMax)
|
||||
elif ease == 4:
|
||||
interval = random.uniform(self.easyIntervalMin,
|
||||
self.easyIntervalMax)
|
||||
else:
|
||||
# if not cramming, boost initial 2
|
||||
if (interval < self.hardIntervalMax and
|
||||
interval > 0.166):
|
||||
interval = self.hardIntervalMax * 3.5
|
||||
# multiply last interval by factor
|
||||
if ease == 2:
|
||||
interval = (interval + delay/4) * 1.2
|
||||
elif ease == 3:
|
||||
interval = (interval + delay/2) * factor
|
||||
elif ease == 4:
|
||||
interval = (interval + delay) * factor * self.factorFour
|
||||
fuzz = random.uniform(0.95, 1.05)
|
||||
interval *= fuzz
|
||||
if self.maxScheduleTime:
|
||||
interval = min(interval, self.maxScheduleTime)
|
||||
return interval
|
||||
|
||||
def nextIntervalStr(self, card, ease, short=False):
|
||||
"Return the next interval for CARD given EASE as a string."
|
||||
int = self.nextInterval(card, ease)
|
||||
return anki.utils.fmtTimeSpan(int*86400, short=short)
|
||||
|
||||
def nextDue(self, card, ease, oldState):
|
||||
"Return time when CARD will expire given EASE."
|
||||
if ease == 1:
|
||||
due = self.delay0
|
||||
else:
|
||||
due = card.interval * 86400.0
|
||||
return due + time.time()
|
||||
|
||||
def updateFactor(self, card, ease):
|
||||
"Update CARD's factor based on EASE."
|
||||
card.lastFactor = card.factor
|
||||
if not card.reps:
|
||||
# card is new, inherit beginning factor
|
||||
card.factor = self.averageFactor
|
||||
if self.cardIsBeingLearnt(card) and ease in [0, 1, 2]:
|
||||
# only penalize failures after success when starting
|
||||
if card.successive and ease != 2:
|
||||
card.factor -= 0.20
|
||||
elif ease in [0, 1]:
|
||||
card.factor -= 0.20
|
||||
elif ease == 2:
|
||||
card.factor -= 0.15
|
||||
elif ease == 4:
|
||||
card.factor += 0.10
|
||||
card.factor = max(1.3, card.factor)
|
||||
|
||||
def _adjustedDelay(self, card, ease):
|
||||
"Return an adjusted delay value for CARD based on EASE."
|
||||
if self.cardIsNew(card):
|
||||
return 0
|
||||
return max(0, (time.time() - card.due) / 86400.0)
|
||||
|
||||
def resetCards(self, ids):
|
||||
"Reset progress on cards in IDS."
|
||||
self.s.statement("""
|
||||
update cards set interval = :new, lastInterval = 0, lastDue = 0,
|
||||
factor = 2.5, reps = 0, successive = 0, averageTime = 0, reviewTime = 0,
|
||||
youngEase0 = 0, youngEase1 = 0, youngEase2 = 0, youngEase3 = 0,
|
||||
youngEase4 = 0, matureEase0 = 0, matureEase1 = 0, matureEase2 = 0,
|
||||
matureEase3 = 0,matureEase4 = 0, yesCount = 0, noCount = 0,
|
||||
spaceUntil = 0, isDue = 0, type = 2,
|
||||
combinedDue = created, modified = :now, due = created
|
||||
where id in %s""" % ids2str(ids), now=time.time(), new=NEW_INTERVAL)
|
||||
self.flushMod()
|
||||
|
||||
# Times
|
||||
##########################################################################
|
||||
|
||||
|
@ -1919,6 +1923,10 @@ alter table models add column source integer not null default 0""")
|
|||
update cards set interval = 0
|
||||
where interval < 1""")
|
||||
deck.version = 14
|
||||
if deck.version < 15:
|
||||
deck.delay1 = deck.delay0
|
||||
deck.delay2 = 0
|
||||
deck.version = 15
|
||||
deck.s.commit()
|
||||
return deck
|
||||
_upgradeDeck = staticmethod(_upgradeDeck)
|
||||
|
|
Loading…
Reference in a new issue