home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
350 Great Games
/
350GamesWindows31.iso
/
350games
/
programs
/
glchess
/
q-a.arc
/
QA.C
< prev
next >
Wrap
Text File
|
1986-08-18
|
10KB
|
321 lines
/*
* qa.c v 1.0 james bumgardner 6/86
* voice: 818-766-0594
* (Microsoft C)
*
* A simple expert system interpreter
*
* Description
*
* This program constructs a binary tree using the data contained in a text
* file. It then queries the user for directions for traversing the tree.
* This technique can be used for designing simple expert systems, or games.
*
* The best way to see how the trees work is to examine the tree files that
* are included in this package. Each node starts with a comment (*) and
* ends with a symbol indicating which type of node it is. Generally, each
* node contains either a multiple choice question with single letter
* responses, or a solution. Each response points to a child node in the
* tree which contains either a new question or solution. Child nodes are
* indented.
*
* Multiple Choice (>)
*
* A multiple choice node contains lines of text (usually a screenful or
* less) followed by the directive ">" and the appropriate answers
* (e.g. ">YN").
* The number of answers is unlimited, but it is best to use fewer than 16.
*
* Solution (!)
*
* A solution is a node without any children. Upon reaching a solution, QA
* diplays the text and says "Hit any key to continue". The user is then put
* back on the root node.
*
* Comment (*)
*
* Generally, each node area in the text file starts with an asterisk character
* followed by the title for the node. This is the single letter response used
* to reach the node. (The root node has a dummy title of Y). These comments
* are not required, but are useful for debugging. You can use the debug
* option to make sure that the tree loads in correctly. For each node
* loaded, it shows the expected title followed by the comment.
*
* Backtracking (^)
*
* When constructing trees you will find that some answers or sub-trees recurr
* often. You can have more than one node backtrack into the same area using
* a backtrack node. When hit, the qa routine will backrack once (up to the
* parent), and then follow the backtrack directions as if they were entered at
* the keyboard. For example, the directive "^//YN" will backtrack thrice, and
* then answer Yes, No.
*
* Random forking (~)
*
* You can design games by using the Random fork node to create random responses
* to questions. A random fork node is like a multiple choice node, except
* no question is asked, instead, one of the answers is automatically
* chosen. Currently, each of the children of a random fork has an equal
* chance of getting chosen, but you can modify the source code to allow
* for greater control. You are limited to 16 children for each random node.
*
* Chaining ($)
*
* You can keep individual sub-trees in different files. Use the chaining
* directive to have QA combine files into one tree.
*
*/
#include "stdio.h"
#include "ctype.h"
#define BS 8
#define RET 13
#define CTRLZ 26
#define ESC 27
#define HOME 327
#define UP 328
#define LEFT 331
#define END 335
#define F1 315
#define NODE struct node
struct node {
char nam,typ,*txt;
struct node *sib,*kid;
} *read_node();
int debug,lvl;
char *kptr = "";
char *malloc();
main(argc,argv)
char *argv[];
{
FILE *ifile;
NODE *tnode;
if (argc != 2 && argc != 3) {
printf("\nSyntax: QA expert_file [debug]\n");
exit();
}
debug = (argc == 3);
if ((ifile = fopen(argv[1],"r")) == NULL) {
printf("Can't open %s for input\n",argv[1]);
exit();
}
printf("\nOne moment please...");
lvl = 0;
tnode = read_node("Y",ifile); /* dummy parent */
fclose(ifile);
while (1)
ask_node('Y',tnode);
}
NODE *read_node(sibs,ifile) /* recursive tree loading function */
char *sibs;
FILE *ifile;
{
/* static vars */
static char in_buffer[256],*ip;
static int *tp,x;
/* recursive vars */
FILE *cfile;
NODE *nod;
char choices[20];
if (*sibs == '\0')
return(NULL);
nod = (NODE *) malloc(sizeof(NODE));
nod->nam = *sibs;
nod->typ = '\0';
nod->kid = nod->sib = NULL;
if (debug) {
for (x = 0; x < lvl; ++x)
printf(" ");
printf("Expecting %c Got ",nod->nam);
}
tp = (int *) &nod->txt;
while (nod->typ == '\0') {
*tp = NULL;
if ((ip = fgets(in_buffer,255,ifile)) == NULL) {
printf("\nUnexpected EOF");
exit();
}
while (isspace(*ip)) /* trim leading space */
ip++;
switch (*ip) {
case '!': /* solution */
nod->typ = *ip;
break;
case '~': /* auto mutliple choice */
case '>': /* multiple choice */
nod->typ = *ip;
trim(ip);
strcpy(choices,++ip);
++lvl;
nod->kid = read_node(choices,ifile);
--lvl;
break;
case '$': /* chain */
free(nod);
trim(ip);
++ip;
if ((cfile = fopen(ip,"r")) == NULL) {
printf("Can't open subfile %s for input.\n",ip);
exit();
}
printf(".");
nod = read_node("Y",cfile);
nod->nam = *sibs;
fclose(cfile);
break;
case '^': /* back track */
nod->typ = *ip;
trim(ip);
nod->txt = malloc(strlen(ip));
strcpy(nod->txt,++ip);
break;
case '*': /* comment */
if (debug)
fputs(ip,stdout);
break;
default: /* text */
*tp = (int) malloc(strlen(in_buffer) + 5);
strcpy(*tp + 4,in_buffer);
tp = (int *) *tp;
break;
}
}
nod->sib = read_node(++sibs,ifile);
return(nod);
}
ask_node(chc,nod) /* recursive question/answer function */
char chc;
NODE *nod;
{
static int c,flg;
static char tmpstr[17];
if (chc != nod->nam) {
if (nod->sib == NULL)
return(FALSE);
return(ask_node(chc,nod->sib));
}
do {
if (nod->typ == '^') {
kptr = nod->txt;
return(FALSE);
}
if (*kptr == '\0') {
switch (nod->typ) {
case '!':
c = getkey(&nod->txt,"Hit any key to continue: ");
break;
case '>':
c = getkey(&nod->txt,"? ");
break;
case '~':
read_sibs(nod->kid,tmpstr);
c = tmpstr[rnd(strlen(tmpstr))];
break;
}
}
else
c = *kptr++;
switch (c) {
case END:
case CTRLZ: exit();
case '/':
case BS:
case LEFT:
case UP: return(FALSE);
case F1:
case HOME:
case ESC: return(TRUE);
}
switch (nod->typ) {
case '>': flg = ask_node(c,nod->kid) == FALSE; break;
case '~': ask_node(c,nod->kid); /* no break */
default: flg = FALSE;
}
} while (flg);
return(TRUE);
}
/*
* misc functions
*/
trim(str) /* trim white space */
char *str;
{
static char *p;
p = str + strlen(str) - 1;
while (isspace(*p))
*p-- = '\0';
}
getkey(tp,str)
int *tp;
char *str;
{
static int c;
for (; *tp; tp = (int *) *tp)
printf(*tp + 4);
printf("\n\n");
cprintf(str);
c = gchar();
if (isprint(c))
printf("%c",c);
printf("\n\n");
return(toupper(c));
}
read_sibs(nod,p)
NODE *nod;
char *p;
{
if (nod) {
*p = nod->nam;
read_sibs(nod->sib,++p);
}
else
*p = '\0';
}
gchar()
{
static int c;
while (bdos(0x0B,00) == 0)
;
if (c = bdos(0x06,0xFF))
return(c);
else
return(256 | bdos(0x06,0xFF));
}
/* random function (could be improved...) */
#define PI 0.141592653897
double seed = 0.0,randomize();
rnd(n) /* return random integer from 0 to n-1 */
{
if (seed == 0.0) seed = randomize();
seed *= 7789.0;
seed -= (int) seed;
return(seed * n);
}
double randomize()
{
static char ireg[8] = {0,0x2C,0,0,0,0,0,0};
static char oreg[8];
sysint(0x21,&ireg,&oreg);
return(PI + PI / *((int *) &oreg[6]));
}