#include <stdio.h>
#include "genlib.h"
#include "random.h"
/* define the maximum dimensions of the map array */
#define MAP_SIZE_X 5
#define MAP_SIZE_Y 5


/* define the maximum dimensions of the map array */

#define MAX_OBJS 100

/* define the maximum number of barrels */
#define NO_OF_BARRELS 12

/*   Enumeration to keep track of the state of game objects - this lets us 
     refer to the state symbolically, making code that refers to particular 
     state more readable  */

typedef enum{
  NORMAL, IN_RINGOS_HAND, ON_THE_GROUND
}State;


/*   Enumeration to keep track of the locations - this lets us refer to the
     locations symbolically, making code that refers to particular locations
     more readable  */

typedef enum {
   LOC_GRAVE,
   LOC_DAVY,
   LOC_SINKHOLE,
   LOC_MICKY,

   LOC_BAR,
   LOC_SHOP,
   LOC_BRINE,
   LOC_CRAB,
   LOC_SUB,

   LOC_CORAL,
   LOC_ROCKS,
   LOC_OCTOPUS,
   LOC_EEL,
   LOC_WATER,

   LOC_SHIP,
   LOC_PUPPETS,
   LOC_BASE,
   LOC_PILE,

   LOC_PARTY,
   LOC_HORSES,
   LOC_COWBOYS,
   LOC_MONKEYS,
   LOC_CENTER,
   /* This is a way of declaring Maximum possible Location we have, 
      It acts as a Sentinel Location, we can use this in declaration of 
      array, or to specify any invalid location value */
   MAX_LOC /* Sentinel Location */
} Location;


/*   Enumeration for game objects.   */
typedef enum {
   OBJ_RINGO,
   OBJ_OCTOPUS,
   OBJ_EEL,
   OBJ_CRAB,
   OBJ_DRUM
} GameObj;


/*  Define ObjectDescription Type 
 *  containing name and Description which are strings
 */

typedef struct{
  char *name;
  char *desc;
}ObjectDescription;


typedef struct{
  int x;
  int y;
  State obj_state;
  GameObj obj_type;
  ObjectDescription *obj_desc; /* ObjectDescription Ptr */
}ObjectInfo;

/* input: a two-dimensional array of Locations map and array of short
          strings to be printed for each map location, locnames, that
          is indexed by Locations

   output: none
   
   side-effects: prints out a table of short map names based on where
                 each location is located in the map array
   notes: - assumes that the first map index encodes the north-south
            direction and the second enoded east-west, and that map[0][0]
            is the northwesternmost point
	 
	  - since this works by following the ordering of whatever is in the
	     map array, this will continue to work even if we scramble the
	     map around, or even enlarge it, provided we still organize the
	     new map as specified above */
   
void View(Location map[MAP_SIZE_Y][MAP_SIZE_X], string locnames[25])
{
  int x, y; 
  
  printf("\n");

  /* Iterate over all map coordinates, starting in the upper-left-hand
     corner of the map, which has coordinates x=0, y=0 in this implementation.
     Note that if you made x=0, y=0 be the lower-left-hand corner, then
     you would need to run the outer for loop backwards, starting from 5
     and ending at zero */
  for(y = 0; y < MAP_SIZE_Y; y++)
    {
      for(x = 0; x < MAP_SIZE_X; x++)
        {
	  /* the array locnames is indexed by locations, so we simply run
	     over all locations in the map, and look up the equivalent
	     string in the locnames array. We use a field width of 16
	     in the printf formatting string since none of the strings
	     are longer than 15 characters, so this should give us evenly-
	     spaced columns */
	  
          printf("%-16s", locnames[map[y][x]]);
        }
      printf("\n");
    }
}

/* input: a Location
   output: a string corresponding to that location, suitable for printing
           in movement messages "Ringo swims DIR, from X to Y" */

string LocationStr(Location loc)
{
   string locstr = "";

   /*   Find out the string corresponding to the location.   */
   switch(loc)
   {
   case LOC_GRAVE:    locstr = "watery grave";  break;
   case LOC_DAVY:     locstr = "Davy Jones locker";  break;
   case LOC_SINKHOLE: locstr = "spooky sinkhole";  break;
   case LOC_MICKY:    locstr = "Micky Dolens locker";  break;

   case LOC_BAR:      locstr = "sand bar & grill";  break;
   case LOC_SHOP:     locstr = "prawn shop";  break;
   case LOC_BRINE:    locstr = "brine & spirits";  break;
   case LOC_CRAB:     locstr = "crabs cottage";  break;
   case LOC_SUB:      locstr = "yellow submarine";  break;

   case LOC_CORAL:    locstr = "coral reef";  break;
   case LOC_ROCKS:    locstr = "pointy rocks";  break;
   case LOC_OCTOPUS:  locstr = "octopus garden";  break;
   case LOC_EEL:      locstr = "eels estates";  break;

   case LOC_WATER:    locstr = "empty ocean spot";  break;
   case LOC_SHIP:     locstr = "sunken pirate ship";  break;
   case LOC_PUPPETS:  locstr = "stolen puppets";  break;
   case LOC_BASE:     locstr = "marine refinery";  break;
   case LOC_PILE:     locstr = "barnacle pile";  break;

   case LOC_PARTY:    locstr = "manatee party";  break;
   case LOC_HORSES:   locstr = "sea horses";  break;
   case LOC_COWBOYS:  locstr = "sea cowboys";  break;
   case LOC_MONKEYS:  locstr = "sea monkeys";  break;
   case LOC_CENTER:   locstr = "visitors center";  break;

   default:
      printf("No location string for %d\n", loc);
   }
   return locstr;
}

/* input: a Location
   output: a string corresponding to that location, suitable for printing
           in movement messages "Ringo swims DIR, from X to Y" */

string DirectionStr(char act)
{
   string dirstr = "";

   /*   Find out the string corresponding to the direction.   */
   switch(act)
   {
   case 'n': dirstr = "north"; break;
   case 's': dirstr = "south"; break;
   case 'e': dirstr = "east"; break;
   case 'w': dirstr = "west"; break;
   }
   return dirstr;
}


/* input: Structure of game object, a character representing the direction
          he is to move, and a two dimensional array representing a map
          of the world so that we can compute where the move will take the 
	  game object.
   output: Strcture which represents game object's new location
   side-effects: prints messages indicating the game object's movement has
                 taken place
*/

ObjectInfo Move (ObjectInfo object, char direction, Location map [5][5] )
{
   int x, y, vx, vy;

   /* We declare a structure for storing the new location where the game
      object can possibly move, this will be used to return the new location
      after move. As all the fields of structure will not be modified we do an 
      intialisation of this game object structure with current game object's 
      structure */

   ObjectInfo new_location=object;
   
   /* Save the game object identification, to identify later as 
      Ringo or Crab, as we need to print different message for their 
      movements.
   */
   
   GameObj who = object.obj_type; 

   x = object.x;
   y = object.y;

   /*   find the location next to it and return the value.   */
   switch(direction)
   {
     /* compute the change in coordinates we will need to make to make
      a move. vx is the change in x coordinates and vy is the change 
      in y coordinates. If we go east, that means that the x coordinate
      increases by 1, and y stays the same. If we go north, the
      y coordinate will decrease by 1, and x will stay the same */
   
   case 'e': vx = 1; vy = 0; break;
   case 'w': vx = -1; vy = 0; break;
   case 'n': vx = 0; vy = -1; break;
   case 's': vx = 0; vy = 1; break;
   }
   
   /* check to see whether the change we want to make will take us off
      the edge of the map (and therefore would be invalid array indices.
      If that is the case, just print a message and return the current
      map location. This test is for Ringo*/
   
   if((x + vx < 0 || x + vx >= MAP_SIZE_X ||
       y + vy < 0 || y + vy >= MAP_SIZE_Y)&&(who == OBJ_RINGO))
   {
      printf("Nothing interesting in this direction.\n");
      printf("Let's stay here.\n");
      return(new_location);
   }
   
   /* check to see whether the change we want to make will take us off
      the edge of the map (and therefore would be invalid array indices.
      If that is the case, just print a message and return the current
      map location. This test is for Crab */
      
   if((x + vx < 0 || x + vx >= MAP_SIZE_X ||
       y + vy < 0 || y + vy >= MAP_SIZE_Y)&&(who == OBJ_CRAB))
     {
       printf("The crab tries to swim %s, out of %s, but the current draws it back.\n", DirectionStr(direction), LocationStr(map[y][x]));
       return(new_location);
     }
  
   /* check to see whether we need to print Ringo's message */
 if (who==OBJ_RINGO){
   printf("You swim %s, out of the %s, into the %s.\n",
	  DirectionStr(direction), 
	  LocationStr(map[y][x]), 
	  LocationStr(map[y + vy][x + vx]));
 }

 /* check to see whether we need to print Crab's message */
 if (who==OBJ_CRAB){
   printf("The crab swims %s, out of the %s, into the %s.\n",
          DirectionStr(direction),
          LocationStr(map[y][x]),
          LocationStr(map[y + vy][x + vx]));
 }


 /*   finally, we change game object's field for location to new location so
      that the caller can update by assignment, as we know structure assignment
      copies every field of structure to the correspoding field of left hand
      side strcture variable, we need to make sure the unmodified fields have 
      the same value, such as obj_type and obj_desc and so on, that is the 
      reason why we initialised new_location with the original structure 
      when we declared it */

   new_location.x = x+vx;
   new_location.y = y+vy;
   return(new_location);
}

/* input: an array of game objects, indexed by GameObjs.
   output: none
   side-effects: changes the location of the grabbed object to Ringo's hand
                 by changing the array directly, and prints messages indicating
                 that this change has happened
   notes: - will not allow Ringo to grab more than one object
          - Ringo can only grab an object at his current location */
	  
void Grab(ObjectInfo objects[MAX_OBJS])
{
   int i;

   /* if something is already in Ringo's hand which is mainted as state of 
      game object, then don't let Ringo grab anything else */
   for(i = 0; i < MAX_OBJS; i++){
      if(objects[i].obj_state == IN_RINGOS_HAND){  
	printf("You already have something in your hand.\n");
	return;
      }
   }

   /* Find an object where ringo is */
   for (i=0; i< MAX_OBJS;i++){
     /*  we find the object we are interested in grabbing but we 
         check if its in  Ringo's current location ...*/
     if(objects[i].x == objects[OBJ_RINGO].x &&
	objects[i].y == objects[OBJ_RINGO].y &&
	objects[i].obj_type!=OBJ_RINGO){ 
       switch(objects[i].obj_type){
       case OBJ_RINGO:
	 /* You cannot grab yourself so this just prints a message */
	 printf("You try to grab yourself but you wriggle free!\n");
	 
	 return; /* We return as you cannot grab yourself */
	 break; /* this break has no effect, as you have already returned */
       case OBJ_OCTOPUS :
	
	 printf("You grab the octopus with your mighty European ");
	 printf("arms.\n");
	 break;
	 
       case OBJ_EEL:
       case OBJ_CRAB:
       case OBJ_DRUM:
	 printf("You grab %s.\n",objects[i].obj_desc->name);
	 break;
       default:
	 /*   This should not happen */
	 printf("You are David CopperField, you grab something which does not exists!");
       	 break;
       }
       objects[i].obj_state = IN_RINGOS_HAND;
       return;
     }
   } 
   printf("Nothing here to grab.\n");
   }

/* input: an array of game objects, indexed by GameObjs, that keeps track of
          the Location,State, etc. of all of the objects in the simulation
   output: none
   side-effect: changes the state of the object in Ringo's hand to Ringo's
                current location by directly changing the game object array,
                and prints a message indicating that this has happened
   notes: - Ringo cannot throw anything if there's nothing in his hand
          - The octopus is handled specially: instead of being placed at
            Ringo's current location with state NORMAL, it is put in the state
            ON_THE_GROUND to encode that the octopus is dazed */

void Throw(ObjectInfo objects[MAX_OBJS])
{
   int i;
   bool found;

   /*   Find the one in ringo's hand.   */
   found = FALSE;
   for(i = 0; i < MAX_OBJS; i++)
   {
      if(objects[i].obj_state == IN_RINGOS_HAND)
	{
	  switch(objects[i].obj_type)
	    {
	    case OBJ_RINGO:
	      /*   shouldn't happen.   */
	      printf("Ringo holding Ringo???\n");
	      exit(1);
	      break;
	      
	    case OBJ_OCTOPUS:
	      printf("You throw the octopus onto the ground.  It is ");
	      printf("momentarily dazed.\n");
	      /* octopus is made dazed */
	      objects[i].obj_state =  ON_THE_GROUND;
	      break;
	    
	    case OBJ_EEL:
	    case OBJ_CRAB:
	    case OBJ_DRUM:
	      printf("You throw %s onto groud.\n",objects[i].obj_desc->name);
	      objects[i].obj_state =  NORMAL;
	      break;
	  
	    default:
	      /*   This should not happen */
	      printf("You are David CopperField, you throw something which does not exists!");
	      break;
  }
	  
	  /* After throwing the game object its location is same as Ringo's
	     location */
	  objects[i].x = objects[OBJ_RINGO].x;
	  objects[i].y = objects[OBJ_RINGO].y;
	  printf("There is %s here.\n",objects[i].obj_desc->name);
	  found = TRUE;
	  break;
	}
   }

/* if we didn't actually find anything in Ringo's hand, then print an
      appropriate message */
   if(!found)
     {
       printf("You try to throw something, but you have nothing ");
       printf("in your hands.\n");
     }
}



/* input : array of game objects 
   output : none 
   side-effect: prints the object present in Ringo's hand with its 
                description
   notes: none */
   
void Examine(ObjectInfo objs[MAX_OBJS]){

  int i;

  /* Check all gameobject ...*/
  for(i=0;i<MAX_OBJS;i++){
    /* check if the object is in Ringo's hand */
    if(objs[i].obj_state == IN_RINGOS_HAND){
      printf("You have %s %s in your Hand!\n",objs[i].obj_desc->desc,objs[i].obj_desc->name);
      
      break; /** Assumption : Ringo Can hold only one object */
     
    }
  }
  /* if none of the game object is in Ringo's hand then print a message */
  if(i == MAX_OBJS){
    printf("Palmistry is not your business, there is nothing in your hand to examine!\n");
    
  }
  
}

/* input : array of string to hold description of locations
   output : none 
   side-effect: Initializes the location array with its corresponding string 
   notes: This array is used to print a location in its string form*/

void initLocNames(string locNames[MAX_LOC]){

  locNames[(int)LOC_GRAVE]    = "watery grave";	
  locNames[(int)LOC_DAVY]     = "DJ's locker";
  locNames[(int)LOC_SINKHOLE] = "sinkhole";
  locNames[(int)LOC_MICKY]    = "MD's locker";
  
  locNames[(int)LOC_BAR]      = "sand bar/grill";
  locNames[(int)LOC_SHOP]     = "prawn shop";
  locNames[(int)LOC_BRINE]    = "brine/spirits";
  locNames[(int)LOC_CRAB]     = "crab";
  locNames[(int)LOC_SUB]      = "yellow sub";
  
  locNames[(int)LOC_CORAL]    = "coral reef";
  locNames[(int)LOC_ROCKS]    = "pointy rocks";
  locNames[(int)LOC_OCTOPUS]  = "octopus";
  locNames[(int)LOC_EEL]      = "eels";
  
  locNames[(int)LOC_WATER]    = "water";
  locNames[(int)LOC_SHIP]     = "pirate ship";
  locNames[(int)LOC_PUPPETS]  = "puppets";
  locNames[(int)LOC_BASE]     = "refinery";
  locNames[(int)LOC_PILE]     = "barnacles";
   
  locNames[(int)LOC_PARTY]    = "manatee party";
  locNames[(int)LOC_HORSES]   = "sea horses";
  locNames[(int)LOC_COWBOYS]  = "sea cowboys";
  locNames[(int)LOC_MONKEYS]  = "sea monkeys";
  locNames[(int)LOC_CENTER]   = "visitor ctr"; 

  
}


/* input : array of ObjectInfo, array of ObjectDescription  
   side-effect: Initializes the ObjectInfo array for all game object
                and initializes entries in the ObjectDescription array
                with descriptions
   notes : These structure's are modified when any game object is moved or 
           its state is changed.*/

void initGameObjects(ObjectInfo objs[MAX_OBJS],ObjectDescription objsDesc[MAX_OBJS])
{

  int i;
  
  /** Initialize Ringo game object */
  
  /* Initialize Ringo's initial location   */
   objs[OBJ_RINGO].x = 2;
   objs[OBJ_RINGO].y = 2;
   
   /* Assign this game object as Ringo type, this field helps in identifying
      the object type, when passed as a single strcture rather than array */
   objs[OBJ_RINGO].obj_type = OBJ_RINGO;
   
   /* Assign the intial state of Ringo */
   objs[OBJ_RINGO].obj_state = NORMAL;
   
   /* Initialize Ringo's description */
   objsDesc[OBJ_RINGO].name="ringo";
   objsDesc[OBJ_RINGO].desc="ringo starr";

   /* Assign the description field, address of description of Ringo object */
   objs[OBJ_RINGO].obj_desc = &objsDesc[OBJ_RINGO];

   
   /** Initialize Octopus game object */
   
   /* Initialize Octopus's initial location */
   objs[OBJ_OCTOPUS].x = 2;
   objs[OBJ_OCTOPUS].y = 2;
   
   /* Assign this game object as Octopus type, this field helps in identifying
       the object type, when passed as a single strcture rather than array */
   objs[OBJ_OCTOPUS].obj_type = OBJ_OCTOPUS;
   
   /* Assign the intial state of Octopus */
   objs[OBJ_OCTOPUS].obj_state = NORMAL;   
   
   /*Initialize Octopus's description */
   objsDesc[OBJ_OCTOPUS].name="octopus";
   objsDesc[OBJ_OCTOPUS].desc="never dying";

   /* Assign the description field, address of description of Octopus object */
   objs[OBJ_OCTOPUS].obj_desc = &objsDesc[OBJ_OCTOPUS];
 

   /** Initialize Eel game object */
   
   /* Initialize Eel's initial location */
   objs[OBJ_EEL].x = 3;
   objs[OBJ_EEL].y = 2;
   
   /* Assign this game object as Eel type, this field helps in identifying
       the object type, when passed as a single strcture rather than array */
   objs[OBJ_EEL].obj_type = OBJ_EEL;

   /* Assign the intial state of Eel */
   objs[OBJ_EEL].obj_state = NORMAL;
   
   /* Initialize Eel's description */
   objsDesc[OBJ_EEL].name="eel";
   objsDesc[OBJ_EEL].desc="ultra-conductive electric";

   /* Assign the description field, address of description of Eel object */
   objs[OBJ_EEL].obj_desc = &objsDesc[OBJ_EEL];


   /** Initialize Crab game object */
   
   /* Initialize Crab's initial location */
   objs[OBJ_CRAB].x = 3;
   objs[OBJ_CRAB].y = 1;
   
   /* Assign this game object as Crab type, this field helps in identifying
      the object type, when passed as a single strcture rather than array */
   objs[OBJ_CRAB].obj_type = OBJ_CRAB;

   /* Assign the intial state of Crab */
   objs[OBJ_CRAB].obj_state = NORMAL;

   /* Initialize Crab's description */
   objsDesc[OBJ_CRAB].name="crab";
   objsDesc[OBJ_CRAB].desc="liquid waste abhorrent";
   
   /* Assign the description field, address of description of Crab object */
   objs[OBJ_CRAB].obj_desc = &objsDesc[OBJ_CRAB];


   /* initialize the (single) description for all drums */
   objsDesc[OBJ_DRUM].name = "drum";
   objsDesc[OBJ_DRUM].desc = "liquid waste";

   /** Initialize all Drum game object */
      
   for(i = OBJ_DRUM; i < NO_OF_BARRELS+OBJ_DRUM; i++)
   {
   
     /* Initialize Drum's initial location */
      objs[i].x = 3;
      objs[i].y = 3;

      /* Assign this game object as Drum type, this field helps in identifying
	 the object type, when passed as a single strcture rather than array */
      objs[i].obj_type = OBJ_DRUM;   
      
      /* Assign the intial state of Drum */
      objs[i].obj_state = NORMAL;
         
      /* Assign the description field, address of description of Drum object */
      objs[i].obj_desc = &objsDesc[OBJ_DRUM];
   }

   /*Initialize all other non-existing objects to be outside the map*/
   for(i = OBJ_DRUM+NO_OF_BARRELS; i < MAX_OBJS; i++)
     {
       /* Initialize non-existing object to location outside the map */
       objs[i].x = -1;
       objs[i].y = -1;
       objs[i].obj_state = NORMAL;
       objs[i].obj_desc = NULL;
     }

}

/* the main program - consists, essentially, of a giant loop that takes
   single-character actions from the user, and calls functions to change
   the state of the game according to the current state and the action the
   user takes */
void main()
{
  /* the action the user wishes Ringo to take and pad character 
     to read the next character from user which is usually '\n'  */
 char act,pad;
  
 /* variable used to store random number from (1,4) */
   int d;
   
   /* this keeps track of the octopus strcuture's last value, so that we can 
      tell whether the octopus should escape or not - see the last 3 if 
      statement at the bottom of the main loop, where this is used. */
   
   ObjectInfo lastOctopusLoc;

   /* Array to hold string description of locations */
   string locNames[25];

   /* Create Array of ObjectDescription */

   /* ObjectDescription holds name and description of each game object */
   ObjectDescription objDesc[MAX_OBJS];
   
   /* Game object array holds each game object */
   ObjectInfo objs[MAX_OBJS];

   
   /*   Initialize the map using 2-dimensional array initialization syntax.
	This makes the the upper left corner (LOC_GRAVE) be at coordinates
	(x,y) = (0,0), LOC_BAR be at (0,1), ... the octopuses garden
	at (2,2), ... LOC_MONKEYS be at (3,4) and the LOC_CENTER be at (4,4).
	This could also be done in the style of locNames, as in initLocNames: 
	one array location at a time */
   
   Location map [MAP_SIZE_Y] [MAP_SIZE_X] =
   {
     { LOC_GRAVE,  LOC_WATER,   LOC_DAVY,    LOC_SINKHOLE, LOC_MICKY },
     { LOC_BAR,    LOC_SHOP,   LOC_BRINE,   LOC_CRAB,     LOC_SUB },
     { LOC_CORAL,  LOC_ROCKS,  LOC_OCTOPUS, LOC_EEL,      LOC_WATER },
     { LOC_WATER,  LOC_SHIP,   LOC_PUPPETS, LOC_BASE,     LOC_PILE },
     { LOC_PARTY,  LOC_HORSES, LOC_COWBOYS, LOC_MONKEYS,  LOC_CENTER }
   };

   /* Initialize the location array to hold their descriptive string */
   initLocNames(locNames);
   
   /* Initialize all Game objects */
   initGameObjects(objs,objDesc); /* converted to function */
   
   /* Start Randomnumber generation routine*/
   Randomize();

   /*   Introductory text.    */
   printf("You're in an octopus' garden, just like in your ");
   printf("song, except the octopus is\nthrowing things at ");
   printf("you and frightening you.\n");
   
    while(1)
   {
      /*   Receive input from the user.   */
      printf("Your action: ");
      act = getchar();
      while ((pad=getchar())!='\n'){
        /* eat up any extra input */
      }

      /*   Check for the quit command as a special case.   */
      if(act == 'q')
      {
         printf("You quit, bored of undersea life already.\n");
         break;
      }

      

      /* store the octopus's current strcuture value since it's movement has
	 to be handled specially */
      lastOctopusLoc = objs[OBJ_OCTOPUS];
      
      /*   Branch out depending on the user's input:  note that one switch
	   statement suffices - we don't need a special one for each
	   location. Most actions have the same effect at any location.
	   For actions that _do_ have a location dependence, we can put
	   an if statement to handle this just in those cases. See below */
      

      switch(act)
      {

      /*   Let's take care of all the cases for swiming in one shot: we
	   always call Move, except if Ringo hasn't escaped yet */
      
      case 'n':
      case 's':
      case 'e':
      case 'w':
	
      	 /* if the octopus isn't stunned and Ringo is trying to escape the
	    octopus's garden, then the octopus should prevent him */
	if(objs[OBJ_RINGO].x == objs[OBJ_OCTOPUS].x &&
	    objs[OBJ_RINGO].y == objs[OBJ_OCTOPUS].y && 
            objs[OBJ_OCTOPUS].obj_state != ON_THE_GROUND)
         {
           printf("You try to swim %s, ", DirectionStr(act));
           printf("but the octopus gets in your way.\n");
	  
	 }
	/* otherwise, call Move to compute the new Location, passing
	    Ringo's current Location, the direction character, and
	    the entire map array (note the lack of square brackets).
	    Be sure to store the new location of Ringo back in the
	    locations array (named "objs" here) */
         
         else
         {
	   objs[OBJ_RINGO] = Move(objs[OBJ_RINGO], act, map);           
	 }
	
	 break;
	
	 /* to throw something, we simply pass the whole array objs to Throw,
	 which takes care of _all_ of the details */
      
      case 't':
	/*  Throw */
	Throw(objs);
	break;
	
	/* similarly, we pass objs to Grab, and it totally does all the work
	   involved in grabbing an object */
      case 'g':
	/* Grab */
	Grab(objs);
	break;

	/* The yell action just prints a message.*/
      case 'y':
         /*   Yell.   */
	printf("You yell, \"go watch TV!\"\n");
	break;
	
	/* At the moment, there's never anything to hide behind, so we print
	   the same message every time */
      case 'h':
         /*   Hide.   */
         printf("You try to hide, but there is nothing to hide ");
         printf("behind.\n");
         break;

      /* The View function totally takes care of printing the map. We need
	 only pass it the map array and an array, indexed by Locations,
	 of strings that should be printed for each Location */
      case 'v':
         /*   View map.   */
         View(map,locNames);
         break; 

	 /* The Examine function totally takes care of finding an object in 
	    Ringo's hand(if any). We need only pass it the game object array 
	    which also has pointer field for name and string that  should be 
	    printed for a game object if its in Ringo's hand */
      case 'x': 
	/* Examine Object */
	Examine(objs);
	break;

      default:
         /*   Error case.  Just let the user know.   */
         printf("Unknown action, type n, s, e, w, y, h, g, t, v, x or q.\n");
         break;
         }/* end of action-decoding switch statement */

      /* we use RandomInteger to pick any integer out of 1 to 4 (both values
	 inclusive), depending on the number we get which is random out of 
	 these four number, we go in that direction, we pick a configuration
	 as for 1=>north, 2=>west, 3=>south and 4=>east. you can use any
	 such assignment scheme, this strategy does not make sure that 
	 crab will always  be successful in staying away from Ringo */

      d=RandomInteger(1,4);
      /* we donot allow crab to move or escape if its in Ringo's hand*/
      if (objs[OBJ_CRAB].obj_state != IN_RINGOS_HAND){
	switch (d){
	case 1: /* we make crab go  north */
	  objs[OBJ_CRAB]= Move(objs[OBJ_CRAB], 'n', map);
	  break;
	case 2: /* we make crab go west */
	  objs[OBJ_CRAB]= Move(objs[OBJ_CRAB], 'w', map);
          break; 
	case 3:/* we make crab go south */
	  objs[OBJ_CRAB]= Move(objs[OBJ_CRAB], 's', map);
          break;
	default: /* we make crab go east */
	  objs[OBJ_CRAB]= Move(objs[OBJ_CRAB], 'e', map);
          break;
	}
      }

      /*   Set the situation variables to new values.   */
     

      /* if Ringo was holding the octopus, and his next action was _not_
	 to throw it, then the octopus should escape, so we reset its
	 location to Ringo's location */
      
      if(lastOctopusLoc.obj_state == IN_RINGOS_HAND &&
	 objs[OBJ_OCTOPUS].obj_state != ON_THE_GROUND)
      {
	printf("The octopus wriggles free of your grasp.\n");
         objs[OBJ_OCTOPUS].x = objs[OBJ_RINGO].x;
	 objs[OBJ_OCTOPUS].y = objs[OBJ_RINGO].y;
	 objs[OBJ_OCTOPUS].obj_state = NORMAL;
      }

      /* if the octopus was dazed on the last turn (indicated by its state
	 ON_THE_GROUD), and Ringo is still in the octopus's garden,
	 then the octopus should recover, leaving the ON_THE_GROUND state
	 so Ringo has to start the cycle all over again */
      
      if(lastOctopusLoc.obj_state == ON_THE_GROUND &&
         objs[OBJ_RINGO].x == objs[OBJ_OCTOPUS].x &&
	 objs[OBJ_RINGO].y == objs[OBJ_OCTOPUS].y &&
	 objs[OBJ_OCTOPUS].obj_state != IN_RINGOS_HAND)
	{
	  printf("The octopus recovers from its fall.\n");
	  objs[OBJ_OCTOPUS].x = objs[OBJ_RINGO].x;
	  objs[OBJ_OCTOPUS].y = objs[OBJ_RINGO].y;
	  objs[OBJ_OCTOPUS].obj_state = NORMAL;
	}
      
      /*   Check if Ringo is still being harrased: he should be if he's still
	   in the octopus's garden and he hasn't grabbed or thrown the
	   octopus on this turn */
      
      if(objs[OBJ_RINGO].x == objs[OBJ_OCTOPUS].x &&
	 objs[OBJ_RINGO].y == objs[OBJ_OCTOPUS].y &&
	 objs[OBJ_OCTOPUS].obj_state == NORMAL)
	{
	  printf("The octopus keeps harassing you.\n");
	}
   }/* end of main while-loop */

}



















































