Express word type with an enum instead of magic numbers. 238/head
authorJason S. Ninneman <jsn@mbar.us>
Wed, 12 Jul 2017 00:44:06 +0000 (17:44 -0700)
committerJason S. Ninneman <jsn@mbar.us>
Wed, 12 Jul 2017 17:35:00 +0000 (10:35 -0700)
* Make a cleaner function for getting vocab metadata.
* Get rid of magic numbers.
* Purge get_vocab_id().
* Abolish the *_WORD() macros.
* Add FIXME comment on some ugliness.

actions.c
advent.h
main.c
misc.c

index 64b5c20aa0f77b3db94e1ce170d80a1e95401637..0e6dd7ad69836045cfb6d3785a070d773a4bfecf 100644 (file)
--- a/actions.c
+++ b/actions.c
@@ -185,13 +185,13 @@ static int bigwords(long id)
  *  Look up foo in special section of vocab to determine which word we've got.
  *  Last word zips the eggs back to the giant room (unless already there). */
 {
-    if ((game.foobar == WORD_EMPTY && id == ACTION_WORD(FEE)) ||
-        (game.foobar == ACTION_WORD(FEE) && id == ACTION_WORD(FIE)) ||
-        (game.foobar == ACTION_WORD(FIE) && id == ACTION_WORD(FOE)) ||
-        (game.foobar == ACTION_WORD(FOE) && id == ACTION_WORD(FOO)) ||
-        (game.foobar == ACTION_WORD(FOE) && id == ACTION_WORD(FUM))) {
+    if ((game.foobar == WORD_EMPTY && id == FEE) ||
+        (game.foobar == FEE && id == FIE) ||
+        (game.foobar == FIE && id == FOE) ||
+        (game.foobar == FOE && id == FOO) ||
+        (game.foobar == FOE && id == FUM)) {
         game.foobar = id;
-        if ((id != ACTION_WORD(FOO)) && (id != ACTION_WORD(FUM))) {
+        if ((id != FOO) && (id != FUM)) {
             rspeak(OK_MAN);
             return GO_CLEAROBJ;
         }
@@ -1127,16 +1127,18 @@ static int say(struct command_t *command)
     }
     char word1[TOKLEN + 1];
     packed_to_token(command->wd1, word1);
-    int wd = (int) get_vocab_id(word1);
-    if (wd == MOTION_WORD(XYZZY) ||
-        wd == MOTION_WORD(PLUGH) ||
-        wd == MOTION_WORD(PLOVER) ||
-        wd == ACTION_WORD(FEE) ||
-        wd == ACTION_WORD(FIE) ||
-        wd == ACTION_WORD(FOE) ||
-        wd == ACTION_WORD(FOO) ||
-        wd == ACTION_WORD(FUM) ||
-        wd == ACTION_WORD(PART)) {
+    long wd;
+    enum wordtype type;
+    get_vocab_metadata(word1, &wd, &type);
+    if (wd == XYZZY ||
+        wd == PLUGH ||
+        wd == PLOVER ||
+        wd == FEE ||
+        wd == FIE ||
+        wd == FOE ||
+        wd == FOO ||
+        wd == FUM ||
+        wd == PART) {
         /* FIXME: scribbles on the interpreter's command block */
         wordclear(&command->wd2);
         return GO_LOOKUP;
index 44839a899c81a0c30f7b6600043c06e6631de309..c545f048f2f67a943957a10a26b994083ef3c851 100644 (file)
--- a/advent.h
+++ b/advent.h
 #define INDEEP(LOC)  ((LOC) >= LOC_MISTHALL && !OUTSID(LOC))
 #define BUG(x)       bug(x, #x)
 
-#define MOTION_WORD(n)  ((n) + 0)
-#define OBJECT_WORD(n)  ((n) + 1000)
-#define ACTION_WORD(n)  ((n) + 2000)
-#define SPECIAL_WORD(n) ((n) + 3000)
-#define PROMOTE_WORD(n) ((n) + 1000)
-#define DEMOTE_WORD(n)  ((n) - 1000)
-
 enum bugtype {
     SPECIAL_TRAVEL_500_GT_L_GT_300_EXCEEDS_GOTO_LIST,
     VOCABULARY_TYPE_N_OVER_1000_NOT_BETWEEN_0_AND_3,
@@ -94,6 +87,8 @@ enum termination {endgame, quitgame, scoregame};
 
 enum speechpart {unknown, intransitive, transitive};
 
+enum wordtype {NO_WORD_TYPE, MOTION, OBJECT, ACTION, SPECIAL};
+
 /* Phase codes for action returns.
  * These were at one time FORTRAN line numbers.
  * The values don't matter, but perturb their order at your peril.
@@ -200,6 +195,8 @@ struct command_t {
     long id1;
     long id2;
     char raw1[LINESIZE], raw2[LINESIZE];
+    enum wordtype type1;
+    enum wordtype type2;
 };
 
 extern struct game_t game;
@@ -225,7 +222,7 @@ extern int get_motion_vocab_id(const char*);
 extern int get_object_vocab_id(const char*);
 extern int get_action_vocab_id(const char*);
 extern int get_special_vocab_id(const char*);
-extern long get_vocab_id(const char*);
+extern void get_vocab_metadata(const char*, long*, enum wordtype*);
 extern void juggle(obj_t);
 extern void move(obj_t, loc_t);
 extern long put(obj_t, long, long);
diff --git a/main.c b/main.c
index 8f3549e97dfc975c91ca4d76d6861b5fd91f5e46..e365e1fc0a6f81dbf0330deeccfe93d390c0c93e 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1006,8 +1006,8 @@ static bool get_command_input(struct command_t *command)
 
     packed_to_token(command->wd1, word1);
     packed_to_token(command->wd2, word2);
-    command->id1 = get_vocab_id(word1);
-    command->id2 = get_vocab_id(word2);
+    get_vocab_metadata(word1, &(command->id1), &(command->type1));
+    get_vocab_metadata(word2, &(command->id2), &(command->type2));
 
     return true;
 }
@@ -1015,7 +1015,6 @@ static bool get_command_input(struct command_t *command)
 static bool do_command()
 /* Get and execute a command */
 {
-    long kmod, defn;
     static struct command_t command;
     char word1[TOKLEN + 1];
 
@@ -1115,7 +1114,7 @@ Lclosecheck:
             lampcheck();
 
         if (command.id1 == ENTER && (command.id2 == STREAM ||
-                                     command.id2 == PROMOTE_WORD(WATER))) {
+                                     command.id2 == WATER)) {
             if (LIQLOC(game.loc) == WATER)
                 rspeak(FEET_WET);
             else
@@ -1127,13 +1126,11 @@ Lclosecheck:
             command.id1 = command.id2;
             command.id2 = WORD_EMPTY;
         } else {
-            /* FIXME: Magic numbers related to vocabulary */
-            if (!((command.id1 != PROMOTE_WORD(WATER) && command.id1 != PROMOTE_WORD(OIL)) ||
-                  (command.id2 != PROMOTE_WORD(PLANT) && command.id2 != PROMOTE_WORD(DOOR)))) {
-                if (AT(DEMOTE_WORD(command.id2)))
+         if (!((command.id1 != WATER && command.id1 != OIL) || (command.id2 != PLANT && command.id2 != DOOR))) {
+                if (AT(command.id2))
                     command.wd2 = token_to_packed("POUR");
             }
-            if (command.id1 == PROMOTE_WORD(CAGE) && command.id2 == PROMOTE_WORD(BIRD) && HERE(CAGE) && HERE(BIRD))
+            if (command.id1 == CAGE && command.id2 == BIRD && HERE(CAGE) && HERE(BIRD))
                 command.wd1 = token_to_packed("CATCH");
         }
 Lookup:
@@ -1146,7 +1143,9 @@ Lookup:
                 rspeak(GO_UNNEEDED);
         }
         packed_to_token(command.wd1, word1);
-        defn = get_vocab_id(word1);
+       long defn;
+       enum wordtype type;
+       get_vocab_metadata(word1, &defn, &type);
         if (defn == WORD_NOT_FOUND) {
             if (fallback_handler(command))
                 continue;
@@ -1154,22 +1153,21 @@ Lookup:
             sspeak(DONT_KNOW, command.raw1);
             goto Lclearobj;
         }
-        /* FIXME: magic numbers related to vocabulary */
-        kmod = MOD(defn, 1000);
-        switch (defn / 1000) {
-        case 0:
-            playermove(kmod);
+        switch (type) {
+       case NO_WORD_TYPE: // FIXME: treating NO_WORD_TYPE as a motion word is confusing
+        case MOTION:
+            playermove(defn);
             return true;
-        case 1:
+        case OBJECT:
             command.part = unknown;
-            command.obj = kmod;
+            command.obj = defn;
             break;
-        case 2:
+        case ACTION:
             command.part = intransitive;
-            command.verb = kmod;
+            command.verb = defn;
             break;
-        case 3:
-            speak(specials[kmod].message);
+        case SPECIAL:
+            speak(specials[defn].message);
             goto Lclearobj;
         default:
             BUG(VOCABULARY_TYPE_N_OVER_1000_NOT_BETWEEN_0_AND_3); // LCOV_EXCL_LINE
diff --git a/misc.c b/misc.c
index 78cc5a30e5a13a5da4f68519e77bb1a30a52ee6b..4844fb89ba8208db7195edd548d5a8d630608a48 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -523,37 +523,61 @@ int get_special_vocab_id(const char* word)
     return (WORD_NOT_FOUND);
 }
 
-long get_vocab_id(const char* word)
-// Search the vocab categories in order for the supplied word.
-{
-    /* Check for an empty string */
-    if (strncmp(word, "", sizeof("")) == 0)
-        return (WORD_EMPTY);
+void get_vocab_metadata(const char* word, long* id, enum wordtype* type)
+{
+  /* Check for an empty string */
+  if (strncmp(word, "", sizeof("")) == 0)
+    {
+      *id = WORD_EMPTY;
+      *type = NO_WORD_TYPE;
+      return;
+    }
 
-    long ref_num;
+  long ref_num;
 
-    /* FIXME: Magic numbers related to vocabulary */
-    ref_num = get_motion_vocab_id(word);
-    if (ref_num != WORD_NOT_FOUND)
-        return MOTION_WORD(ref_num);
+  ref_num = get_motion_vocab_id(word);
+  if (ref_num != WORD_NOT_FOUND)
+    {
+      *id = ref_num;
+      *type = MOTION;
+      return;
+    }
 
-    ref_num = get_object_vocab_id(word);
-    if (ref_num != WORD_NOT_FOUND)
-        return OBJECT_WORD(ref_num);
+  ref_num = get_object_vocab_id(word);
+  if (ref_num != WORD_NOT_FOUND)
+    {
+      *id = ref_num;
+      *type = OBJECT;
+      return;
+    }
 
-    ref_num = get_action_vocab_id(word);
-    if (ref_num != WORD_NOT_FOUND)
-        return ACTION_WORD(ref_num);
+  ref_num = get_action_vocab_id(word);
+  if (ref_num != WORD_NOT_FOUND)
+    {
+      *id = ref_num;
+      *type = ACTION;
+      return;
+    }
 
-    ref_num = get_special_vocab_id(word);
-    if (ref_num != WORD_NOT_FOUND)
-        return SPECIAL_WORD(ref_num);
+  ref_num = get_special_vocab_id(word);
+  if (ref_num != WORD_NOT_FOUND)
+    {
+      *id = ref_num;
+      *type = SPECIAL;
+      return;
+    }
 
-    // Check for the reservoir magic word.
-    if (strcasecmp(word, game.zzword) == 0)
-        return ACTION_WORD(PART);
+  // Check for the reservoir magic word.
+  if (strcasecmp(word, game.zzword) == 0)
+    {
+      *id = PART;
+      *type = ACTION;
+      return;
+    }
 
-    return (WORD_NOT_FOUND);
+  *id = WORD_NOT_FOUND;
+  *type = NO_WORD_TYPE;
+  return;
 }
 
 void juggle(obj_t object)