X-Git-Url: https://git.cworth.org/git?p=mnemon;a=blobdiff_plain;f=mnemon.h;h=27e02a075b52db8b352db442e3211c1bac68486d;hp=d33cb742ac000cb2b461c9ac99bbc83142208c61;hb=5ae11041e3b0f7c5a04795c71fe3794d663eb195;hpb=e213a74c688dc475578348ac5e0e438055d11311 diff --git a/mnemon.h b/mnemon.h index d33cb74..27e02a0 100644 --- a/mnemon.h +++ b/mnemon.h @@ -20,24 +20,55 @@ #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 @@ -65,13 +96,28 @@ mnemon_load_category (mnemon_t *mnemon, 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 @@ -87,85 +133,66 @@ mnemon_load (mnemon_t *mnemon); * 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