/* Problem 7--Jumble!
   This wasn't particularly hard, just a bit tedious.  Just follow the
   rules to decide whether a word is good, fair, or poor.  Note:  one
   of the data sets gives a different answer using my solution from the
   distributed solution.  It sure looks to me, though, that my solution
   is right and theirs is in error. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define VCSIZE 12
#define CCSIZE 37

typedef struct LLC {
 /* ANSI C has no standard routine for reading a string of unspecified
    length, so this data structure accomplishes this. */
 char c;
 struct LLC *n;
} LLC;

int main (int argc, char **argv);
int ReadString (char **A);
int IsVowel (char c);
int Good (char *J);
int GoodVowel (char *J);
int GoodCons (char *J);
int Match (char *W, char *J);

FILE *in, *out;

/* The acceptable vowel and consonant combinations */
char *VowelComb[VCSIZE] = {"AI","AY","EA","EE","EO","IO","OA","OO","OY",
                           "YA","YO","YU"};
char *ConsComb[CCSIZE] = {"SCH","SCR","SHR","THR","BL","BR","CH","CK",
                          "CL","CR","DR","FL","FR","GH","GL","GR","KL",
                          "KR","KW","PF","PL","PR","SC","SH","SK","SL",
                          "SM","SN","SP","SQ","ST","SW","TH","TR","TW",
                          "WH","WR"};

int main (int argc, char **argv) {

  char *Word, *Jumble;

 in = fopen ("prob7.in","r");
 out = fopen ("prob7.out","w");
 while (ReadString (&Word)) { /* Get the word and the jumble. */
  ReadString (&Jumble);
  switch (Match (Word,Jumble)) { /* Print appropriate message. */
   case 0 : {fprintf (out,"\"%s\" is not a scramble of \"%s\"\n\n",
                      Jumble,Word);
             break;}
   case 1 : {fprintf (out,"\"%s\" is a good scramble of \"%s\"\n\n",
                      Jumble,Word);
             break;}
   case 2 : {fprintf (out,"\"%s\" is a poor scramble of \"%s\"\n\n",
                      Jumble,Word);
             break;}
   case 3 : {fprintf (out,"\"%s\" is a fair scramble of \"%s\"\n\n",
                      Jumble,Word);
             break;}
  }
 }
 fclose (in);
 fclose (out);
 return EXIT_SUCCESS;
}

/* ReadString reads in a string of unspecified length into a linked
   list and then converts it to a char array.  It returns 0 if the data
   is exhausted, 1 otherwise. */
int ReadString (char **A) {

  int c, ct=0;
  LLC *head = NULL, *t;

 do {
  c = fgetc (in);  /* Read characters into linked list until EOF or */
  if (c==EOF) break; /* EOLN is found. */
  t = malloc (sizeof (LLC));
  t->n = head;
  head = t;
  if (c >= 'A' && c <= 'Z') t->c = c;
  else t->c = 0;
  ct++;
 } while (c!='\n');
 if (c!=EOF) *A = malloc (ct*sizeof(char)); /* Build string from list */
 while (head != NULL) {
  if (c!=EOF) (*A)[--ct] = head->c;
  t = head; head=t->n; free (t);
 }
 return c!=EOF;
}

/* IsVowel returns a boolean indicating whether the given letter is a
   vowel. */
int IsVowel (char c) {
 return c=='A' || c=='E' || c=='I' || c=='O' || c=='U' || c=='Y';
}

/* returns a boolean indicating whether the given word is "good" */
int Good (char *J) {
 if (IsVowel (J[0])) return GoodVowel (J);
 return GoodCons (J);
}

/* GoodVowel accepts a word and returns true provided that the word is
   good and begins with a vowel, false otherwise. */
int GoodVowel (char *J) {

  int i;

 if (J[0]==0) return 1;
 if (!IsVowel (J[0])) return 0; /* doesn't begin with a vowel */
 for (i=0;i < VCSIZE; i++){ /* Go through valid double vowels */
  if (strlen (VowelComb[i]) <= strlen (J) &&
      memcmp (VowelComb[i],J,strlen(VowelComb[i]))==0)
   return GoodCons (&(J[strlen(VowelComb[i])]));}
 return GoodCons (&(J[1]));/*return whether rest of string is GoodCons*/
}

/* GoodCons accepts a word and returns true provided that the word is
   good and begins with a consonant, false otherwise. */
int GoodCons (char *J) {

  int i;

 if (J[0]==0) return 1;
 if (IsVowel (J[0])) return 0; /* doesn't begin with a consonant */
 for (i=0;i < CCSIZE; i++) /* Go through valid double consonants */
  if (strlen (ConsComb[i]) <= strlen (J) &&
      memcmp (ConsComb[i],J,strlen(ConsComb[i]))==0)
   return GoodVowel (&(J[strlen(ConsComb[i])]));
 if (J[0]==J[1]) return GoodVowel (&(J[2])); /* Check for rep. cons. */
 return GoodVowel (&(J[1]));/* return whether rest is GoodVowel */
}

/* Match takes a word and a jumble and returns 0 if not a jumble, 1 if
   it is a good jumble, 2 if it is a poor jumble, and 3 if it is a fair
   jumble. */
int Match (char *W, char *J) {

  int i, m, g;

 if (strcmp (W,J)==0) return 0;
 g = Good (J);
 for (m=0,i=0; i < strlen (W); i++)
  if (W[i]==J[i]) m++; /* Count matches in word and jumble */
 if (g && m==0) return 1;
 if (!g && (W[0]==J[0] || m>=2)) return 2;
 return 3;
}
