From 50efa22849c73c3b43e5005e6ddafc5f0027464a Mon Sep 17 00:00:00 2001 From: "Jason S. Ninneman" Date: Tue, 11 Jul 2017 17:44:06 -0700 Subject: [PATCH] Express word type with an enum instead of magic numbers. * 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 | 34 +++++++++++++------------- advent.h | 13 ++++------ main.c | 40 +++++++++++++++---------------- misc.c | 72 ++++++++++++++++++++++++++++++++++++------------------- 4 files changed, 90 insertions(+), 69 deletions(-) diff --git a/actions.c b/actions.c index 64b5c20..0e6dd7a 100644 --- 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; diff --git a/advent.h b/advent.h index 44839a8..c545f04 100644 --- a/advent.h +++ b/advent.h @@ -69,13 +69,6 @@ #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 8f3549e..e365e1f 100644 --- 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 78cc5a3..4844fb8 100644 --- 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) -- 2.31.1