/* 2017/2018 Regional ACM International Collegiate Programming Contest Problem ? Haiku M. K. Furon. 2017-10-29. */ #include #include #include #include enum charclass {NEITHER = 0, CONSONANT = 1, VOWEL = 2}; int delimiter, i, line1, line2, total, wordcount; char *iostatus, *result, *token; int syllablecount[20]; char *word[20]; char lineimage[204], originalline[204]; enum charclass lettertype[204]; void abend (char *message) { (void) fputs (message, stderr); (void) fputc ('\n', stderr); exit (4); } enum charclass chartype (int thischar) { static const enum charclass letter[26] = {VOWEL, CONSONANT, CONSONANT, CONSONANT, VOWEL, CONSONANT, CONSONANT, CONSONANT, VOWEL, CONSONANT, CONSONANT, CONSONANT, CONSONANT, CONSONANT, VOWEL, CONSONANT, CONSONANT, CONSONANT, CONSONANT, CONSONANT, VOWEL, CONSONANT, CONSONANT, CONSONANT, VOWEL, CONSONANT}; int offset; enum charclass result; offset = (toupper (thischar)) - 'A'; result = ((offset < 0) || (offset > 25)) ? NEITHER : letter[offset]; return (result); } int numsyllables (char *word) { /* Count the number of syllables in a word. */ int i, nextchar, testchar, wordlen; int count = 0; enum charclass state, thisclass; struct { int lastchar; enum charclass lasttype; } lastletter[4]; wordlen = (int) strlen (word); state = NEITHER; for (i = 0; i < 4; i++) { lastletter[i].lastchar = 0; lastletter[i].lasttype = NEITHER; } for (i = 0; i < wordlen; i++) { testchar = toupper ((int) word[i]); if ((chartype (testchar)) == NEITHER) break; /* Handle the special cases. */ if (testchar == 'Q') { thisclass = CONSONANT; /* Ignore any 'U' that follows and set the state to consonant. */ nextchar = toupper ((int) word[(i + 1)]); if (nextchar == 'U') i++; } else if (testchar == 'Y') { /* If the following character is a non-Y vowel, treat the Y as a consonant. */ thisclass = VOWEL; nextchar = toupper ((int) word[(i + 1)]); if ((isupper (nextchar)) && (nextchar != 'Y') && ((chartype (nextchar)) == VOWEL)) thisclass = CONSONANT; } else thisclass = chartype (testchar); /* Store the last letter and its state in the "last four" buffer. */ lastletter[3] = lastletter[2]; lastletter[2] = lastletter[1]; lastletter[1] = lastletter[0]; lastletter[0].lastchar = testchar; lastletter[0].lasttype = thisclass; if (thisclass == VOWEL) { if (state != VOWEL) { /* Normally the syllable count increases at a non-vowel to vowel transition. Check to see if a special case applies. First special case: does the word end in an E? */ if (testchar == 'E') { if ((chartype (toupper (word[(i + 1)]))) == NEITHER) { /* Handle potential silent E. */ if ((lastletter[1].lastchar == 'L') && (lastletter[2].lasttype == CONSONANT)) count++; } else if ((toupper ((int) word[(i + 1)]) == 'S') && ((chartype (toupper ((int) word[(i + 2)]))) == NEITHER)) { /* Handle ES at the end of a word. */ if ((lastletter[1].lasttype == CONSONANT) && (lastletter[2].lasttype == CONSONANT)) count++; } else /* E is not at the end of a word. */ count++; } else /* Vowel is not E. */ count++; state = VOWEL; } } else state = CONSONANT; } if (!count) /* If zero syllables counted */ count = 1; return (count); } int main (int argc, char *argv[], char *envp[]) { while (fgets (lineimage, 202, stdin) != NULL) { /* Reset the per-word syllable counts. */ wordcount = 0; for (i = 0; i < 20; i++) syllablecount[i] = 0; (void) strncpy (originalline, lineimage, 203); /* Crack the line into words separated by whitespace. */ token = strtok (lineimage, " \t\n"); while ((wordcount < 20) && (token != NULL)) { word[wordcount] = token; syllablecount[wordcount++] = numsyllables (token); token = strtok (NULL, " \t\n"); } /* We now have the word count and the number of syllables in each word. Determine if there are breaks at five, seven, and five syllables. */ line1 = line2 = total = 0; for (i = 0; i < 20; i++) { total += syllablecount[i]; if (total == 5) line1 = 1; else if (total == 12) line2 = 1; } /* If there are a total of seventeen syllables and there were breaks at five and twelve syllables, we have a haiku. */ if ((total == 17) && line1 && line2) { total = 0; for (i = 0; syllablecount[i]; i++) { /* Print each word, inserting line breaks at five and twelve syllables. */ (void) fputs (word[i], stdout); total += syllablecount[i]; delimiter = ((total == 5) || (total == 12) || (total == 17)) ? '\n' : ' '; (void) fputc (delimiter, stdout); } } else (void) fputs (originalline, stdout); } return (0); }