#ifndef MNEMON_H_INCLUDED
#define MNEMON_H_INCLUDED
-typedef struct _bin bin_t;
-typedef struct _category category_t;
+#define unused(foo) foo __attribute__((unused))
+
+typedef int bool_t;
+
+typedef struct _item {
+ int score;
+ char *challenge;
+ char *response;
+} item_t;
+
+typedef struct _bin {
+ int score;
+ unsigned int items_size;
+ unsigned int num_items;
+ item_t **items;
+} bin_t;
+
+typedef enum {
+ CATEGORY_ORDER_RANDOM,
+ CATEGORY_ORDER_SEQUENTIAL
+} category_order_t;
+
+typedef struct _category {
+ char *name;
+ unsigned int items_size;
+ unsigned int num_items;
+ item_t *items;
+
+ /* Support sequential introduction of items from bin 0 */
+ category_order_t order;
+ /* Support categories where responses are timed (0.0 == disable). */
+ double time_limit;
+ unsigned int bin_zero_head;
+ /* Support challenges of non-text types (image, audio, etc.) */
+ char *challenge_type;
+ /* Whether to repeat afterwards (for a little extra reinforcement) */
+ bool_t repeat;
+} category_t;
typedef struct _mnemon {
char *dir_name;
- int categories_size;
- int num_categories;
+ unsigned int categories_size;
+ unsigned int num_categories;
category_t *categories;
- int bins_size;
- int num_bins;
+ unsigned int bins_size;
+ unsigned int num_bins;
bin_t *bins;
-
- int to_introduce;
- int to_master;
- int unlearned;
- int mastered;
} mnemon_t;
/* Initialize a new mnemon object. This function must be called before
void
mnemon_load (mnemon_t *mnemon);
-/* Run a series of memory challenges acoording to the to_introduce and
- * to_master counters as set on the given mnemon object.
+/* Select the next (weighted) random item to challenge the user.
*
- * The challenge system is designed to rapidly reinforce items needing
+ * This function provides four return values (and yes, that's
+ * exceedingly awkward and a simpler interface should be designed to
+ * replace this):
+ *
+ * bin: The bin from which the item was selected
+ *
+ * item_index: The index within the bin of the slected item
+ *
+ * category: The name of the category for this item
+ *
+ * introduced: A flag indicating whether this is a newly
+ * introduced item. Items from bin 0 always count
+ * as newly introduced. If there is no bin 0,
+ * then items from the lowest non-negative bin
+ * will be flagged as introduced.
+ *
+ * The selection system is designed to rapidly reinforce items needing
* to be learned and provide exponentially less reinforcement for
* items as mastery is displayed. This is achieved by storing the
- * items in a series of numberred bins.
+ * items in a series of numbered bins.
*
* Items start in bin 0 indicating that they have never been presented
* to a user. When an item is presented to the user and answered
* number is the most likely to be chosen, while each succesively-
* higher-numbered bin has a probability one-half of that of the
* previous bin.
+ */
+void
+mnemon_select_item (mnemon_t *mnemon,
+ bin_t **bin_ret,
+ int *item_index_ret,
+ category_t **category_ret,
+ int *introduced_ret);
+
+/* Update an item based on a user's answer (correct or incorrect).
+ *
+ * The bin and item_index should be exactly as returned by
+ * mnemon_select_item. The correct flag should indicate whether the
+ * user answered the challenge correctly or not, (and should only
+ * count as correct if the answer was within the time limit, if any).
+ *
+ * The item will be moved from its current bin to a new bin based on
+ * whether the challenge was answered correctly. The bin updates are
+ * as follows:
+ *
+ * If the answer was correct:
+ * Increase the bin number by 1
+ * If the new bin number is 0, set it to 1 (0 bin is for new items)
+ *
+ * If the answer was incorrect:
+ * If the old bin was positive, move to bin -2 (for extra training)
+ * Otherwise decrease the bin number by 1
*
- * A session of challenges consists of three phases, some of which may
- * be entirely empty, as follows:
- *
- * 1. The introduction phase
- *
- * This phase is controlled by the to_introduce counter which is
- * by default set to 10. It is decremented every time an item is
- * introduced from the bin with score 0, or (if there is no bin
- * with score 0), every time an item is introduced from the bin
- * with the lowest non-negative score of any bin.
- *
- * 2. The mastering phase
- *
- * This phase is controlled by the to_master counter which is
- * initially set to 10. It begins at the beginning of the session
- * so can run concurrently with the introduction phase. The
- * to_master counter is decremented every time an item with a
- * positive (non-zero) score is answered correctly. It is also
- * incremented every time an item with a positive (non-zero) score
- * is answered incorrectly during the introduction phase. If
- * perfect mastery is demonstrated, the mastering phase is likely
- * to be complete simultaneous with the introduction stage. If the
- * user is really struggling with mastery, the mastering phase
- * will extend long after the introduction phase is over. But
- * since we never incremeent to_master after the introduction
- * phase is over, the user cannot build an infinite snowball of
- * to_master items and have to give up in despair.
- *
- * 3. The solidifying phase
- *
- * This final phase continues after the mastering phase for as
- * long as any items with a negative score remain. The idea here
- * is that we want to quickly give the reinforcement from a missed
- * item in the current session. Also, there's a bit of a challenge
- * to the user to demonstrate good mastery of any non-negative
- * items presented so that the phase actually terminates. It's
- * possible for this phase to extend for an arbitrary amount of
- * time, but not very likely, (since the negative items are chosen
- * preferentially and the user will continue to see the correct
- * answers to them over and over).
- *
- * This function returns after all three phases are complete.
- *
- * The user's progress (the movement of items to various new bins) is
- * kept only in memory. In order to save this progress to disk, the
- * caller must call mnemon_save.
+ * Note: All item and bin movement is kept only in memory. In order to
+ * save this progress to disk, the caller must call mnemon_save.
*/
void
-mnemon_do_challenges (mnemon_t *mnemon);
+mnemon_score_item (mnemon_t *mnemon,
+ bin_t *bin,
+ unsigned int item_index,
+ bool_t correct);
/* Save the user's progress by updating the category files in the
* users .mnemon directory. */
void
mnemon_save (mnemon_t *mnemon);
-/* Print a histogram showing the number of items in each bin.
+/* Remove a bin of a particular number.
*
- * If category_name is not NULL, then only the items from the given
- * category (matching a particular filename within the user's .mnemon
- * directory) will be shown.
- *
- * If length is non zero, then only items with a challenge string of
- * 'length' characters will be shown. (This is only useful for
- * particular types of challenges, such as for showing anagram
- * challenges of a given length).
- *
- * To see a histogram of all currently-loaded items, pass NULL for
- * category and 0 for length.
- *
- * Note: Some bins may be removed entirely by (a misfeature side
- * effect of) the mnemon_do_challenges function, (such as bin 0 being
- * removed after the introduction phase is complete). An accurate
- * histogram can be guaranteed by calling menmon_print_histogram
- * immediately after calling mnemon_load.
+ * This can be useful in situations such as wanting to practice
+ * mastery of learned items without mixing in new items that the user
+ * has never seen before. This could be achieved by removing bin 0,
+ * for example.
*/
void
-mnemon_print_histogram (mnemon_t *mnemon,
- const char *category_name,
- int length);
+mnemon_remove_bin (mnemon_t *mnemon, int bin_number);
+
+/* Find the category to which an item belongs. */
+category_t *
+mnemon_item_category (mnemon_t *mnemon,
+ item_t *item);
+
+/* Get a category by name if it exists */
+category_t *
+mnemon_get_category_if_exists (mnemon_t *mnemon,
+ const char *name);
+
#endif