Break mnemon up into a main program and a mnemon "library"
authorCarl Worth <cworth@cworth.org>
Mon, 26 Sep 2011 02:53:02 +0000 (19:53 -0700)
committerCarl Worth <cworth@cworth.org>
Mon, 26 Sep 2011 03:30:30 +0000 (20:30 -0700)
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).

Makefile
main.c [new file with mode: 0644]
mnemon.c
mnemon.h [new file with mode: 0644]

index 360b418b1c66d516311e9b1d346f4a1c69ca3b99..538b1db6eba89dcbdab1e5fa052c03c271030b2a 100644 (file)
--- 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 (file)
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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <math.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#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;
+}
index 5fa8ac9e418a8d6f6f1e143c92d6d4addd039f6b..f869993061de67ad9332bbe3b77a8753ab882310 100644 (file)
--- 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 <stdio.h>
@@ -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 (file)
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