Module: FsrsRuby::Strategies

Defined in:
lib/fsrs_ruby/strategies/seed.rb,
lib/fsrs_ruby/strategies/learning_steps.rb

Class Method Summary collapse

Class Method Details

.basic_learning_steps_strategy(parameters, state, cur_step) ⇒ Hash

Basic learning steps strategy

Parameters:

  • parameters (Parameters)

    FSRS parameters

  • state (Integer)

    Current state

  • cur_step (Integer)

    Current step index

Returns:

  • (Hash)

    Mapping of ratings to { scheduled_minutes:, next_step: }



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/fsrs_ruby/strategies/learning_steps.rb', line 31

def self.basic_learning_steps_strategy(parameters, state, cur_step)
  learning_steps = if [State::RELEARNING, State::REVIEW].include?(state)
                     parameters.relearning_steps
                   else
                     parameters.learning_steps
                   end

  steps_length = learning_steps.length
  return {} if steps_length.zero? || cur_step >= steps_length

  first_step = learning_steps[0]

  result = {}

  if state == State::REVIEW
    # Review → again: return first relearning step
    result[Rating::AGAIN] = {
      scheduled_minutes: convert_step_unit_to_minutes(first_step),
      next_step: 0
    }
  else
    # New, Learning, Relearning states
    result[Rating::AGAIN] = {
      scheduled_minutes: convert_step_unit_to_minutes(first_step),
      next_step: 0
    }

    # Hard interval
    hard_minutes = if steps_length == 1
                     (convert_step_unit_to_minutes(first_step) * 1.5).round
                   else
                     second_step = learning_steps[1]
                     ((convert_step_unit_to_minutes(first_step) + convert_step_unit_to_minutes(second_step)) / 2.0).round
                   end

    result[Rating::HARD] = {
      scheduled_minutes: hard_minutes,
      next_step: cur_step
    }

    # Good: advance to next step if it exists
    next_step_index = cur_step + 1
    if next_step_index < steps_length
      next_step = learning_steps[next_step_index]
      result[Rating::GOOD] = {
        scheduled_minutes: convert_step_unit_to_minutes(next_step).round,
        next_step: next_step_index
      }
    end
  end

  result
end

.convert_step_unit_to_minutes(step) ⇒ Integer

Convert step unit string to minutes

Parameters:

  • step (String)

    Step string like “1m”, “10m”, “5h”, “2d”

Returns:

  • (Integer)

    Minutes

Raises:

  • (ArgumentError)


8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/fsrs_ruby/strategies/learning_steps.rb', line 8

def self.convert_step_unit_to_minutes(step)
  unit = step[-1]
  value = step[0...-1].to_i

  raise ArgumentError, "Invalid step value: #{step}" if value < 0

  case unit
  when 'm'
    value
  when 'h'
    value * 60
  when 'd'
    value * 1440
  else
    raise ArgumentError, "Invalid step unit: #{step}, expected m/h/d"
  end
end

.default_init_seed_strategy(scheduler) ⇒ String

Default seed strategy using review time and card properties

Parameters:

  • scheduler (BaseScheduler)

    Scheduler instance

Returns:

  • (String)

    Seed string



8
9
10
11
12
13
# File 'lib/fsrs_ruby/strategies/seed.rb', line 8

def self.default_init_seed_strategy(scheduler)
  time = scheduler.review_time.to_i
  reps = scheduler.current.reps
  mul = (scheduler.current.difficulty * scheduler.current.stability).round(2)
  "#{time}_#{reps}_#{mul}"
end

.gen_seed_strategy_with_card_id(card_id_field) ⇒ Proc

Generate seed strategy with card ID field

Parameters:

  • card_id_field (String, Symbol)

    Field name for card ID

Returns:

  • (Proc)

    Seed strategy proc



18
19
20
21
22
23
24
# File 'lib/fsrs_ruby/strategies/seed.rb', line 18

def self.gen_seed_strategy_with_card_id(card_id_field)
  ->(scheduler) do
    card_id = scheduler.current.send(card_id_field)
    reps = scheduler.current.reps || 0
    "#{card_id}#{reps}"
  end
end