#include #include #include #include #include #include #include #include #define BUFLEN 128 struct Entry { char buf[BUFLEN]; /* associated input line */ char* hint; /* description or hint, points into buf */ char* phrase; /* to be guessed phrase, points into buf */ }; unsigned int sample(char* filename, unsigned int nofentries, struct Entry selected[nofentries]) { FILE* fp = fopen(filename, "r"); if (!fp) return 0; char buf[BUFLEN]; unsigned int filled = 0; unsigned int number_of_records = 0; while (fgets(buf, sizeof buf, fp)) { char* sep = 0; for (char* cp = buf; *cp && cp < buf + sizeof buf; ++cp) { if (*cp == '\t') { sep = cp; break; } } if (!sep) continue; ++number_of_records; unsigned int index = filled; if (filled < nofentries) { ++filled; } else { index = rand() % number_of_records; } if (index < nofentries) { strncpy(selected[index].buf, buf, sizeof buf); selected[index].hint = selected[index].buf; unsigned int i = sep - buf; selected[index].phrase = selected[index].buf + i + 1; selected[index].buf[i] = 0; /* separate the two strings */ } } fclose(fp); return filled; } unsigned long incl(unsigned long letterset, char ch) { assert(isalpha(ch)); if (isupper(ch)) { ch = tolower(ch); } letterset |= 1 << (ch - 'a'); return letterset; } bool inset(unsigned long letterset, char ch) { assert(isalpha(ch)); if (isupper(ch)) { ch = tolower(ch); } return letterset & (1 << (ch - 'a')); } unsigned long init_set_from_phrase(char* phrase) { unsigned long letterset = 0; while (*phrase) { char ch = *phrase; if (isalpha(ch)) { letterset = incl(letterset, ch); } ++phrase; } return letterset; } void print_status(unsigned int hangman_count, unsigned long guessed, char* phrase) { printf("%d ", hangman_count); unsigned int count = 0; for (char letter = 'a'; letter <= 'z'; ++letter) { if (inset(guessed, letter)) { putchar(letter); } else { ++count; } } while (count--) { putchar(' '); } putchar(' '); for (char* cp = phrase; *cp != '\n'; ++cp) { if (isalpha(*cp) && !inset(guessed, *cp)) { putchar('_'); } else { putchar(*cp); } } putchar('\n'); fflush(stdout); } /* return value: > 0: number of points = 0: game lost -1: end of input */ int run_game(struct Entry* entry) { // start the game by printing the description puts(entry->hint); // prepare the game unsigned long letterset = init_set_from_phrase(entry->phrase); unsigned long guessed = 0; unsigned int hangman_count = 7; while (hangman_count && ((guessed & letterset) != letterset)) { print_status(hangman_count, guessed, entry->phrase); int ch; while ((ch = getchar()) != EOF && !isalpha(ch)) { if (!isspace(ch)) { puts("Letter expected."); } } if (ch == EOF) { puts("End of input. Exiting."); return -1; } if (!inset(letterset, ch)) { --hangman_count; } guessed = incl(guessed, ch); } print_status(hangman_count, guessed, entry->phrase); if (hangman_count > 0) { printf("Congratulations, you got %d points!\n", hangman_count); } else { fputs(entry->phrase, stdout); // use fputs to avoid a double LF puts("You lose!"); } return hangman_count; } int main() { srand(getpid() ^ time(0)); struct Entry entries[16]; unsigned int nof_entries = sample("Ulm.hm", sizeof entries / sizeof(entries[0]), entries); if (nof_entries == 0) { puts("No valid input file found."); return 1; } unsigned int points = 0; unsigned int games; for (games = 0; games < sizeof(entries)/sizeof(entries[0]); ++games) { int result = run_game(entries + games); if (result < 0) break; points += result; } printf("You got %d points after %d games.\n", points, games); }