home *** CD-ROM | disk | FTP | other *** search
/ 350 Great Games / 350GamesWindows31.iso / 350games / programs / glchess / q-a.arc / QA.C < prev    next >
Text File  |  1986-08-18  |  10KB  |  321 lines

  1. /*
  2.  * qa.c v 1.0                              james bumgardner 6/86
  3.  *                                         voice: 818-766-0594
  4.  * (Microsoft C)
  5.  *
  6.  *       A simple expert system interpreter
  7.  *      
  8.  * Description
  9.  * 
  10.  * This program constructs a binary tree using the data contained in a text
  11.  * file.  It then queries the user for directions for traversing the tree.
  12.  * This technique can be used for designing simple expert systems, or games.
  13.  * 
  14.  * The best way to see how the trees work is to examine the tree files that
  15.  * are included in this package.  Each node starts with a comment (*) and
  16.  * ends with a symbol indicating which type of node it is. Generally, each
  17.  * node contains either a multiple choice question with single letter
  18.  * responses, or a solution.  Each response points to a child node in the
  19.  * tree which contains either a new question or solution. Child nodes are
  20.  * indented. 
  21.  * 
  22.  * Multiple Choice (>)
  23.  * 
  24.  * A multiple choice node contains lines of text (usually a screenful or
  25.  * less) followed by the directive ">" and the appropriate answers
  26.  * (e.g. ">YN").
  27.  * The number of answers is unlimited, but it is best to use fewer than 16.
  28.  * 
  29.  * Solution (!)
  30.  * 
  31.  * A solution is a node without any children.  Upon reaching a solution, QA
  32.  * diplays the text and says "Hit any key to continue".  The user is then put
  33.  * back on the root node.
  34.  * 
  35.  * Comment (*)
  36.  * 
  37.  * Generally, each node area in the text file starts with an asterisk character
  38.  * followed by the title for the node. This is the single letter response used 
  39.  * to reach the node.  (The root node has a dummy title of Y).  These comments
  40.  * are not required, but are useful for debugging.  You can use the debug
  41.  * option to make sure that the tree loads in correctly. For each node
  42.  * loaded, it shows the expected title followed by the comment. 
  43.  * 
  44.  * Backtracking (^)
  45.  * 
  46.  * When constructing trees you will find that some answers or sub-trees recurr
  47.  * often.  You can have more than one node backtrack into the same area using
  48.  * a backtrack node.  When hit, the qa routine will backrack once (up to the
  49.  * parent), and then follow the backtrack directions as if they were entered at
  50.  * the keyboard. For example, the directive "^//YN" will backtrack thrice, and
  51.  * then answer Yes, No.
  52.  * 
  53.  * Random forking (~)
  54.  * 
  55.  * You can design games by using the Random fork node to create random responses
  56.  * to questions.  A random fork node is like a multiple choice node, except
  57.  * no question is asked, instead, one of the answers is automatically
  58.  * chosen. Currently, each of the children of a random fork has an equal
  59.  * chance of getting chosen, but you can modify the source code to allow
  60.  * for greater control.  You are limited to 16 children for each random node.
  61.  *
  62.  * Chaining ($)
  63.  *
  64.  * You can keep individual sub-trees in different files.  Use the chaining
  65.  * directive to have QA combine files into one tree.
  66.  *
  67.  */
  68.  
  69. #include "stdio.h"
  70. #include "ctype.h"
  71.  
  72. #define BS      8
  73. #define RET     13
  74. #define CTRLZ   26
  75. #define ESC     27
  76. #define HOME    327
  77. #define UP      328
  78. #define LEFT    331
  79. #define END     335
  80. #define    F1      315
  81.  
  82. #define NODE    struct node
  83.  
  84. struct node {
  85.         char nam,typ,*txt;
  86.         struct node *sib,*kid;
  87. } *read_node();
  88.  
  89. int debug,lvl;
  90. char *kptr = "";
  91. char *malloc();
  92.  
  93. main(argc,argv)
  94. char *argv[];
  95. {
  96.         FILE *ifile;
  97.         NODE *tnode;
  98.         if (argc != 2 && argc != 3)     {
  99.                 printf("\nSyntax: QA expert_file [debug]\n");
  100.                 exit();
  101.         }
  102.         debug = (argc == 3);
  103.         if ((ifile = fopen(argv[1],"r")) == NULL) {
  104.                 printf("Can't open %s for input\n",argv[1]);
  105.                 exit();
  106.         }
  107.         printf("\nOne moment please...");
  108.         lvl = 0;
  109.         tnode = read_node("Y",ifile);   /* dummy parent */
  110.         fclose(ifile);
  111.         while (1)
  112.                 ask_node('Y',tnode);
  113. }
  114.  
  115. NODE *read_node(sibs,ifile)     /* recursive tree loading function */
  116. char *sibs;
  117. FILE *ifile;
  118. {
  119.         /* static vars */
  120.         static char in_buffer[256],*ip;
  121.         static int *tp,x;
  122.         /* recursive vars */
  123.         FILE *cfile;
  124.         NODE *nod;
  125.         char choices[20];
  126.  
  127.         if (*sibs == '\0')
  128.                 return(NULL);
  129.         nod = (NODE *) malloc(sizeof(NODE));
  130.         nod->nam = *sibs;
  131.         nod->typ = '\0';
  132.         nod->kid = nod->sib = NULL;
  133.         if (debug)      {
  134.                 for (x = 0; x < lvl; ++x)
  135.                         printf("    ");
  136.                 printf("Expecting %c   Got ",nod->nam);
  137.         }
  138.         tp = (int *) &nod->txt;
  139.         while (nod->typ == '\0')        {
  140.                 *tp = NULL;
  141.                 if ((ip = fgets(in_buffer,255,ifile)) == NULL)  {
  142.                         printf("\nUnexpected EOF");
  143.                         exit();
  144.                 }
  145.                 while (isspace(*ip))    /* trim leading space */
  146.                         ip++;
  147.                 switch (*ip)    {
  148.                 case '!':       /* solution */
  149.                         nod->typ = *ip;
  150.                         break;
  151.                 case '~':       /* auto mutliple choice */
  152.                 case '>':       /* multiple choice */
  153.                         nod->typ = *ip;
  154.                         trim(ip);
  155.                         strcpy(choices,++ip);
  156.                         ++lvl;
  157.                         nod->kid = read_node(choices,ifile);
  158.                         --lvl;
  159.                         break;
  160.                 case '$':       /* chain */
  161.                         free(nod);
  162.                         trim(ip);
  163.                         ++ip;
  164.                         if ((cfile = fopen(ip,"r")) == NULL) {
  165.                                 printf("Can't open subfile %s for input.\n",ip);
  166.  
  167.                                 exit();
  168.                         }
  169.                         printf(".");
  170.                         nod = read_node("Y",cfile);
  171.                         nod->nam = *sibs;
  172.                         fclose(cfile);
  173.                         break;
  174.                 case '^':       /* back track */
  175.                         nod->typ = *ip;
  176.                         trim(ip);
  177.                         nod->txt = malloc(strlen(ip));
  178.                         strcpy(nod->txt,++ip);
  179.                         break;
  180.                 case '*':       /* comment */
  181.                         if (debug)
  182.                                 fputs(ip,stdout);
  183.                         break;
  184.                 default:        /* text */
  185.                         *tp = (int) malloc(strlen(in_buffer) + 5);
  186.                         strcpy(*tp + 4,in_buffer);
  187.                         tp = (int *) *tp;
  188.                         break;
  189.                 }
  190.         }
  191.         nod->sib = read_node(++sibs,ifile);
  192.         return(nod);
  193. }
  194.  
  195. ask_node(chc,nod)       /* recursive question/answer function */
  196. char chc;
  197. NODE *nod;
  198. {
  199.         static int c,flg;
  200.         static char tmpstr[17];
  201.  
  202.         if (chc != nod->nam)    {
  203.                 if (nod->sib == NULL)
  204.                         return(FALSE);
  205.                 return(ask_node(chc,nod->sib));
  206.         }
  207.         do      {
  208.                 if (nod->typ == '^')    {
  209.                         kptr = nod->txt;
  210.                         return(FALSE);
  211.                 }
  212.                 if (*kptr == '\0')      {
  213.                         switch (nod->typ)       {
  214.                         case '!':
  215.                                 c = getkey(&nod->txt,"Hit any key to continue: ");
  216.                                 break;
  217.                         case '>':
  218.                                 c = getkey(&nod->txt,"? ");
  219.                                 break;
  220.                         case '~':
  221.                                 read_sibs(nod->kid,tmpstr);
  222.                                 c = tmpstr[rnd(strlen(tmpstr))];
  223.                                 break;
  224.                         }
  225.                 }
  226.                 else
  227.                         c = *kptr++;
  228.                 switch (c)      {
  229.         case END:
  230.                 case CTRLZ:        exit();
  231.                 case '/':
  232.                 case BS:
  233.         case LEFT:
  234.         case UP:    return(FALSE);
  235.         case F1:
  236.         case HOME:
  237.                 case ESC:        return(TRUE);
  238.                 }
  239.                 switch (nod->typ)       {
  240.                 case '>':       flg = ask_node(c,nod->kid) == FALSE; break;
  241.                 case '~':       ask_node(c,nod->kid); /* no break */
  242.                 default:        flg = FALSE;
  243.                 }
  244.         } while (flg);
  245.         return(TRUE);
  246. }
  247.  
  248. /*
  249.  * misc functions
  250.  */
  251.  
  252. trim(str)               /* trim white space */
  253. char *str;
  254. {
  255.         static char *p;
  256.         p = str + strlen(str) - 1;
  257.         while (isspace(*p))
  258.                 *p-- = '\0';
  259. }
  260.  
  261. getkey(tp,str)
  262. int *tp;
  263. char *str;
  264. {
  265.         static int c;
  266.         for (; *tp; tp = (int *) *tp)
  267.                 printf(*tp + 4);
  268.         printf("\n\n");
  269.         cprintf(str);
  270.     c = gchar();
  271.         if (isprint(c))
  272.                 printf("%c",c);
  273.     printf("\n\n");
  274.         return(toupper(c));
  275. }
  276.  
  277. read_sibs(nod,p)
  278. NODE *nod;
  279. char *p;
  280. {
  281.         if (nod)        {
  282.                 *p = nod->nam;
  283.                 read_sibs(nod->sib,++p);
  284.         }
  285.         else
  286.                 *p = '\0';
  287. }
  288.  
  289. gchar()
  290. {
  291.     static int c;
  292.     while (bdos(0x0B,00) == 0)
  293.         ;
  294.     if (c = bdos(0x06,0xFF))
  295.         return(c);
  296.     else
  297.         return(256 | bdos(0x06,0xFF));
  298. }
  299.  
  300. /* random function (could be improved...) */
  301.  
  302. #define PI    0.141592653897
  303. double seed = 0.0,randomize();
  304.  
  305. rnd(n) /* return random integer from 0 to n-1 */
  306. {
  307.         if (seed == 0.0)        seed = randomize();
  308.         seed *= 7789.0;
  309.         seed -= (int) seed;
  310.         return(seed * n);
  311. }
  312.  
  313. double randomize()
  314. {
  315.     static char ireg[8] = {0,0x2C,0,0,0,0,0,0};
  316.     static char oreg[8];
  317.     sysint(0x21,&ireg,&oreg);
  318.     return(PI + PI / *((int *) &oreg[6]));
  319. }
  320.  
  321.