/* $Id: mazeserver.c 53 2008-05-01 05:50:20Z edsko $ */
/* $Source: /home/jgroup/judge1/edsko/maze/RCS/mazeserver.c,v $ */

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/poll.h>
#include <time.h>

#define TRUE 1
#define FALSE 0

#define MAXW 20
#define MAXH 20
#define SSIZE 81

int ubgets(char *buf, int bufsiz, int timeout);

int cx;
int cy;
int ex;
int ey;
int h;
int w;
int m[MAXW][MAXH];

int ReadMaze(FILE *f)
{
   int exitCount=0;
   int startCount=0;
   int len;
   int n;
   int x;
   int y;
   char s[SSIZE];

   ex=-1;
   ey=-1;
   cx=-1;
   cy=-1;
   fgets(s,SSIZE,f);
   len=strlen(s);
   if (s[len - 1] != '\n') {
      fprintf(stderr,"maze configuration: first line missing newline or line too long\n");
      exit(2);
   }
   else {
     s[len - 1]='\0';
   }
   n=sscanf(s,"%d %d",&h,&w);
   if (n != 2) {
      fprintf(stderr,"maze configuration: unable to convert two integers from first line\n");
      exit(2);
   }
   if ((h < 1) || (h > 20)) {
      fprintf(stderr,"maze configuration: rows must be in [1..20]\n");
      exit(2);
   }
   if ((w < 1) || (w > 20)) {
      fprintf(stderr,"maze configuration: columns must be in [1..20]\n");
      exit(2);
   }
   for (y=0; y < h; y++) {
      if (fgets(s,SSIZE,f) == NULL) {
         fprintf(stderr,"maze configuration: unexpected end-of-file on row %d\n",y);
         exit(2);
      }
      len=strlen(s);
      if (s[len - 1] != '\n') {
         fprintf(stderr,"maze configuration: row %d line missing newline or line too long\n",y);
         exit(2);
      }
      else {
        s[len - 1]='\0';
      }
      len=strlen(s);
      if (len != w) {
         fprintf(stderr,"maze configuration: row %d must be %d characters long\n",y,w);
         exit(2);
      }
      for (x=0; x < w; x++) {
         switch (s[x]) {
          case ' ':
            m[x][y]=FALSE;
            break;
          case '*':
            m[x][y]=TRUE;
            break;
          case '-':
            m[x][y]=FALSE;
            cx=x;
            cy=y;
            startCount++;
            break;
          case 'E':
            m[x][y]=FALSE;
            ex=x;
            ey=y;
            exitCount++;
            break;
          default:
            fprintf(stderr,"maze configuration: row %d, unexpected character '%c'\n",y,s[x]);
            exit(2);
         }
      }
   }
   if (fgets(s,SSIZE,f) != NULL) {
      fprintf(stderr,"maze configuration: unexpected data after row %d\n",h-1);
      exit(2);
   }
   if ((ex < 0) || (ey < 0)) {
      fprintf(stderr,"maze configuration: no exit 'E' specified\n");
      exit(2);
   }
   if (exitCount > 1) {
      fprintf(stderr,"maze configuration: only one exit may be specified\n");
      exit(2);
   }
   if ((cx < 0) || (cy < 0)) {
      fprintf(stderr,"maze configuration: no starting point '-' specified\n");
      exit(2);
   }
   if (startCount > 1) {
      fprintf(stderr,"maze configuration: only one starting point may be specified\n");
      exit(2);
   }

/* check for proper edges */

   y=0;
   for (x=0; x < w; x++) {
      if (!m[x][y] && ((x != ex) || (y != ey))) {
         fprintf(stderr,"maze configuration: unexpected pathway at edge (%d,%d)\n",y,x);
         exit(2);
      }
   }
   y=h - 1;
   for (x=0; x < w; x++) {
      if (!m[x][y] && ((x != ex) || (y != ey))) {
         fprintf(stderr,"maze configuration: unexpected pathway at edge (%d,%d)\n",y,x);
         exit(2);
      }
   }
   x=0;
   for (y=0; y < h; y++) {
      if (!m[x][y] && ((x != ex) || (y != ey))) {
         fprintf(stderr,"maze configuration: unexpected pathway at edge (%d,%d)\n",y,x);
         exit(2);
      }
   }
   x=w - 1;
   for (y=0; y < h; y++) {
      if (!m[x][y] && ((x != ex) || (y != ey))) {
         fprintf(stderr,"maze configuration: unexpected pathway at edge (%d,%d)\n",y,x);
         exit(2);
      }
   }
}

void Newxy(int *nx, int *ny, int cx, int cy, int d)
{
   static int dx[6]=   { 0, 1, 1, 0,-1,-1};
   static int dy[2][6]={-1, 0, 1, 1, 1, 0
                       ,-1,-1, 0, 1, 0,-1};

#ifdef DEBUG
  {
   int DX=dx[d - 1];
   int DY=dy[cx%2][d - 1];
   int y;
   for (y=0; y < 6; y++) {
      fprintf(stdout,"%2d: [%2d]  [%2d][%2d]\n",y+1,dx[y],dy[0][y],dy[1][y]);
   }
   fprintf(stdout," DX=%d, DY=%d\n",DX,DY);
  }
#endif
   *nx=cx + dx[d - 1];
   *ny=cy + dy[cx%2][d - 1];
}

void DisplayMaze(FILE *f)
{
   int x;
   int y;

   for (y=0; y < h; y++) {
      fprintf(f,"%2d: ",y);
      for (x=0; x < w; x++) {
         if ((x == cx) && (y == cy)) {
            fputc('-',f);
         }
         else if ((x == ex) && (y == ey)) {
            fputc('E',f);
         }
         else if (m[x][y]) {
            fputc('*',f);
         }
         else {
            fputc(' ',f);
         }
      }
      fputc('\n',f);
   }
}

int main(int argc, char *argv[])
{
   int   len;
   FILE *mazeFile;
   int   moveLimit=0;
   int   moves=0;
   int   nx;
   int   ny;
   char  s[SSIZE];
   FILE *transcriptFile;
   int   x;
   int   y;

   for (y=0; y < MAXH; y++) {
      for (x=0; x < MAXW; x++) {
         m[x][y]=TRUE;
      }
   }
   mazeFile=fopen(argv[1],"r");
   if (mazeFile == NULL) {
      fprintf(stderr,"Could not open maze file \"%s\": %s\n",argv[1],strerror(errno));
      exit(1);
   }
   transcriptFile=fopen(argv[2],"w");
   if (transcriptFile == NULL) {
      fprintf(stderr,"Could not open transcript file \"%s\": %s\n",argv[2],strerror(errno));
      exit(1);
   }
   ReadMaze(mazeFile);
   moveLimit=2*h*w;
   fprintf(transcriptFile,"Start=(%d,%d) Exit=(%d,%d) Limit=%d moves\n",cy,cx,ey,ex,moveLimit); fflush(transcriptFile);
   fprintf(transcriptFile,"move: direction response (row,column)\n"); fflush(transcriptFile);
   do {
      int d;
      char *response;

#     ifdef DEBUG
         DisplayMaze(stdout);
#     endif
      len=ubgets(s,sizeof(s),1000);
/*    fgets(s,sizeof(s),stdin); len=strlen(s); */
      moves++;
      if (len == -1) {
         fprintf(stderr,"move %d: Wrong Answer (unexpected end-of-file)\n",moves);
         exit(0);
      }
      if (len == 0) {
         fprintf(stderr,"move %d: Time Limit Exceeded\n",moves);
         exit(0);
      }
      if (s[len-1] != '\n') {
         fprintf(stderr,"move %d: Run Time Error (no newline)\n",moves);
         exit(0);
      }
      else {
         s[len-1]='\0';
      }
      if (len != 2) {
         fprintf(stderr,"'%s'\n",s);
         fprintf(stderr,"move %d: Run Time Error (line too long/too short)\n",moves);
         exit(0);
      }
      if ((s[0] < '1') || (s[0] > '6')) {
         fprintf(stderr,"'%s'\n",s);
         fprintf(stderr,"move %d: Run Time Error (unexpected character)\n",moves);
         exit(0);
      }
      if (moves > moveLimit) {
         fprintf(stderr,"'%s'\n",s);
         fprintf(stderr,"move %d: Wrong Answer (too many moves, limit=%d)\n",moves,moveLimit);
         exit(0);
      }
      sscanf(s,"%d",&d);
#     ifdef WEIRD
         fprintf(transcriptFile,"%d: '%s'",d,s);
#     endif
      Newxy(&nx,&ny,cx,cy,d);
      if (m[nx][ny]) {
         response="n";
      }
      else {
         cx=nx;
         cy=ny;
         if ((cx == ex) && (cy == ey)) {
            response="E";
         }
         else {
            response="y";
         }
      }
#ifdef VERIFY
      fprintf(stdout," (%d,%d)",cy,cx);
#endif
      fprintf(stdout,"%s\n",response); fflush(stdout);
      fprintf(transcriptFile,"%3d: %d %s (%d,%d)\n",moves,d,response,cy,cx); fflush(transcriptFile);
   } while ((cx != ex) || (cy != ey));
   len=ubgets(s,sizeof(s),1000);
   if (len == -1) {
      fprintf(stderr,"Correct.  Congratulations.\n"); fflush(stderr);
   }
   else {
      fprintf(stderr,"%s",s);
      fprintf(stderr,"Presentation Error (input after finding exit)\n"); fflush(stderr);
   }
   exit(0);
}
