From: Carl Worth Date: Mon, 26 Sep 2011 02:53:02 +0000 (-0700) Subject: Break mnemon up into a main program and a mnemon "library" X-Git-Url: https://git.cworth.org/git?p=mnemon;a=commitdiff_plain;h=e213a74c688dc475578348ac5e0e438055d11311 Break mnemon up into a main program and a mnemon "library" This is in preparation for other programs to start sharing the mnemon code, (likely as a git submodule, so we don't actually build the code as an actual library). --- diff --git a/Makefile b/Makefile index 360b418..538b1db 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ MY_LDFLAGS=-lreadline -lm PROGRAMS=mnemon all: $(PROGRAMS) -%: %.o +mnemon: main.o mnemon.o $(CC) $(CFLAGS) $(MY_CFLAGS) $(LDFLAGS) $(MY_LDFLAGS) -o $@ $^ %.o: %.c diff --git a/main.c b/main.c new file mode 100644 index 0000000..643f49d --- /dev/null +++ b/main.c @@ -0,0 +1,83 @@ +/* mnemon - A memory training program + * + * Copyright © 2006,2011 Carl Worth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." + */ + +/* for asprintf */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mnemon.h" + +int +main (int argc, char *argv[]) +{ + mnemon_t mnemon; + char *response; + + void _load_categories() + { + if (argc > 1) { + int i; + for (i = 1; i < argc; i++) + mnemon_load_category (&mnemon, argv[i]); + } else { + mnemon_load (&mnemon); + } + } + + srand (time (NULL)); + + mnemon_init (&mnemon); + + _load_categories (); + + mnemon_do_challenges (&mnemon); + + mnemon_save (&mnemon); + + mnemon_fini (&mnemon); + + mnemon_init (&mnemon); + + _load_categories (); + + printf ("Great job.\nHere are your current results:\n"); + mnemon_print_histogram (&mnemon, NULL, 0); + response = readline ("Press enter to quit.\n"); + free (response); + + mnemon_fini (&mnemon); + + return 0; +} diff --git a/mnemon.c b/mnemon.c index 5fa8ac9..f869993 100644 --- a/mnemon.c +++ b/mnemon.c @@ -1,9 +1,10 @@ -/* - * Copyright © 2006 Carl Worth +/* mnemon - A memory training library + * + * Copyright © 2006,2011 Carl Worth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) + * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, @@ -16,6 +17,8 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." */ +#include "mnemon.h" + /* for asprintf */ #define _GNU_SOURCE #include @@ -52,12 +55,12 @@ typedef struct _item { char *response; } item_t; -typedef struct _bin { +struct _bin { int score; int items_size; int num_items; item_t **items; -} bin_t; +}; typedef enum { CATEGORY_ORDER_RANDOM, @@ -72,7 +75,7 @@ typedef enum { CHALLENGE_TYPE_TEXT_TO_SPEECH } challenge_type_t; -typedef struct _category { +struct _category { char *name; int items_size; int num_items; @@ -87,24 +90,7 @@ typedef struct _category { challenge_type_t 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; - category_t *categories; - - int bins_size; - int num_bins; - bin_t *bins; - - int to_introduce; - int to_master; - int unlearned; - int mastered; -} mnemon_t; +}; static void * xmalloc (size_t size) @@ -410,7 +396,7 @@ bin_num_items_matching (bin_t *bin, return num_items; } -static void +void mnemon_init (mnemon_t *mnemon) { char *home; @@ -435,7 +421,7 @@ mnemon_init (mnemon_t *mnemon) mnemon->mastered = -1; } -static void +void mnemon_fini (mnemon_t *mnemon) { int i; @@ -579,7 +565,7 @@ trim_space (char *string) return string; } -static void +void mnemon_load_category (mnemon_t *mnemon, const char *name) { @@ -750,7 +736,7 @@ mnemon_load_category (mnemon_t *mnemon, } } -static void +void mnemon_load (mnemon_t *mnemon) { DIR *dir; @@ -779,7 +765,7 @@ mnemon_load (mnemon_t *mnemon) closedir (dir); } -static void +void mnemon_save (mnemon_t *mnemon) { int i, err; @@ -1011,7 +997,7 @@ print_histogram_bar (double size, printf ("\n"); } -static void +void mnemon_print_histogram (mnemon_t *mnemon, const char *category_name, int length) @@ -1254,7 +1240,7 @@ mnemon_hide_challenge (unused (mnemon_t *mnemon), free (command); } -static void +void mnemon_do_challenges (mnemon_t *mnemon) { bin_t *bin; @@ -1348,46 +1334,3 @@ mnemon_do_challenges (mnemon_t *mnemon) mnemon->unlearned || mnemon->to_master > 0); } - -int -main (int argc, char *argv[]) -{ - mnemon_t mnemon; - char *response; - - void _load_categories() - { - if (argc > 1) { - int i; - for (i = 1; i < argc; i++) - mnemon_load_category (&mnemon, argv[i]); - } else { - mnemon_load (&mnemon); - } - } - - srand (time (NULL)); - - mnemon_init (&mnemon); - - _load_categories (); - - mnemon_do_challenges (&mnemon); - - mnemon_save (&mnemon); - - mnemon_fini (&mnemon); - - mnemon_init (&mnemon); - - _load_categories (); - - printf ("Great job.\nHere are your current results:\n"); - mnemon_print_histogram (&mnemon, NULL, 0); - response = readline ("Press enter to quit.\n"); - free (response); - - mnemon_fini (&mnemon); - - return 0; -} diff --git a/mnemon.h b/mnemon.h new file mode 100644 index 0000000..d33cb74 --- /dev/null +++ b/mnemon.h @@ -0,0 +1,171 @@ +/* mnemon - A memory training library + * + * Copyright © 2006,2011 Carl Worth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." + */ + +#ifndef MNEMON_H_INCLUDED +#define MNEMON_H_INCLUDED + +typedef struct _bin bin_t; +typedef struct _category category_t; + +typedef struct _mnemon { + char *dir_name; + + int categories_size; + int num_categories; + category_t *categories; + + int bins_size; + 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 + * any other mnemon functions are used. */ +void +mnemon_init (mnemon_t *mnemon); + +/* Inidicate the caller is finished with a mnemon object. Free all + * resources associated with this object. After this call, the given + * mnemon object should not be passed to any other menmon function, + * (except mnemon_init to start over). */ +void +mnemon_fini (mnemon_t *mnemon); + +/* Load a specific category of mnemon challenges. The name should + * indicate the name of a file within the user's .mnemon directory. */ +void +mnemon_load_category (mnemon_t *mnemon, + const char *name); + +/* Load all categories of mnemon challenges. + * + * This is equivalent to calling mnemon_load_category for all files + * found within the user's .mnemon directory. */ +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. + * + * The challenge 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 start in bin 0 indicating that they have never been presented + * to a user. When an item is presented to the user and answered + * correctly, it is moved into the bin of the next higher number. + * + * However, when an item is answered incorrectly, it is moved directly + * to bin -2 (if coming from a bin of a positive number), or the bin + * of the next lower integer (more negative) if coming from a bin of a + * negative number. + * + * When selecting a new item to challenge, first a bin is chosen + * (considering only the non-empty bins). The bin with the lowest + * 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. + * + * 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. + */ +void +mnemon_do_challenges (mnemon_t *mnemon); + +/* 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. + * + * 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. + */ +void +mnemon_print_histogram (mnemon_t *mnemon, + const char *category_name, + int length); + +#endif