Handouts:
Assignment #6
Assignment #5 Answers
Class Notes, Chapter 23
Class Notes, Chapter 24
Exercises:
struct cmdtab { char *name; int (*func)(struct actor *, struct object *, struct sentence *); }; extern struct cmdtab *findcmd(char *, struct cmdtab [], int);
static int dircmd(struct actor *, struct object *, struct sentence *); static int takecmd(struct actor *, struct object *, struct sentence *); static int dropcmd(struct actor *, struct object *, struct sentence *); static int lookcmd(struct actor *, struct object *, struct sentence *); static int invcmd(struct actor *, struct object *, struct sentence *); static int examcmd(struct actor *, struct object *, struct sentence *); static int hitcmd(struct actor *, struct object *, struct sentence *); static int breakcmd(struct actor *, struct object *, struct sentence *); static int fixcmd(struct actor *, struct object *, struct sentence *); static int cutcmd(struct actor *, struct object *, struct sentence *); static int readcmd(struct actor *, struct object *, struct sentence *); static int opencmd(struct actor *, struct object *, struct sentence *); static int closecmd(struct actor *, struct object *, struct sentence *); static int lockcmd(struct actor *, struct object *, struct sentence *); static int unlockcmd(struct actor *, struct object *, struct sentence *); static int putcmd(struct actor *, struct object *, struct sentence *); static int helpcmd(struct actor *, struct object *, struct sentence *); static int quitcmd(struct actor *, struct object *, struct sentence *); static struct cmdtab commands[] = { "n", dircmd, "north", dircmd, "s", dircmd, "south", dircmd, "e", dircmd, "east", dircmd, "w", dircmd, "west", dircmd, "ne", dircmd, "northeast", dircmd, "se", dircmd, "southeast", dircmd, "nw", dircmd, "northwest", dircmd, "sw", dircmd, "southwest", dircmd, "up", dircmd, "down", dircmd, "take", takecmd, "drop", dropcmd, "look", lookcmd, "i", invcmd, "inventory", invcmd, "examine", examcmd, "hit", hitcmd, "break", breakcmd, "fix", fixcmd, "cut", cutcmd, "read", readcmd, "open", opencmd, "close", closecmd, "lock", lockcmd, "unlock", unlockcmd, "put", putcmd, "?", helpcmd, "help", helpcmd, "quit", quitcmd, };
docommand(struct actor *player, struct sentence *cmd) { struct cmdtab *cmdtp; cmdtp = findcmd(cmd->verb, commands, Sizeofarray(commands)); if(cmdtp != NULL) { (*cmdtp->func)(player, cmd->object, cmd); return TRUE; } else { printf("I don't know the word \"%s\".\n", cmd->verb); return FALSE; } }The new findcmd function wants to know (as its third argument) the number of entries in the command table. It would be a nuisance if we had to count them, and we'd have to keep updating our count each time we added an entry to the table. The built-in sizeof operator can tell us the size of the array, but it tells us the size in bytes, while we want to know the number of entries. But the number of entries is the size of the array in bytes divided by the size of one entry in bytes, or
sizeof(commands) / sizeof(commands[0])(here we get a handle on ``the size of one entry'' by arbitrarily taking sizeof(commands[0])). Since this is a common operation, I like to define a function-like macro to encapsulate it:
#define Sizeofarray(a) (sizeof(a) / sizeof(a[0]))With that definition in place, the number of entries in the commands array is simply Sizeofarray(commands).
#include <string.h> #include "cmdtab.h" struct cmdtab * findcmd(char *cmd, struct cmdtab cmdtab[], int ncmds) { int i; for(i = 0; i < ncmds; i++) { if(strcmp(cmdtab[i].name, cmd) == 0) return &cmdtab[i]; } return NULL; }
static int takecmd(struct actor *player, struct object *objp, struct sentence *cmd) { if(objp == NULL) { printf("You must tell me what to take.\n"); return FALSE; } if(contains(player->contents, objp)) { printf("You already have the %s.\n", objp->name); return FALSE; } if(hasattr(objp, "immobile")) { printf("The %s cannot be picked up.\n", objp->name); return FALSE; } if(!takeobject(player, objp)) { /* shouldn't happen */ printf("You can't pick up the %s.\n", objp->name); return FALSE; } printf("Taken.\n"); return SUCCESS; }With one exception, all of the rest of the command functions are similar; they just have
static int xxxcmd(struct actor *actor, struct object *objp, struct sentence *cmd) { ... return SUCCESS; }wrapped around the code that used to be in one of the
else if(strcmp(verb, "xxx") == 0) { ... }blocks.
static int dircmd(struct actor *player, struct object *objp, struct sentence *cmd) { struct room *roomp = player->location; char *verb = cmd->verb; int dir; if(strcmp(verb, "n") == 0 || strcmp(verb, "north") == 0) dir = NORTH; else if(strcmp(verb, "s") == 0 || strcmp(verb, "south") == 0) dir = SOUTH; else if(strcmp(verb, "e") == 0 || strcmp(verb, "east") == 0) dir = EAST; else if(strcmp(verb, "w") == 0 || strcmp(verb, "west") == 0) dir = WEST; else if(strcmp(verb, "ne") == 0 || strcmp(verb, "northeast") == 0) dir = NORTHEAST; else if(strcmp(verb, "se") == 0 || strcmp(verb, "southeast") == 0) dir = SOUTHEAST; else if(strcmp(verb, "nw") == 0 || strcmp(verb, "northwest") == 0) dir = NORTHWEST; else if(strcmp(verb, "sw") == 0 || strcmp(verb, "southwest") == 0) dir = SOUTHWEST; else if(strcmp(verb, "up") == 0) dir = UP; else if(strcmp(verb, "down") == 0) dir = DOWN; else return ERROR; if(roomp == NULL) { printf("Where are you?\n"); return ERROR; } /* If the exit does not exist, or if gotoroom() fails, */ /* the player can't go that way. */ if(roomp->exits[dir] == NULL || !gotoroom(player, roomp->exits[dir])) { printf("You can't go that way.\n"); return ERROR; } /* player now in new room */ listroom(player); return SUCCESS; }This function also returns another status code, ERROR (which is also ignored, for now, by docommand). If your copy of game.h doesn't include them, you can put the lines
#define ERROR 0 #define SUCCESS 1in it to #define these values.
This page by Steve Summit // Copyright 1995-9 // mail feedback