1# 2# cramming.py <Peter.Bienstman@UGent.be> 3# 4 5from mnemosyne.libmnemosyne.schedulers.SM2_mnemosyne import SM2Mnemosyne 6 7RANDOM = 0 8EARLIEST_FIRST = 1 9LATEST_FIRST = 2 10MOST_LAPSES_FIRST = 3 11 12 13class Cramming(SM2Mnemosyne): 14 15 UNSEEN = 0 16 WRONG = 1 17 RIGHT = 2 18 19 name = "cramming" 20 21 def __init__(self, component_manager): 22 SM2Mnemosyne.__init__(self, component_manager) 23 self.first_run = True 24 25 def reset(self, new_only=False): 26 if self.first_run and self.config()["cramming_store_state"] == False: 27 self.database().set_scheduler_data(self.UNSEEN) 28 self.first_run = False 29 SM2Mnemosyne.reset(self, new_only) 30 31 def rebuild_queue(self, learn_ahead=False): 32 db = self.database() 33 if not db.is_loaded() or not db.active_count(): 34 return 35 max_ret_reps = 1 if self.new_only else -1 # TODO: make configurable 36 if self.new_only and db.recently_memorised_count(max_ret_reps) == 0: 37 return 38 self._card_ids_in_queue = [] 39 self._fact_ids_in_queue = [] 40 self.criterion = db.current_criterion() 41 # Determine sort key. 42 if self.config()["cramming_order"] == RANDOM: 43 sort_key = "random" 44 elif self.config()["cramming_order"] == EARLIEST_FIRST: 45 sort_key = "next_rep" 46 elif self.config()["cramming_order"] == LATEST_FIRST: 47 sort_key = "next_rep desc" 48 elif self.config()["cramming_order"] == MOST_LAPSES_FIRST: 49 sort_key = "lapses desc" 50 # Stage 1: do all the unseen cards. 51 if self.stage == 1: 52 for _card_id, _fact_id in db.cards_with_scheduler_data(self.UNSEEN, 53 sort_key=sort_key, limit=25, max_ret_reps=max_ret_reps): 54 if _fact_id not in self._fact_ids_in_queue: 55 self._card_ids_in_queue.append(_card_id) 56 self._fact_ids_in_queue.append(_fact_id) 57 if len(self._card_ids_in_queue): 58 return 59 self.stage = 2 60 # Stage 2: do the cards we got wrong. 61 if self.stage == 2: 62 for _card_id, _fact_id in db.cards_with_scheduler_data(self.WRONG, 63 sort_key=sort_key, limit=25, max_ret_reps=max_ret_reps): 64 if _fact_id not in self._fact_ids_in_queue: 65 self._card_ids_in_queue.append(_card_id) 66 self._fact_ids_in_queue.append(_fact_id) 67 if len(self._card_ids_in_queue): 68 return 69 # Start again. 70 self.database().set_scheduler_data(self.UNSEEN) 71 self.stage = 1 72 self.rebuild_queue() 73 74 def grade_answer(self, card, new_grade, dry_run=False): 75 # The dry run mode is typically used to determine the intervals 76 # for the different grades, so we don't want any side effects 77 # from hooks running then. 78 if not dry_run: 79 for f in self.component_manager.all("hook", "before_repetition"): 80 f.run(card) 81 # Do the actual grading. 82 if new_grade <= 1: 83 card.scheduler_data = self.WRONG 84 else: 85 card.scheduler_data = self.RIGHT 86 # Run hooks. 87 self.criterion.apply_to_card(card) 88 for f in self.component_manager.all("hook", "after_repetition"): 89 f.run(card) 90 return 0