home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume36 / formes / part02 / quizstep.c < prev    next >
C/C++ Source or Header  |  1993-04-01  |  12KB  |  614 lines

  1.  
  2. /*
  3.  *  Copyright (C) 1992-1993 Jeffrey Chilton
  4.  *
  5.  *  Permission is granted to anyone to make or distribute copies of
  6.  *  this program, in any medium, provided that the copyright notice
  7.  *  and permission notice are preserved, and that the distributor
  8.  *  grants the recipient permission for further redistribution as
  9.  *  permitted by this notice.
  10.  *  
  11.  *  Author's E-mail address:  172-9221@mcimail.com
  12.  *  
  13.  */
  14.  
  15. static char *whatstring = "@(#)quizstep.c    2.7 JWC";
  16.  
  17. #include <ctype.h>
  18. #include <stdio.h>
  19.  
  20. #include "class.h"
  21. #include "quizstep.h"
  22.  
  23. #include "assoc.h"
  24. #include "collect.h"
  25. #include "exstr.h"
  26. #include "subject.h"
  27. #include "subjset.h"
  28. #include "random.h"
  29. #include "report.h"
  30. #include "verb.h"
  31. #include "verbset.h"
  32.  
  33. extern Random *Squizzer;
  34. extern VerbSet *AllVerbs;
  35. extern SubjectSet *AllSubjects;
  36. extern ReportCard *VerbScores;
  37. extern int GotRight;
  38.  
  39. static int matchStep();
  40.  
  41. QuizStep *
  42. QuizStep_new()
  43. {
  44.     QuizStep *self;
  45.  
  46.     self = (QuizStep *)malloc(sizeof (QuizStep));
  47.     if (!self)
  48.     {
  49.     fprintf(stderr, "QuizStep_new: malloc fails\n");
  50.     goto out;
  51.     }
  52.  
  53.     self->detail = Collection_new(matchStep, NULLDESTROY);
  54.     if (!self->detail)
  55.     {
  56.     fprintf(stderr, "QuizStep_new: Collection_new fails\n");
  57.     self = (QuizStep *)0;
  58.     goto out;
  59.     }
  60.  
  61.     self->type = STEP_NONE;
  62.  
  63. out:
  64.  
  65.     return self;
  66.  
  67. }
  68.  
  69. static int
  70. matchStep(symbol, key)
  71. Association *symbol;
  72. char *key;
  73. {
  74.     return strcmp(Association_getKey(symbol), key);
  75. }
  76.  
  77.  
  78. char *Opers[N_STEPTYPES] =
  79. {
  80.     "NONE", "VERB", "PERSON", "TEXT-OF", "CONJUGATE", "QUIZ", "SCORE"
  81. };
  82.  
  83. void cutOneWord();
  84.  
  85. QuizStep *
  86. QuizStep_newFromString(string, symbols)
  87. char *string;
  88. Collection *symbols;
  89. {
  90.     register int i;
  91.     QuizStep *self;
  92.     char operation[32];
  93.     char detail[80];
  94.     char *start, *word;
  95.     char copy[80];
  96.     Association *sym;
  97.     ExtendString *t;
  98.     int length;
  99.     int rc;
  100.  
  101.     self = QuizStep_new();
  102.     if (!self)
  103.     {
  104.     fprintf(stderr, "QuizStep_newFromString: QuizStep_new fails\n");
  105.     goto out;
  106.     }
  107.  
  108.     sscanf(string, "%s %[^\n]", operation, detail);
  109.  
  110.     /* Look up step type */
  111.  
  112.     rc = FALSE;
  113.     for (i = STEP_VERB; i < N_STEPTYPES; i++)
  114.     {
  115.     if (0 == strcmp(operation, Opers[i]))
  116.     {
  117.         self->type = i;
  118.         rc = TRUE;
  119.         break;
  120.     }
  121.     }
  122.     if (!rc)
  123.     {
  124.     fprintf(stderr, "QuizStep_newFromString: unknown: %s\n", operation);
  125.     goto out;
  126.     }
  127.  
  128.     /* Parse detail section and look up symbols */
  129.  
  130.     start = &detail[0];
  131.     cutOneWord(&start, &word, &length);
  132.     while (word)
  133.     {
  134.     strncpy(copy, word, length);
  135.     copy[length] = '\0';
  136.  
  137.     sym = (Association *)Collection_atKeyGet(symbols, copy);
  138.     if (!sym)
  139.     {
  140.         t = ExtendString_newFromString(copy);
  141.         sym = Association_newWithKey(t);
  142.         Collection_add(symbols, sym);
  143.     }
  144.  
  145.     Collection_add(self->detail, (char *)sym);
  146.     cutOneWord(&start, &word, &length);
  147.     }
  148.  
  149. out:
  150.  
  151.     return self;
  152.  
  153. }
  154.  
  155. void
  156. cutOneWord(start, word, length)
  157. char **start;
  158. char **word;
  159. int *length;
  160. {
  161.     char *t, *u;
  162.  
  163.     t = *start;                /* skip over any leading spaces    */
  164.     while (*t == ' ' || *t == '>')
  165.     {
  166.     t++;
  167.     }
  168.     if (*t == '\0')            /* indicate done if at the end    */
  169.     {
  170.     *word = NULL;
  171.     goto out;
  172.     }
  173.  
  174.     if (*t == '<')            /* special case quoted text    */
  175.     {
  176.     u = t++;
  177.     while (*t && *t != '>')        /* which ends only on end quote    */
  178.     {
  179.         t++;
  180.     }
  181.     t++;
  182.     }
  183.     else if (*t == '{' || *t == '}')    /* or special case "{" & "}"    */
  184.     {
  185.     u = t++;
  186.     }
  187.     else                /* else end on "<", " ", or "}"    */
  188.     {
  189.     u = t++;
  190.     while (*t && *t != '<' && *t != ' ' && *t != '}')
  191.     {
  192.         t++;
  193.     }
  194.     }
  195.  
  196.     *word = u;                /* send out the results        */
  197.     *start = t;
  198.     *length = t - u;
  199.  
  200. out:
  201.  
  202.     return;
  203.  
  204. }
  205.  
  206. /* QuizStep_display - display one step */
  207.  
  208. int
  209. QuizStep_display(self)
  210. QuizStep *self;
  211. {
  212.     register int i;
  213.     Association *sym;
  214.  
  215.     printf("  %s: ", Opers[self->type]);
  216.     for (i = 0; i < Collection_size(self->detail); i++)
  217.     {
  218.     sym = (Association *)Collection_atGet(self->detail, i);
  219.     printf("%s(%x) ", Association_getKey(sym), Association_getValue(sym));
  220.     }
  221.     printf("\n");
  222.  
  223.     return PERFECT;
  224.  
  225. }
  226.  
  227. /* QuizStep_perform - do whatever this step does */
  228.  
  229. #define SAMEFORM(a, b) ( \
  230.     Form_isEquivalent(Subject_getForm(a), Subject_getForm(b)) \
  231.     )
  232.  
  233. char *tenses[N_OF_TENSES] = {
  234.     "INFINITIVE", 
  235.     "PRESENT", 
  236.     "IMPERFECT", 
  237.     "SIMPLE-PAST",
  238.     "FUTURE", 
  239.     "CONDITIONAL", 
  240.     "SUBJUNCTIVE", 
  241.     "IMPERFECT-SUBJUNCTIVE",
  242.     "PAST", 
  243.     "PLUPERFECT",
  244.     "PAST-ANTERIOR",
  245.     "FUTURE-ANTERIOR",
  246.     "CONDITIONAL-PERFECT",
  247.     "PAST-SUBJUNCTIVE",
  248.     "PLUPERFECT-SUBJUNCTIVE",
  249.     "IMPERATIVE"
  250.     };
  251.  
  252. static char *punctuateLine();
  253. static int askQuiz();
  254.  
  255. int
  256. QuizStep_perform(self, temps)
  257. QuizStep *self;
  258. Collection *temps;
  259. {
  260.     register int i;
  261.     static int lastTry;
  262.     int class;
  263.     Verb *verb;
  264.     Subject *subj;
  265.     Form *form;
  266.     ExtendString *text;
  267.     Association *op;
  268.     Association *lhs;
  269.     ExtendString line[256];
  270.     char *t;
  271.     int rc;
  272.  
  273.     rc = PERFECT;
  274.     switch (self->type)
  275.     {
  276.     case STEP_VERB:
  277.  
  278.         op = (Association *)Collection_atGet(self->detail, 1);
  279.         text = Association_getKey(op);
  280.         if (strcmp(text, "<random>") == 0)
  281.         {
  282.         class = ReportCard_pickClass(VerbScores);
  283.         verb = VerbSet_getOneFromClass(AllVerbs, class);
  284.         }
  285.         else
  286.         {
  287.         verb = VerbSet_getOneByName(AllVerbs, text);
  288.         class = Verb_getConjugationClass(verb);
  289.         }
  290.         lhs = (Association *)Collection_atGet(self->detail, 0);
  291.         Association_setValue(lhs, verb);
  292.  
  293. #if XDEBUG
  294. printf("QuizStep_perform: verb: %s\n", Verb_infinitive(verb));
  295. #endif
  296.  
  297.         break;
  298.  
  299.     case STEP_PSUBJ:
  300.  
  301.         op = (Association *)Collection_atGet(self->detail, 1);
  302.         text = Association_getKey(op);
  303.         if (strcmp(text, "<random>") == 0)
  304.         {
  305.         subj = SubjectSet_getOneAtRandom(AllSubjects);
  306.         if (Collection_size(self->detail) > 2)
  307.         {
  308.             op = (Association *)Collection_atGet(self->detail, 2);
  309.             while (SAMEFORM(subj, (Subject *)Association_getValue(op)))
  310.             {
  311.             subj = SubjectSet_getOneAtRandom(AllSubjects);
  312.             }
  313.         }
  314.         }
  315.         else
  316.         {
  317.         subj = SubjectSet_getOneByName(AllSubjects, text);
  318.         }
  319.         lhs = (Association *)Collection_atGet(self->detail, 0);
  320.         Association_setValue(lhs, subj);
  321.  
  322. #if XDEBUG
  323. printf("QuizStep_perform: subj: %s\n", Subject_getText(subj));
  324. #endif
  325.  
  326.         break;
  327.  
  328.     case STEP_TEXTOF:
  329.  
  330.         op = (Association *)Collection_atGet(self->detail, 1);
  331.         text = Subject_getText((Subject *)Association_getValue(op));
  332.         lhs = (Association *)Collection_atGet(self->detail, 0);
  333.         Association_setValue(lhs, text);
  334.  
  335. #if XDEBUG
  336. printf("QuizStep_perform: text: %s\n", text);
  337. #endif
  338.  
  339.         break;
  340.  
  341.     case STEP_CONJUGATE:
  342.  
  343.         op = (Association *)Collection_atGet(self->detail, 2);
  344.         t = Association_getKey(op);
  345.         for (i = 0; i < N_OF_TENSES; i++)
  346.         {
  347.         if (0 == strcmp(tenses[i], t))
  348.         {
  349.             break;
  350.         }
  351.         }
  352.         if (i == N_OF_TENSES)
  353.         {
  354.         fprintf(stderr, "QuizStep_perform: unknown: %s\n", t);
  355.         i = TENSE_INFINITIVE;
  356.         }
  357.         if (i != TENSE_INFINITIVE)
  358.         {
  359.         op = (Association *)Collection_atGet(self->detail, 3);
  360.         form = Subject_getForm((Subject *)Association_getValue(op));
  361.         }
  362.         op = (Association *)Collection_atGet(self->detail, 1);
  363.         verb = Association_getValue(op);
  364.         text = Verb_conjugate(verb, form, i);
  365.         if (!text)
  366.         {
  367.         rc = FAILURE;
  368.         goto out;
  369.         }
  370.         Collection_add(temps, (char *)text);
  371.         lhs = (Association *)Collection_atGet(self->detail, 0);
  372.         Association_setValue(lhs, text);
  373.  
  374. #if XDEBUG
  375. printf("QuizStep_perform: conjugate: %s\n", text);
  376. #endif
  377.  
  378.         break;
  379.  
  380.     case STEP_QUIZ:
  381.  
  382.         line[0] = '\0';
  383.         for (i = 0; i < Collection_size(self->detail); i++)
  384.         {
  385.         op = (Association *)Collection_atGet(self->detail, i);
  386.         text = (ExtendString *)Association_getValue(op);
  387.         if (text)
  388.         {
  389.             strcat(line, text);
  390.             continue;
  391.         }
  392.         text = (ExtendString *)Association_getKey(op);
  393.         if (text[0] == '{' || text[0] == '}')
  394.         {
  395.             strcat(line, text);
  396.             continue;
  397.         }
  398.         strcat(line, text + 1);
  399.         line[strlen(line) - 1] = '\0';
  400.         }
  401.  
  402. #if XDEBUG
  403. printf("QuizStep_perform: line: %s\n", line);
  404. #endif
  405.  
  406.         t = punctuateLine(line);
  407.         lastTry = askQuiz(t);
  408.         break;
  409.  
  410.     case STEP_SCORE:
  411.  
  412.         op = (Association *)Collection_atGet(self->detail, 0);
  413.         verb = Association_getValue(op);
  414.         class = Verb_getConjugationClass(verb);
  415.         ReportCard_record(VerbScores, class, lastTry);
  416.         GotRight = lastTry ? PERFECT : FAILURE;
  417.         break;
  418.  
  419.     default:
  420.  
  421.         fprintf(stderr, "QuizStep_perform: unknown: %d\n", self->type);
  422.         rc = FAILURE;
  423.         break;
  424.  
  425.     }
  426.  
  427. out:
  428.  
  429.     return rc;
  430.  
  431. }
  432.  
  433. /* puncuateLine - A simple punctuator */
  434.  
  435. #define upperize(c) (islower(c) ? toupper(c) : (c))
  436.  
  437. static char *
  438. punctuateLine(line)
  439. char *line;
  440. {
  441.     register int i, j;
  442.     static ExtendString *vowels;
  443.     static char result[256];
  444.     int preSentence;
  445.     int holdingBrace;
  446.     int alreadyGlommed;
  447.     int postEorI;
  448.     int preWord;
  449.     int length;
  450.     char c;
  451.  
  452.     if (!vowels)
  453.     {
  454.     vowels = ExtendString_newFromString("AaEeE'e'IiOoUuHh");
  455.     }
  456.  
  457.     preSentence = TRUE;
  458.     holdingBrace = FALSE;
  459.     alreadyGlommed = 0;
  460.     postEorI = FALSE;
  461.     length = 0;
  462.  
  463.     j = 0;
  464.     for (i = 0; line[i]; i++)
  465.     {
  466.     c = line[i];
  467.     if (c == '{')
  468.     {
  469.         holdingBrace = TRUE;
  470.         continue;
  471.     }
  472.     if (c == ' ')
  473.     {
  474.         result[j++] = c;
  475.         preWord = TRUE;
  476.         alreadyGlommed -= 1;
  477.         length = 0;
  478.         continue;
  479.     }
  480.     if (preWord && postEorI && alreadyGlommed < 1)
  481.     {
  482.         if (strchr(vowels, c))
  483.         {
  484.         j -= 2;
  485.         result[j++] = '\'';
  486.         alreadyGlommed = 2;
  487.         if (holdingBrace)
  488.         {
  489.             result[j++] = '{';
  490.             holdingBrace = FALSE;
  491.         }
  492.         result[j++] = c;
  493.         preWord = FALSE;
  494.         continue;
  495.         }
  496.     }
  497.     length++;
  498.     preWord = FALSE;
  499.     postEorI = length < 4 && strchr("ei", c);
  500.     if (holdingBrace)
  501.     {
  502.         result[j++] = '{';
  503.         holdingBrace = FALSE;
  504.     }
  505.     if (preSentence)
  506.     {
  507.         result[j++] = upperize(c);
  508.         preSentence = FALSE;
  509.         continue;
  510.     }
  511.     result[j++] = c;
  512.     }
  513.  
  514.     result[j] = '\0';
  515.  
  516.     return result;
  517.  
  518. }
  519.  
  520. /* askQuiz */
  521.  
  522. int QuestionNumber = 0;
  523.  
  524. static int
  525. askQuiz(line)
  526. ExtendString *line;
  527. {
  528.     register int i, j;
  529.     ExtendString blank[132];
  530.     ExtendString answer[132];
  531.     int lineLength;
  532.     char guess[80];
  533.     int spaceBack;
  534.     int tries;
  535.  
  536.     /* Copy answer part of line to answer and blank it out */
  537.  
  538.     lineLength = 0;
  539.     spaceBack = -1;
  540.     i = j = 0;
  541.     while (*line)
  542.     {
  543.     if (lineLength > 45 && spaceBack < 0 && *line == ' ')
  544.     {
  545.         line++;
  546.         lineLength = 0;
  547.         strcpy(&blank[j], "\n    ");
  548.         j = j + 5;
  549.         continue;
  550.     }
  551.     if (*line == '{' && i == 0)    /* hit start of answer section    */
  552.     {
  553.         line++;
  554.         spaceBack = lineLength;
  555.         while (*line != '}')    /* copy & blank up to end mark    */
  556.         {
  557.         answer[i++] = *line++;
  558.         blank[j++] = '_';
  559.         lineLength++;
  560.         }
  561.         line++;
  562.         while (j % 5)        /* add additional blanking    */
  563.         {
  564.         blank[j++] = '_';
  565.         lineLength++;
  566.         }
  567.     }
  568.     blank[j++] = *line++;
  569.     lineLength++;
  570.     }
  571.     answer[i] = '\0';
  572.     blank[j] = '\0';
  573.  
  574.     /* Present the blanked question until _notre ami_ gets it right */
  575.  
  576.     QuestionNumber++;
  577.     tries = 1;
  578.     while (TRUE)
  579.     {
  580.     printf("%2d. ", QuestionNumber);
  581.     printf("%s", blank);
  582.     i = lineLength - spaceBack;
  583.     for (j = 0; j < i; j++)
  584.     {
  585.         printf("%c", '\b');
  586.     }
  587.  
  588.     gets(guess);
  589.  
  590.     if (ExtendString_compareSansAccent(answer, guess) == 0)
  591.     {
  592.         break;
  593.     }
  594.  
  595.     tries++;
  596.     printf("\nMais non! C'est %c%s%c\n\n",
  597.         QUOTE_GAUCHE, answer, QUOTE_DROIGT);
  598.     }
  599.  
  600.     return tries == 1;            /* TRUE for right on first try    */
  601.  
  602. }
  603.  
  604. /* QuizStep_destroy */
  605.  
  606. void
  607. QuizStep_destroy(self)
  608. QuizStep *self;
  609. {
  610.     Collection_destroy(self->detail);
  611.     free(self);
  612. }
  613.  
  614.