306 lines
5.5 KiB
C
306 lines
5.5 KiB
C
/* animals - guessing game Authors: Terrence W. Holm & Edwin L. Froese */
|
|
|
|
#include <sys/types.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <sgtty.h>
|
|
#include <ctype.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
|
|
#define ANIMALS "/usr/lib/animals"
|
|
#define DEFAULT_ANIMAL "beaver"
|
|
#define MAX_NODES 999 /* Enough for 500 animals */
|
|
#define MAX_LINE 90
|
|
|
|
void Abort();
|
|
char *Get_Animal();
|
|
char *Get_Question();
|
|
char *A_or_An();
|
|
char *Alloc();
|
|
|
|
struct node {
|
|
int question;
|
|
char *text;
|
|
int yes;
|
|
int no;
|
|
} animals[MAX_NODES];
|
|
|
|
int count = 0;
|
|
struct sgttyb old_tty_mode;
|
|
|
|
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
|
|
{
|
|
char *animal_file = ANIMALS;
|
|
|
|
if (argc > 2) {
|
|
fprintf(stderr, "Usage: %s [ data_base ]\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
if (argc == 2) animal_file = argv[1];
|
|
|
|
ioctl(0, TIOCGETP, &old_tty_mode);
|
|
|
|
signal(SIGINT, Abort);
|
|
signal(SIGQUIT, Abort);
|
|
|
|
if (access(animal_file, R_OK) == 0)
|
|
Read_Animals(animal_file);
|
|
else {
|
|
animals[0].question = 0;
|
|
animals[0].text = DEFAULT_ANIMAL;
|
|
count = 1;
|
|
}
|
|
|
|
while (Ask("\nAre you thinking of an animal?")) {
|
|
int i = 0;
|
|
|
|
while (1) {
|
|
if (animals[i].question) {
|
|
if (Ask(animals[i].text))
|
|
i = animals[i].yes;
|
|
else
|
|
i = animals[i].no;
|
|
} else {
|
|
printf("Were you thinking of %s %s",
|
|
A_or_An(animals[i].text), animals[i].text);
|
|
|
|
if (Ask("?")) printf("I knew it!\n");
|
|
|
|
else {
|
|
/* Insert a new question and animal name */
|
|
|
|
if (count + 2 > MAX_NODES)
|
|
Error("Too many animal names");
|
|
|
|
animals[count].question = 0;
|
|
animals[count].text = animals[i].text;
|
|
++count;
|
|
|
|
animals[count].question = 0;
|
|
printf("What animal were you thinking of? ");
|
|
animals[count].text = Get_Animal();
|
|
++count;
|
|
|
|
animals[i].question = 1;
|
|
printf("What question would distinguish %s %s from\n%s %s? ",
|
|
A_or_An(animals[count - 2].text), animals[count - 2].text,
|
|
A_or_An(animals[count - 1].text), animals[count - 1].text);
|
|
|
|
animals[i].text = Get_Question();
|
|
|
|
printf("For %s %s, the answer would be",
|
|
A_or_An(animals[count - 1].text), animals[count - 1].text);
|
|
|
|
if (Ask("?")) {
|
|
animals[i].yes = count - 1;
|
|
animals[i].no = count - 2;
|
|
} else {
|
|
animals[i].yes = count - 2;
|
|
animals[i].no = count - 1;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
} /* End while ( 1 ) */
|
|
|
|
}
|
|
|
|
|
|
ioctl(0, TIOCSETP, &old_tty_mode);
|
|
|
|
printf("\nThank you for playing \"animals\".\n");
|
|
printf("The animal data base is now being updated.\n");
|
|
|
|
Write_Animals(animal_file);
|
|
|
|
sleep(1);
|
|
printf("\nBye.\n");
|
|
|
|
exit(0);
|
|
}
|
|
|
|
|
|
/* Reading and writing the animal data base */
|
|
|
|
|
|
Read_Animals(animal_file)
|
|
char *animal_file;
|
|
|
|
{
|
|
FILE *f;
|
|
char buffer[MAX_LINE];
|
|
|
|
if ((f = fopen(animal_file, "r")) == NULL)
|
|
Error("Can not open animal data base");
|
|
|
|
while (fgets(buffer, MAX_LINE, f) != NULL) {
|
|
int string_length;
|
|
char *string;
|
|
|
|
buffer[strlen(buffer) - 1] = '\0';
|
|
|
|
swab(buffer, buffer, strlen(buffer));
|
|
|
|
if (buffer[0] == 'q') {
|
|
char *end = strchr(buffer, '?');
|
|
string_length = end - buffer;
|
|
animals[count].question = 1;
|
|
sscanf(end+1, "%d:%d",&animals[count].yes,&animals[count].no);
|
|
} else {
|
|
animals[count].question = 0;
|
|
string_length = strlen(buffer) - 1;
|
|
}
|
|
|
|
string = Alloc(string_length + 1);
|
|
|
|
string[0] = '\0';
|
|
strncat(string, buffer + 1, string_length);
|
|
|
|
animals[count].text = string;
|
|
|
|
count++;
|
|
}
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
|
|
Write_Animals(animal_file)
|
|
char *animal_file;
|
|
|
|
{
|
|
FILE *f;
|
|
int i;
|
|
char buffer[MAX_LINE];
|
|
|
|
if ((f = fopen(animal_file, "w")) == NULL)
|
|
Error("Can not write animal data base");
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
if (animals[i].question) sprintf(buffer, "q%s%d:%d", animals[i].text,
|
|
animals[i].yes, animals[i].no);
|
|
else
|
|
sprintf(buffer, "a%s", animals[i].text);
|
|
|
|
/* Make the data base a bit difficult to read */
|
|
swab(buffer, buffer, strlen(buffer));
|
|
fprintf(f, "%s\n", buffer);
|
|
}
|
|
|
|
fclose(f);
|
|
chmod(animal_file, 0666);
|
|
}
|
|
|
|
|
|
/* Reading data from the user */
|
|
int Ask(question)
|
|
char *question;
|
|
{
|
|
struct sgttyb new_tty_mode;
|
|
int response;
|
|
|
|
new_tty_mode = old_tty_mode;
|
|
new_tty_mode.sg_flags |= CBREAK;
|
|
ioctl(0, TIOCSETP, &new_tty_mode);
|
|
|
|
printf("%s ", question);
|
|
|
|
while ((response = getchar()) != 'y' && response != 'n')
|
|
printf("\n%s [yn]?", question);
|
|
putchar('\n');
|
|
ioctl(0, TIOCSETP, &old_tty_mode);
|
|
if (response == 'y')
|
|
return(1);
|
|
else
|
|
return(0);
|
|
}
|
|
|
|
|
|
char *Get_Animal()
|
|
{
|
|
char s[MAX_LINE];
|
|
char *text;
|
|
int text_length;
|
|
|
|
fgets(s, MAX_LINE, stdin);
|
|
text_length = strlen(s);
|
|
text = Alloc(text_length);
|
|
text[0] = '\0';
|
|
strncat(text, s, text_length - 1);
|
|
return(text);
|
|
}
|
|
|
|
|
|
char *Get_Question()
|
|
{
|
|
char s[MAX_LINE];
|
|
char *end;
|
|
char *text;
|
|
|
|
fgets(s, MAX_LINE, stdin);
|
|
|
|
/* Capitalize the first letter */
|
|
if (islower(s[0])) s[0] = toupper(s[0]);
|
|
|
|
/* Make sure the question ends with a '?' */
|
|
if ((end = strchr(s, '?')) == NULL)
|
|
s[strlen(s) - 1] = '?';
|
|
else
|
|
end[1] = '\0';
|
|
|
|
text = Alloc(strlen(s) + 1);
|
|
strcpy(text, s);
|
|
return(text);
|
|
}
|
|
|
|
|
|
/* Utility routines */
|
|
char *A_or_An(word)
|
|
char *word;
|
|
{
|
|
if (strchr("aeiouAEIOU", word[0]) == NULL)
|
|
return("a");
|
|
else
|
|
return("an");
|
|
}
|
|
|
|
|
|
char *Alloc(size)
|
|
int size;
|
|
{
|
|
char *malloc();
|
|
char *memory;
|
|
|
|
if ((memory = malloc(size)) == NULL)
|
|
Error("No room in memory for all the animals");
|
|
|
|
return(memory);
|
|
}
|
|
|
|
|
|
void Abort()
|
|
{
|
|
ioctl(0, TIOCSETP, &old_tty_mode);
|
|
|
|
printf("\nThank you for playing \"animals\".\n");
|
|
printf("Since you aborted, the animal data base will not be updated.\n");
|
|
sleep(1);
|
|
printf("\nBye.\n");
|
|
exit(1);
|
|
}
|
|
|
|
|
|
Error(message)
|
|
char *message;
|
|
{
|
|
ioctl(0, TIOCSETP, &old_tty_mode);
|
|
fprintf(stderr, "Error: %s\n", message);
|
|
exit(1);
|
|
}
|