home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume36
/
formes
/
part02
/
quizstep.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-04-01
|
12KB
|
614 lines
/*
* Copyright (C) 1992-1993 Jeffrey Chilton
*
* Permission is granted to anyone to make or distribute copies of
* this program, in any medium, provided that the copyright notice
* and permission notice are preserved, and that the distributor
* grants the recipient permission for further redistribution as
* permitted by this notice.
*
* Author's E-mail address: 172-9221@mcimail.com
*
*/
static char *whatstring = "@(#)quizstep.c 2.7 JWC";
#include <ctype.h>
#include <stdio.h>
#include "class.h"
#include "quizstep.h"
#include "assoc.h"
#include "collect.h"
#include "exstr.h"
#include "subject.h"
#include "subjset.h"
#include "random.h"
#include "report.h"
#include "verb.h"
#include "verbset.h"
extern Random *Squizzer;
extern VerbSet *AllVerbs;
extern SubjectSet *AllSubjects;
extern ReportCard *VerbScores;
extern int GotRight;
static int matchStep();
QuizStep *
QuizStep_new()
{
QuizStep *self;
self = (QuizStep *)malloc(sizeof (QuizStep));
if (!self)
{
fprintf(stderr, "QuizStep_new: malloc fails\n");
goto out;
}
self->detail = Collection_new(matchStep, NULLDESTROY);
if (!self->detail)
{
fprintf(stderr, "QuizStep_new: Collection_new fails\n");
self = (QuizStep *)0;
goto out;
}
self->type = STEP_NONE;
out:
return self;
}
static int
matchStep(symbol, key)
Association *symbol;
char *key;
{
return strcmp(Association_getKey(symbol), key);
}
char *Opers[N_STEPTYPES] =
{
"NONE", "VERB", "PERSON", "TEXT-OF", "CONJUGATE", "QUIZ", "SCORE"
};
void cutOneWord();
QuizStep *
QuizStep_newFromString(string, symbols)
char *string;
Collection *symbols;
{
register int i;
QuizStep *self;
char operation[32];
char detail[80];
char *start, *word;
char copy[80];
Association *sym;
ExtendString *t;
int length;
int rc;
self = QuizStep_new();
if (!self)
{
fprintf(stderr, "QuizStep_newFromString: QuizStep_new fails\n");
goto out;
}
sscanf(string, "%s %[^\n]", operation, detail);
/* Look up step type */
rc = FALSE;
for (i = STEP_VERB; i < N_STEPTYPES; i++)
{
if (0 == strcmp(operation, Opers[i]))
{
self->type = i;
rc = TRUE;
break;
}
}
if (!rc)
{
fprintf(stderr, "QuizStep_newFromString: unknown: %s\n", operation);
goto out;
}
/* Parse detail section and look up symbols */
start = &detail[0];
cutOneWord(&start, &word, &length);
while (word)
{
strncpy(copy, word, length);
copy[length] = '\0';
sym = (Association *)Collection_atKeyGet(symbols, copy);
if (!sym)
{
t = ExtendString_newFromString(copy);
sym = Association_newWithKey(t);
Collection_add(symbols, sym);
}
Collection_add(self->detail, (char *)sym);
cutOneWord(&start, &word, &length);
}
out:
return self;
}
void
cutOneWord(start, word, length)
char **start;
char **word;
int *length;
{
char *t, *u;
t = *start; /* skip over any leading spaces */
while (*t == ' ' || *t == '>')
{
t++;
}
if (*t == '\0') /* indicate done if at the end */
{
*word = NULL;
goto out;
}
if (*t == '<') /* special case quoted text */
{
u = t++;
while (*t && *t != '>') /* which ends only on end quote */
{
t++;
}
t++;
}
else if (*t == '{' || *t == '}') /* or special case "{" & "}" */
{
u = t++;
}
else /* else end on "<", " ", or "}" */
{
u = t++;
while (*t && *t != '<' && *t != ' ' && *t != '}')
{
t++;
}
}
*word = u; /* send out the results */
*start = t;
*length = t - u;
out:
return;
}
/* QuizStep_display - display one step */
int
QuizStep_display(self)
QuizStep *self;
{
register int i;
Association *sym;
printf(" %s: ", Opers[self->type]);
for (i = 0; i < Collection_size(self->detail); i++)
{
sym = (Association *)Collection_atGet(self->detail, i);
printf("%s(%x) ", Association_getKey(sym), Association_getValue(sym));
}
printf("\n");
return PERFECT;
}
/* QuizStep_perform - do whatever this step does */
#define SAMEFORM(a, b) ( \
Form_isEquivalent(Subject_getForm(a), Subject_getForm(b)) \
)
char *tenses[N_OF_TENSES] = {
"INFINITIVE",
"PRESENT",
"IMPERFECT",
"SIMPLE-PAST",
"FUTURE",
"CONDITIONAL",
"SUBJUNCTIVE",
"IMPERFECT-SUBJUNCTIVE",
"PAST",
"PLUPERFECT",
"PAST-ANTERIOR",
"FUTURE-ANTERIOR",
"CONDITIONAL-PERFECT",
"PAST-SUBJUNCTIVE",
"PLUPERFECT-SUBJUNCTIVE",
"IMPERATIVE"
};
static char *punctuateLine();
static int askQuiz();
int
QuizStep_perform(self, temps)
QuizStep *self;
Collection *temps;
{
register int i;
static int lastTry;
int class;
Verb *verb;
Subject *subj;
Form *form;
ExtendString *text;
Association *op;
Association *lhs;
ExtendString line[256];
char *t;
int rc;
rc = PERFECT;
switch (self->type)
{
case STEP_VERB:
op = (Association *)Collection_atGet(self->detail, 1);
text = Association_getKey(op);
if (strcmp(text, "<random>") == 0)
{
class = ReportCard_pickClass(VerbScores);
verb = VerbSet_getOneFromClass(AllVerbs, class);
}
else
{
verb = VerbSet_getOneByName(AllVerbs, text);
class = Verb_getConjugationClass(verb);
}
lhs = (Association *)Collection_atGet(self->detail, 0);
Association_setValue(lhs, verb);
#if XDEBUG
printf("QuizStep_perform: verb: %s\n", Verb_infinitive(verb));
#endif
break;
case STEP_PSUBJ:
op = (Association *)Collection_atGet(self->detail, 1);
text = Association_getKey(op);
if (strcmp(text, "<random>") == 0)
{
subj = SubjectSet_getOneAtRandom(AllSubjects);
if (Collection_size(self->detail) > 2)
{
op = (Association *)Collection_atGet(self->detail, 2);
while (SAMEFORM(subj, (Subject *)Association_getValue(op)))
{
subj = SubjectSet_getOneAtRandom(AllSubjects);
}
}
}
else
{
subj = SubjectSet_getOneByName(AllSubjects, text);
}
lhs = (Association *)Collection_atGet(self->detail, 0);
Association_setValue(lhs, subj);
#if XDEBUG
printf("QuizStep_perform: subj: %s\n", Subject_getText(subj));
#endif
break;
case STEP_TEXTOF:
op = (Association *)Collection_atGet(self->detail, 1);
text = Subject_getText((Subject *)Association_getValue(op));
lhs = (Association *)Collection_atGet(self->detail, 0);
Association_setValue(lhs, text);
#if XDEBUG
printf("QuizStep_perform: text: %s\n", text);
#endif
break;
case STEP_CONJUGATE:
op = (Association *)Collection_atGet(self->detail, 2);
t = Association_getKey(op);
for (i = 0; i < N_OF_TENSES; i++)
{
if (0 == strcmp(tenses[i], t))
{
break;
}
}
if (i == N_OF_TENSES)
{
fprintf(stderr, "QuizStep_perform: unknown: %s\n", t);
i = TENSE_INFINITIVE;
}
if (i != TENSE_INFINITIVE)
{
op = (Association *)Collection_atGet(self->detail, 3);
form = Subject_getForm((Subject *)Association_getValue(op));
}
op = (Association *)Collection_atGet(self->detail, 1);
verb = Association_getValue(op);
text = Verb_conjugate(verb, form, i);
if (!text)
{
rc = FAILURE;
goto out;
}
Collection_add(temps, (char *)text);
lhs = (Association *)Collection_atGet(self->detail, 0);
Association_setValue(lhs, text);
#if XDEBUG
printf("QuizStep_perform: conjugate: %s\n", text);
#endif
break;
case STEP_QUIZ:
line[0] = '\0';
for (i = 0; i < Collection_size(self->detail); i++)
{
op = (Association *)Collection_atGet(self->detail, i);
text = (ExtendString *)Association_getValue(op);
if (text)
{
strcat(line, text);
continue;
}
text = (ExtendString *)Association_getKey(op);
if (text[0] == '{' || text[0] == '}')
{
strcat(line, text);
continue;
}
strcat(line, text + 1);
line[strlen(line) - 1] = '\0';
}
#if XDEBUG
printf("QuizStep_perform: line: %s\n", line);
#endif
t = punctuateLine(line);
lastTry = askQuiz(t);
break;
case STEP_SCORE:
op = (Association *)Collection_atGet(self->detail, 0);
verb = Association_getValue(op);
class = Verb_getConjugationClass(verb);
ReportCard_record(VerbScores, class, lastTry);
GotRight = lastTry ? PERFECT : FAILURE;
break;
default:
fprintf(stderr, "QuizStep_perform: unknown: %d\n", self->type);
rc = FAILURE;
break;
}
out:
return rc;
}
/* puncuateLine - A simple punctuator */
#define upperize(c) (islower(c) ? toupper(c) : (c))
static char *
punctuateLine(line)
char *line;
{
register int i, j;
static ExtendString *vowels;
static char result[256];
int preSentence;
int holdingBrace;
int alreadyGlommed;
int postEorI;
int preWord;
int length;
char c;
if (!vowels)
{
vowels = ExtendString_newFromString("AaEeE'e'IiOoUuHh");
}
preSentence = TRUE;
holdingBrace = FALSE;
alreadyGlommed = 0;
postEorI = FALSE;
length = 0;
j = 0;
for (i = 0; line[i]; i++)
{
c = line[i];
if (c == '{')
{
holdingBrace = TRUE;
continue;
}
if (c == ' ')
{
result[j++] = c;
preWord = TRUE;
alreadyGlommed -= 1;
length = 0;
continue;
}
if (preWord && postEorI && alreadyGlommed < 1)
{
if (strchr(vowels, c))
{
j -= 2;
result[j++] = '\'';
alreadyGlommed = 2;
if (holdingBrace)
{
result[j++] = '{';
holdingBrace = FALSE;
}
result[j++] = c;
preWord = FALSE;
continue;
}
}
length++;
preWord = FALSE;
postEorI = length < 4 && strchr("ei", c);
if (holdingBrace)
{
result[j++] = '{';
holdingBrace = FALSE;
}
if (preSentence)
{
result[j++] = upperize(c);
preSentence = FALSE;
continue;
}
result[j++] = c;
}
result[j] = '\0';
return result;
}
/* askQuiz */
int QuestionNumber = 0;
static int
askQuiz(line)
ExtendString *line;
{
register int i, j;
ExtendString blank[132];
ExtendString answer[132];
int lineLength;
char guess[80];
int spaceBack;
int tries;
/* Copy answer part of line to answer and blank it out */
lineLength = 0;
spaceBack = -1;
i = j = 0;
while (*line)
{
if (lineLength > 45 && spaceBack < 0 && *line == ' ')
{
line++;
lineLength = 0;
strcpy(&blank[j], "\n ");
j = j + 5;
continue;
}
if (*line == '{' && i == 0) /* hit start of answer section */
{
line++;
spaceBack = lineLength;
while (*line != '}') /* copy & blank up to end mark */
{
answer[i++] = *line++;
blank[j++] = '_';
lineLength++;
}
line++;
while (j % 5) /* add additional blanking */
{
blank[j++] = '_';
lineLength++;
}
}
blank[j++] = *line++;
lineLength++;
}
answer[i] = '\0';
blank[j] = '\0';
/* Present the blanked question until _notre ami_ gets it right */
QuestionNumber++;
tries = 1;
while (TRUE)
{
printf("%2d. ", QuestionNumber);
printf("%s", blank);
i = lineLength - spaceBack;
for (j = 0; j < i; j++)
{
printf("%c", '\b');
}
gets(guess);
if (ExtendString_compareSansAccent(answer, guess) == 0)
{
break;
}
tries++;
printf("\nMais non! C'est %c%s%c\n\n",
QUOTE_GAUCHE, answer, QUOTE_DROIGT);
}
return tries == 1; /* TRUE for right on first try */
}
/* QuizStep_destroy */
void
QuizStep_destroy(self)
QuizStep *self;
{
Collection_destroy(self->detail);
free(self);
}