#include <stdio.h>
#include "genlib.h"


#define MAP_SIZE_X 5
#define MAP_SIZE_Y 5
#define MAX_OBJS 100


/*   Enumeration to keep track of the locations.   */
typedef enum {
   LOC_GRAVE,
   LOC_TOMB,
   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_SMELTS,

   LOC_SHELLS,
   LOC_SHIP,
   LOC_PUPPETS,
   LOC_BASE,
   LOC_PILE,

   LOC_PARTY,
   LOC_HORSES,
   LOC_COWBOYS,
   LOC_MONKEYS,
   LOC_CENTER,

   LOC_RINGO,
   LOC_SMASHED,
} Location;

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


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_TOMB:     locstr = "undersea tomb";  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_SMELTS:   locstr = "mess of smelts";  break;

   case LOC_SHELLS:   locstr = "bunch of shells";  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;
}

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;
}


Location Move(Location current, char act, 
   Location map[MAP_SIZE_Y][MAP_SIZE_X])
{
   int x, y, vx, vy;
   bool found = FALSE;

   /*   find the coordinates.   */
   for(x = 0; x < MAP_SIZE_X; x++)
   {
      for(y = 0; y < MAP_SIZE_Y; y++)
      {
         if(current == map[y][x])
         {
            found = TRUE;
            break;
         }
      }
      if(found)
      {
         break;
      }
   }
   if(!found)
   {
      printf("Unknown location: %d\n", current);
      exit(1);
   }

   /*   find the location next to it and return the value.   */
   switch(act)
   {
   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;
   }
   if(x + vx < 0 || x + vx >= MAP_SIZE_X ||
      y + vy < 0 || y + vy >= MAP_SIZE_Y)
   {
      printf("Nothing interesting in this direction.\n");
      printf("Let's stay here.\n");
      return map[y][x];
   }

   printf("You swim %s, out of the %s, into the %s.\n",
      DirectionStr(act), 
      LocationStr(map[y][x]), 
      LocationStr(map[y + vy][x + vx]));

   return map[y + vy][x + vx];
}


void Grab(Location locations[MAX_OBJS])
{
   int i;

   /*   Check if ringo has anything.   */
   for(i = 0; i < MAX_OBJS; i++)
   {
      if(locations[i] == LOC_RINGO)
      {
         printf("You alraedy have something in your hand.\n");
         return;
      }
   }

   /*  Find an object where ringo is.   */
   for(i = 0; i < MAX_OBJS; i++)
   {
      if(locations[i] == locations[OBJ_RINGO] && i != OBJ_RINGO)
      {
         switch(i)
         {
         case OBJ_RINGO:
            /*   just skip.   */
            break;

         case OBJ_OCTOPUS:
            printf("You grab an octopus.\n");
            break;

         case OBJ_EEL:
            printf("You grab an eel.\n");
            break;

         case OBJ_CRAB:
            printf("You grab a crab.\n");
            break;

         default:
            /*   should be a drum.   */
            printf("You grab a drum of liquid waste.\n");
            break;
         }
         locations[i] = LOC_RINGO;
         return;
      }
   }

   printf("Nothing here.\n");
}


void Throw(Location locations[MAX_OBJS])
{
   int i;
   bool found;

   /*   Find the one in ringo's hand.   */
   found = FALSE;
   for(i = 0; i < MAX_OBJS; i++)
   {
      if(locations[i] == LOC_RINGO)
      {
         switch(i)
         {
         case OBJ_RINGO:
            /*   shouldn't happen.   */
            printf("Ringo holding Ringo???\n");
            exit(1);
            break;

         case OBJ_OCTOPUS:
            printf("You throw an octopus onto the ground.\n");
            break;

         case OBJ_CRAB:
            printf("You throw a crab onto the ground.\n");
            break;

         case OBJ_EEL:
            printf("You throw an eel onto the ground.\n");
            break;

         default:
            /*   should be one of the drums.   */
            printf("You throw a drum of liquid waste onto the ground.\n");
            break;
         }
         locations[i] = locations[OBJ_RINGO];
         found = TRUE;
         break;
      }
   }
   if(!found)
   {
      printf("You try to throw something, but you have nothing ");
      printf("in your hands.\n");
   }
}


void main()
{
   char act;
   int i;
   Location lastOctopusLoc;

   /*   These keep track of locations of oil waste drums.   */
   Location objs[MAX_OBJS];

   /*   Initialize the map.   */
   Location map [MAP_SIZE_Y] [MAP_SIZE_X] =
   {
     { LOC_GRAVE,  LOC_TOMB,   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_SMELTS },
     { LOC_SHELLS, LOC_SHIP,   LOC_PUPPETS, LOC_BASE,     LOC_PILE },
     { LOC_PARTY,  LOC_HORSES, LOC_COWBOYS, LOC_MONKEYS,  LOC_CENTER }
   };

   /*   Initialize the location of game objects.   */
   objs[OBJ_RINGO] = LOC_OCTOPUS;
   objs[OBJ_OCTOPUS] = LOC_OCTOPUS;
   objs[OBJ_EEL] = LOC_EEL;
   objs[OBJ_CRAB] = LOC_CRAB;
   for(i = OBJ_DRUM_START; i < MAX_OBJS; i++)
   {
      objs[i] = LOC_BASE;
   }

   /*   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();
      getchar();

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

      /*   Branch out depending on the user's input.   */
      lastOctopusLoc = objs[OBJ_OCTOPUS];
      switch(act)
      {
      case 'n':
      case 's':
      case 'e':
      case 'w':
         /*   Let's take care of all the cases for swiming in one shot.   */
         if(objs[OBJ_RINGO] == LOC_OCTOPUS && 
            objs[OBJ_OCTOPUS] != LOC_SMASHED)
         {
           printf("You try to swim %s, ", DirectionStr(act));
           printf("but the octopus gets in your way.\n");
         }
         else
         {
            objs[OBJ_RINGO] = Move(objs[OBJ_RINGO], act, map);
         }
         break;

      case 't':
         /*   Throw.   */
         if(objs[OBJ_RINGO] == LOC_OCTOPUS &&
            objs[OBJ_OCTOPUS] == LOC_RINGO)
         {
            printf("You throw the octopus onto the ground.  It is ");
            printf("momentarily dazed.\n");
            objs[OBJ_OCTOPUS] = LOC_SMASHED;
         }
         else
         {
            Throw(objs);
         }
         break;

      case 'g':
         /*   Grab.   */
         if(objs[OBJ_RINGO] == LOC_OCTOPUS &&
            objs[OBJ_OCTOPUS] == LOC_OCTOPUS)
         {
            printf("You grab the octopus with your mighty European ");
            printf("arms.\n");
            objs[OBJ_OCTOPUS] = LOC_RINGO;
         }
         else
         {
            Grab(objs);
         }
         break;

      case 'y':
         /*   Yell.   */
         if(objs[OBJ_RINGO] == LOC_OCTOPUS)
         {
             printf("You yell at the octopus, \"go watch TV!\"\n");
         }
         else
         {
             printf("You yell, \"I hate the ocean!\"\n");
             printf("Nothing happens.\n");
         }
         break;

      case 'h':
         /*   Hide.   */
         printf("You try to hide, but there is nothing to hide ");
         printf("behind.\n");
         break;

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


      /*   Set the situation variables to new values.   */
      if(lastOctopusLoc == LOC_RINGO &&
         objs[OBJ_OCTOPUS] != LOC_SMASHED)
      {
         printf("The octopus wriggles free of your grasp.\n");
         objs[OBJ_OCTOPUS] = objs[OBJ_RINGO];
      }
      if(lastOctopusLoc == LOC_SMASHED &&
         objs[OBJ_RINGO] == LOC_OCTOPUS)
      {
         printf("The octopus recovers from its fall.\n");
         objs[OBJ_OCTOPUS] = objs[OBJ_RINGO];
      }

      /*   Check if Ringo is still being harrased.   */
      if(objs[OBJ_RINGO] == LOC_OCTOPUS &&
         objs[OBJ_OCTOPUS] == LOC_OCTOPUS)
      {
         printf("The octopus keeps harassing you.\n");
      }
   }
}


