Class: JLDrill::Schedule
- Inherits:
-
Object
- Object
- JLDrill::Schedule
- Defined in:
- lib/jldrill/model/Quiz/Schedule.rb
Overview
Calculates and stores the Schedule information for an item in the Spaced Repetition Drill.
-
score is the number of times the item has been successfully drilled in the current bin.
-
level is 0 if meaning has not been introduced
1 if kanji has not been introduced, 2 otherwise
Constant Summary collapse
- SCORE_RE =
/^Score: (.*)/
- LEVEL_RE =
/^Level: (.*)/
- LASTREVIEWED_RE =
/^LastReviewed: (.*)/
- SCHEDULEDTIME_RE =
Note: ScheduledTime is deprecated
/^ScheduledTime: (.*)/
- DIFFICULTY_RE =
/^Difficulty: (.*)/
- DURATION_RE =
/^Duration: (.*)/
- SECONDS_PER_DAY =
60 * 60 * 24
- MAX_ADDITIONAL_TIME =
4 * SECONDS_PER_DAY
Instance Attribute Summary collapse
-
#item ⇒ Object
Note: ScheduledTime is deprecated.
-
#lastReviewed ⇒ Object
Note: ScheduledTime is deprecated.
-
#level ⇒ Object
Note: ScheduledTime is deprecated.
-
#name ⇒ Object
readonly
Note: ScheduledTime is deprecated.
-
#numIncorrect ⇒ Object
Note: ScheduledTime is deprecated.
-
#scheduledTime ⇒ Object
Note: ScheduledTime is deprecated.
-
#score ⇒ Object
Note: ScheduledTime is deprecated.
-
#seen ⇒ Object
Note: ScheduledTime is deprecated.
Class Method Summary collapse
-
.backoff(interval) ⇒ Object
Return the the new interval after backing off.
Instance Method Summary collapse
-
#assign(schedule) ⇒ Object
copy the data from the Schedule passed in to this one Note: Doesn’t assign the item.
-
#calculateInterval ⇒ Object
To avoid increasing the gap too much, a maximum of twice the previous duration plus 25% is used.
-
#clone ⇒ Object
Create a clone of this schedule.
-
#correct ⇒ Object
Mark the item as correct.
-
#demote ⇒ Object
Unschedule and reset the level and score of the item.
-
#difficulty ⇒ Object
Return the difficulty of the item.
-
#difficultyFromInterval(interval) ⇒ Object
Calculate the difficulty from the interval.
- #duration ⇒ Object
- #duration=(seconds) ⇒ Object
-
#durationWithin?(range) ⇒ Boolean
Returns true if the scheduled duration is in the range of times supplied.
-
#elapsedTime ⇒ Object
Returns the number of seconds since the item was last reviewed.
-
#incorrect ⇒ Object
Mark the item as incorrect.
-
#initialize(item) ⇒ Schedule
constructor
A new instance of Schedule.
-
#intervalFromDifficulty(diff) ⇒ Object
This is the interval the item will have when it it first promoted into the Review Set.
-
#markReviewed ⇒ Object
Updates the time that the item was last reviewed to be the real current time.
-
#maxInterval ⇒ Object
Return the maximum interval that this item can have.
-
#onDay?(current, date, day) ⇒ Boolean
Returns true if the date is on the specified day.
-
#parse(string) ⇒ Object
Parses a single part of the Schedule information.
-
#potentialScheduleInDays ⇒ Object
Returns the total number of days the item was last scheduled for.
-
#randomVariation(interval) ⇒ Object
Returns a +-10% random variation in the interval.
- #recalculateDifficulty ⇒ Object
-
#reset ⇒ Object
Resets the schedule.
-
#reviewed? ⇒ Boolean
Returns true if the item has been marked reviewed at least once.
-
#reviewedDate ⇒ Object
Returns a human readable string showing when the item was last reviewed.
-
#reviewedOn?(day) ⇒ Boolean
Returns true if the item was reviewed on the specified day.
-
#reviewLoad ⇒ Object
This is simply 1/reviewRate.
-
#reviewRate ⇒ Object
Returns the “velocity” for reviewing.
-
#schedule(int = -1)) ⇒ Object
Schedule the item for review.
-
#scheduled? ⇒ Boolean
Returns true if the item has been scheduled for review.
-
#scheduleDuration ⇒ Object
Return the duration of the schedule Old quizes might not have the duration stored, so it is calculated from the scheduledTime.
-
#secondsToDays(seconds) ⇒ Object
Converts seconds to days rounded to the nearest 10th of a day.
-
#seen? ⇒ Boolean
Returns true if the item has been seen before.
-
#to_s ⇒ Object
Outputs the item schedule in save format.
-
#unschedule ⇒ Object
Remove review schedule for the item.
Constructor Details
#initialize(item) ⇒ Schedule
Returns a new instance of Schedule.
35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 35 def initialize(item) @name = "Schedule" @score = 0 @level = 0 @lastReviewed = nil # scheduledTime is deprecated @scheduledTime = nil @seen = false @numIncorrect = 0 @item = item @duration = Duration.new end |
Instance Attribute Details
#item ⇒ Object
Note: ScheduledTime is deprecated
27 28 29 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 27 def item @item end |
#lastReviewed ⇒ Object
Note: ScheduledTime is deprecated
27 28 29 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 27 def lastReviewed @lastReviewed end |
#level ⇒ Object
Note: ScheduledTime is deprecated
27 28 29 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 27 def level @level end |
#name ⇒ Object (readonly)
Note: ScheduledTime is deprecated
27 28 29 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 27 def name @name end |
#numIncorrect ⇒ Object
Note: ScheduledTime is deprecated
27 28 29 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 27 def numIncorrect @numIncorrect end |
#scheduledTime ⇒ Object
Note: ScheduledTime is deprecated
27 28 29 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 27 def scheduledTime @scheduledTime end |
#score ⇒ Object
Note: ScheduledTime is deprecated
27 28 29 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 27 def score @score end |
#seen ⇒ Object
Note: ScheduledTime is deprecated
27 28 29 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 27 def seen @seen end |
Class Method Details
.backoff(interval) ⇒ Object
Return the the new interval after backing off
184 185 186 187 188 189 190 191 192 193 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 184 def Schedule.backoff(interval) sixMonths = Duration.new sixMonths.days = 180 if(interval < sixMonths.seconds) factor = 2.0 - (interval.to_f / sixMonths.seconds.to_f) return (factor * interval).to_i else return (interval).to_i end end |
Instance Method Details
#assign(schedule) ⇒ Object
copy the data from the Schedule passed in to this one Note: Doesn’t assign the item
82 83 84 85 86 87 88 89 90 91 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 82 def assign(schedule) @score = schedule.score @level = schedule.level @lastReviewed = schedule.lastReviewed # scheduledTime is deprecated @scheduledTime = schedule.scheduledTime @seen = schedule.seen @numIncorrect = schedule.numIncorrect @duration.seconds = schedule.duration end |
#calculateInterval ⇒ Object
To avoid increasing the gap too much, a maximum of twice the previous duration plus 25% is used.
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 213 def calculateInterval interval = intervalFromDifficulty(difficulty) # If it is scheduled, then that means it isn't # a newly promoted item if scheduled? elapsed = elapsedTime if Schedule.backoff(elapsed) > @duration.seconds interval = Schedule.backoff(elapsed) max = maxInterval if (interval > max) && (max > 0) interval = max end else interval = @duration.seconds end end interval end |
#clone ⇒ Object
Create a clone of this schedule
74 75 76 77 78 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 74 def clone retVal = Schedule.new(@item) retVal.assign(self) return retVal end |
#correct ⇒ Object
Mark the item as correct.
283 284 285 286 287 288 289 290 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 283 def correct if @item.bin == 4 recalculateDifficulty schedule end markReviewed @score += 1 end |
#demote ⇒ Object
Unschedule and reset the level and score of the item
262 263 264 265 266 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 262 def demote unschedule @score = 0 @level = 0 end |
#difficulty ⇒ Object
Return the difficulty of the item. Right now that is the number of times it was incorrect.
270 271 272 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 270 def difficulty @numIncorrect end |
#difficultyFromInterval(interval) ⇒ Object
Calculate the difficulty from the interval. This is used to reset the difficulty of an item based on past performance.
170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 170 def difficultyFromInterval(interval) # to deal with corrupt files where the review times are screwed up if interval <= 0 return 50 end i = 0 while interval < intervalFromDifficulty(i) i += 1 end return i end |
#duration ⇒ Object
97 98 99 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 97 def duration return @duration.seconds end |
#duration=(seconds) ⇒ Object
93 94 95 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 93 def duration=(seconds) @duration.seconds = seconds end |
#durationWithin?(range) ⇒ Boolean
Returns true if the scheduled duration is in the range of times supplied. The range is of the form of number of seconds from the epoch
349 350 351 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 349 def durationWithin?(range) range.include?(scheduleDuration) end |
#elapsedTime ⇒ Object
Returns the number of seconds since the item was last reviewed
114 115 116 117 118 119 120 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 114 def elapsedTime retVal = 0 if reviewed? retVal = Time::now().to_i - @lastReviewed.to_i end return retVal end |
#incorrect ⇒ Object
Mark the item as incorrect.
275 276 277 278 279 280 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 275 def incorrect @numIncorrect += 1 unschedule markReviewed @score = 0 end |
#intervalFromDifficulty(diff) ⇒ Object
This is the interval the item will have when it it first promoted into the Review Set.
It is a sliding scale based on difficulty. If the user has never gotten the item incorrect, then the interval will be 5.0. For each time the get it wrong, it moves closer to 0.
154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 154 def intervalFromDifficulty(diff) if diff <= 5 SECONDS_PER_DAY + (MAX_ADDITIONAL_TIME * (1.0 - (diff.to_f / 5.0))).to_i else scale = diff - 5 current = 0.0 1.upto(scale) do |x| current = current + (1 - current).to_f / 10.0 end (SECONDS_PER_DAY * (1.0 - current)).to_i end end |
#markReviewed ⇒ Object
Updates the time that the item was last reviewed to be the real current time. Returns the time that it set.
104 105 106 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 104 def markReviewed @lastReviewed = Time::now() end |
#maxInterval ⇒ Object
Return the maximum interval that this item can have. It is calculated as twice the previous duration plus 25% It will return -1 if there is no maximum
198 199 200 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 198 def maxInterval return Schedule.backoff(@duration.seconds.to_f * 1.25) end |
#onDay?(current, date, day) ⇒ Boolean
Returns true if the date is on the specified day. 0 is today, -1 is yesterday, 1 is tomorrow. Uses the date, not 24 hour time period.
327 328 329 330 331 332 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 327 def onDay?(current, date, day) target = current + (SECONDS_PER_DAY * day) return date.day == target.day && date.month == target.month && date.year == target.year end |
#parse(string) ⇒ Object
Parses a single part of the Schedule information
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 49 def parse(string) parsed = true case string when SCORE_RE @score = $1.to_i when LEVEL_RE @level = $1.to_i when LASTREVIEWED_RE @lastReviewed = Time.at($1.to_i) when SCHEDULEDTIME_RE # scheduledTime is deprecated if @item.bin == 4 @scheduledTime = Time.at($1.to_i) end when DIFFICULTY_RE @numIncorrect = $1.to_i when DURATION_RE @duration = Duration.parse($1) else # Not something we understand parsed = false end parsed end |
#potentialScheduleInDays ⇒ Object
Returns the total number of days the item was last scheduled for. Returns a float.
304 305 306 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 304 def potentialScheduleInDays return secondsToDays(calculateInterval.to_i) end |
#randomVariation(interval) ⇒ Object
Returns a +-10% random variation in the interval. This smooths out the distribution of items and makes it so that similar items aren’t always together.
142 143 144 145 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 142 def randomVariation(interval) # 10% - rand(20%) = +- 10% ((interval.to_f / 10) - rand(interval.to_f / 5)).to_i end |
#recalculateDifficulty ⇒ Object
232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 232 def recalculateDifficulty # If it's scheduled, then it isn't a newly promoted item # Set the difficulty based on how long the person was # able to go since the last review. if scheduled? elapsed = elapsedTime diff = difficultyFromInterval(elapsed) if diff < @numIncorrect @numIncorrect = diff end end end |
#reset ⇒ Object
Resets the schedule
123 124 125 126 127 128 129 130 131 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 123 def reset @lastReviewed = nil # scheduledTime is deprecated @scheduledTime = nil @score = 0 @seen = false @numIncorrect = 0 @duration = Duration.new end |
#reviewed? ⇒ Boolean
Returns true if the item has been marked reviewed at least once
109 110 111 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 109 def reviewed? !@lastReviewed.nil? end |
#reviewedDate ⇒ Object
Returns a human readable string showing when the item was last reviewed.
355 356 357 358 359 360 361 362 363 364 365 366 367 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 355 def reviewedDate retVal = "" if reviewed? if reviewedOn?(0) retVal = "Today" elsif reviewedOn?(-1) retVal = "Yesterday" else retVal = @lastReviewed.strftime("%x") end end retVal end |
#reviewedOn?(day) ⇒ Boolean
Returns true if the item was reviewed on the specified day. 0 is today, -1 is yesterday, -2 is the day before, etc. Uses the date, not 24 hour time period (i.e., if it’s 1am, then an item reviewed 2 hours ago is yesterday).
338 339 340 341 342 343 344 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 338 def reviewedOn?(day) if !reviewed? return false else return onDay?(Time::now(), @lastReviewed, day) end end |
#reviewLoad ⇒ Object
This is simply 1/reviewRate. It is used to sort the schedules since we want the smalled reviewRates at the end of the list.
385 386 387 388 389 390 391 392 393 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 385 def reviewLoad retVal = 1.0 sched = scheduleDuration.to_f time = elapsedTime.to_f if time != 0.0 retVal = sched / time end retVal end |
#reviewRate ⇒ Object
Returns the “velocity” for reviewing. It shows the ratio of the actual time between review vs. scheduled time. Values greater than 1 mean it is taking longer than expected, values less than 1 mean it is taking less time than expected.
373 374 375 376 377 378 379 380 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 373 def reviewRate retVal = 1.0 dur = scheduleDuration if dur != 0 retVal = elapsedTime.to_f / dur.to_f end retVal end |
#schedule(int = -1)) ⇒ Object
Schedule the item for review
246 247 248 249 250 251 252 253 254 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 246 def schedule(int = -1) if int < 0 interval = calculateInterval @duration.seconds = interval + randomVariation(interval) else @duration.seconds = int end return @duration.seconds end |
#scheduled? ⇒ Boolean
Returns true if the item has been scheduled for review
134 135 136 137 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 134 def scheduled? # scheduledTime is deprecated (@duration.valid?) || (!@scheduledTime.nil?) end |
#scheduleDuration ⇒ Object
Return the duration of the schedule Old quizes might not have the duration stored, so it is calculated from the scheduledTime. scheduledTime is now deprecated, though.
312 313 314 315 316 317 318 319 320 321 322 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 312 def scheduleDuration retVal = -1 if scheduled? if (!@duration.valid?) && !@scheduledTime.nil? retVal = @scheduledTime.to_i - @lastReviewed.to_i else retVal = @duration.seconds end end return retVal end |
#secondsToDays(seconds) ⇒ Object
Converts seconds to days rounded to the nearest 10th of a day
298 299 300 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 298 def secondsToDays(seconds) return (seconds * 10 / SECONDS_PER_DAY).to_f / 10 end |
#seen? ⇒ Boolean
Returns true if the item has been seen before.
293 294 295 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 293 def seen? @seen end |
#to_s ⇒ Object
Outputs the item schedule in save format.
396 397 398 399 400 401 402 403 404 405 406 |
# File 'lib/jldrill/model/Quiz/Schedule.rb', line 396 def to_s retVal = "/Score: #{@score}" + "/Level: #{@level}" if reviewed? retVal += "/LastReviewed: #{@lastReviewed.to_i}" end if scheduled? retVal += "/Duration: #{scheduleDuration.to_i}" end retVal += "/Difficulty: #{difficulty}" retVal end |