home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / CLIPPER / MISC / CONSULTP.ZIP / CONSULT.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-06-24  |  22.8 KB  |  863 lines

  1. {$R-}    {Range checking off}
  2. {$B+}    {Boolean complete evaluation on}
  3. {$S+}    {Stack checking on}
  4. {$I+}    {I/O checking on}
  5. {$N-}    {No numeric coprocessor}
  6. {$M 65500,16384,655360} {Turbo 3 default stack and heap}
  7.  
  8. PROGRAM Consult(Input,Output,rules,dbase);
  9.  
  10.  
  11. Uses
  12.   Crt,
  13.   Dos,
  14.   Turbo3,Library;
  15.  
  16.  
  17. CONST
  18.    WORD_MAX=80;
  19.    LINE_MAX=127;
  20.    COLON=':';
  21.    PERIOD='.';
  22.    COMMA=',';
  23.    SPACE=' ';
  24.    EQUALS='=';
  25.    DEFINITE=100;
  26. TYPE
  27.    word_string=string[Word_Max];
  28.    line_string=string[Line_Max];
  29.    infile_string=string[14];
  30.    value_ptr=^value;
  31.    legal_ptr=^legal_value;
  32.    object_ptr=^object;
  33.  
  34.    value = RECORD
  35.              name : word_string;
  36.              cert : integer;
  37.              setby : word_string;
  38.              next : value_ptr
  39.              END;
  40.  
  41.    legal_value = RECORD
  42.              name : word_string;
  43.              next : legal_ptr
  44.              END;
  45.  
  46.    object = RECORD
  47.              name : word_string;
  48.              question : line_string;
  49.              multivald : boolean;
  50.              legal_list : legal_ptr;
  51.              sought : boolean;
  52.              value_list : value_ptr;
  53.              next : object_ptr
  54.              END;
  55.  
  56.    prem_ptr = ^prem;
  57.    con_ptr = ^con;
  58.    rule_ptr = ^rule;
  59.  
  60.    prem = RECORD
  61.              object : word_string;
  62.              value : word_string;
  63.              next : prem_ptr
  64.              END;
  65.  
  66.    con = RECORD
  67.              object : word_string;
  68.              value : word_string;
  69.              cert : integer;
  70.              next : con_ptr
  71.              END;
  72.  
  73.    rule = RECORD
  74.              name : word_string;
  75.              prem : prem_ptr;
  76.              con : con_ptr;
  77.              next : rule_ptr
  78.              END;
  79. VAR
  80.     choice, max_choice, choice_lim : integer;
  81.     last_try,top_fact: object_ptr;
  82.     s_word, s_object, s_value : word_string;
  83.     s_line : line_string;
  84.     datfile : infile_string;
  85.     s_cf : integer;
  86.     top_rule : rule_ptr;
  87.     rules : Text;
  88.     explain : boolean;
  89.     another : boolean;
  90.     ok : boolean;
  91.  
  92. Procedure Wait;
  93.  
  94. Var
  95.    Ch : Char;
  96.  
  97. begin
  98.      Off;
  99.      write('Press any key to continue...');
  100.      Read(kbd,ch);
  101.      On;
  102. end;
  103.  
  104. Function DressUp(f_object:word_string):word_string;
  105. var
  106.    Hit : Integer;
  107.    Dressed : word_string;
  108.  
  109. begin
  110.      For Hit := 1 to length(f_object) do
  111.      if f_object[Hit] = #95 then f_object[Hit] := #32;
  112.      DressUp :=f_object;
  113.  
  114. end;
  115. PROCEDURE make_node(VAR curr_object: object_ptr);
  116.     VAR
  117.       head : object_ptr;
  118.     BEGIN
  119.       new(curr_object);
  120.       head:=top_fact;
  121.       top_fact:=curr_object;
  122.       WITH curr_object^ DO
  123.         Begin
  124.           next:=head;
  125.           value_list:=NIL;
  126.           question:='';
  127.           legal_list:=NIL;
  128.           multivald:=FALSE;
  129.           sought:=FALSE
  130.         end
  131.     END;
  132.  
  133.  
  134. FUNCTION find_object(f_object: word_string):object_ptr;
  135.   VAR
  136.     curr_object:object_ptr;
  137.   BEGIN
  138.     IF (last_try<>NIL) AND (last_try^.name=f_object)
  139.       THEN find_object:=last_try
  140.     ELSE
  141.       begin
  142.         curr_object:=top_fact;
  143.         last_try:=NIL;
  144.         find_object:=NIL;
  145.         WHILE ((curr_object<>NIL) AND (last_try=NIL)) DO
  146.           begin
  147.             IF (curr_object^.name=f_object) THEN
  148.               begin
  149.                 find_object:=curr_object;
  150.                 last_try:=curr_object
  151.               end;
  152.             curr_object:=curr_object^.next
  153.           end
  154.       end
  155.   END;
  156.  
  157. PROCEDURE split(f_line:line_string; VAR f_object,f_value:word_string);
  158.   VAR
  159.    st_left,st_right : integer;
  160.   BEGIN
  161.     st_right:=pos(PERIOD,f_line);
  162.     IF (st_right=length(f_line)) THEN f_line:=copy(f_line,1,st_right-1);
  163.     st_left:=pos(EQUALS,f_line);
  164.     st_right:=pos(COMMA,f_line);
  165.     IF ((st_left=0) AND (st_right=0)) THEN f_object:=f_line;
  166.     IF (st_right=0) THEN st_right:=length(f_line)+1;
  167.     IF (st_left>0) THEN
  168.       Begin
  169.         f_object:=copy(f_line,1,st_left-1);
  170.         IF (pos(')',f_object)=0) THEN
  171.           f_value:=copy(f_line,st_left+1,st_right-st_left-1)
  172.       End;
  173.     st_right:=pos(')',f_object);
  174.     IF (st_right>0) THEN f_object:=copy(f_line,1,st_right-1)
  175.   END;
  176.  
  177. FUNCTION test(f_object,f_value:word_string) :value_ptr;
  178.     VAR
  179.       curr_object : object_ptr;
  180.       curr_value : value_ptr;
  181.     BEGIN
  182.       curr_object:=find_object(f_object);
  183.       test:=NIL;
  184.       IF (curr_object <> NIL) THEN
  185.         begin
  186.           curr_value := curr_object^.value_list;
  187.           WHILE (curr_value<>NIL) DO
  188.             begin
  189.              IF (curr_value^.name=f_value) THEN test:=curr_value;
  190.              curr_value:=curr_value^.next
  191.             end
  192.         end
  193.     END;
  194.  
  195. PROCEDURE add_object(f_object,f_value:word_string);
  196.     VAR
  197.       curr_object : object_ptr;
  198.       value_list, head : value_ptr;
  199.     BEGIN
  200.       curr_object:=find_object(f_object);
  201.       IF (curr_object=NIL) THEN make_node(curr_object);
  202.       curr_object^.name := f_object;
  203.       curr_object^.sought:=TRUE;
  204.       value_list:=test(f_object,f_value);
  205.       IF (value_list = NIL) THEN
  206.         begin
  207.           head:=curr_object^.value_list;
  208.           new(value_list);
  209.           WITH value_list^ DO
  210.              begin
  211.                next:=head;
  212.                cert:=0;
  213.                setby:='';
  214.                name:=f_value
  215.              end;
  216.           curr_object^.value_list:=value_list
  217.         end
  218.     END;
  219.  
  220. PROCEDURE see_vals(curr_object: object_ptr);
  221.    VAR
  222.      curr_value : value_ptr;
  223.      cf: integer;
  224.    BEGIN
  225.      curr_value:=curr_object^.value_list;
  226.      write('The answer to ',UpperCase(DressUp(curr_object^.name)),' is ');
  227.      IF (curr_value=NIL) THEN write ('Undefined');
  228.      WHILE (curr_value<>NIL) DO
  229.        begin
  230.          write(UpperCase(DressUp(curr_value^.name)),'. ');
  231.          cf:=curr_value^.cert;
  232.          write(' Degree of certainty is ',cf,'.');
  233.          curr_value:=curr_value^.next;
  234.          IF (curr_value<>NIL) THEN write(',')
  235.        end;
  236.      writeln
  237.    END;
  238.  
  239. PROCEDURE see_objects;
  240.    VAR
  241.      curr_object : object_ptr;
  242.    BEGIN
  243.      writeln;
  244.      writeln('KNOWLEDGE BASE FACTS:');
  245.      writeln;
  246.      curr_object:=top_fact;
  247.      WHILE (curr_object<>NIL) DO
  248.        begin
  249.          see_vals(curr_object);
  250.          curr_object:=curr_object^.next
  251.        end;
  252.      writeln;
  253.      writeln('(END OF KNOWLEDGE BASE)')
  254.    END;
  255.  
  256. PROCEDURE clean;
  257.    VAR
  258.      curr_object : object_ptr;
  259.    BEGIN
  260.      curr_object:=top_fact;
  261.      WHILE (curr_object<>NIL) DO
  262.        begin
  263.          curr_object^.sought:=FALSE;
  264.          curr_object^.value_list:=NIL;
  265.          curr_object:=curr_object^.next
  266.        end;
  267.    END;
  268.  
  269.  
  270.  
  271. FUNCTION get_cf(f_line:line_string):integer;
  272.   VAR
  273.     result,st_right,cf : integer;
  274.     trim : line_string;
  275.   BEGIN
  276.     cf:=DEFINITE;
  277.     st_right:=pos(PERIOD,f_line);
  278.     IF st_right=length(f_line) THEN f_line:=copy(f_line,1,st_right-1);
  279.     st_right:=pos('cf',f_line);
  280.     IF (st_right>0) AND (st_right+3 < LINE_MAX) THEN
  281.       Begin
  282.         trim:=copy(f_line,st_right+3,length(f_line)-st_right-2);
  283.         val(trim,cf,result);
  284.         IF (result>0)              THEN cf:=DEFINITE;
  285.         IF pos('poor',trim)>0      THEN cf:= 25;
  286.         IF pos('fair',trim)>0      THEN cf:= 50;
  287.         IF pos('good',trim)>0      THEN cf:= 75;
  288.         IF pos('excellent',trim)>0 THEN cf:= DEFINITE
  289.       End;
  290.     get_cf:=cf
  291.   END;
  292.  
  293. FUNCTION blend(cf1,cf2:integer):integer;
  294.   BEGIN
  295.     blend:=(((100*cf1)+(100*cf2)-(cf1*cf2)) DIV 100)
  296.   END;
  297.  
  298. PROCEDURE add_cf(f_object,f_value:word_string;cf2:integer);
  299.   VAR
  300.     cf1: integer;
  301.     curr_value: value_ptr;
  302.   BEGIN
  303.     curr_value := test(f_object,f_value);
  304.     cf1:=curr_value^.cert;
  305.     curr_value^.cert :=blend(cf1,cf2)
  306.   END;
  307.  
  308. FUNCTION ok_add(f_object: word_string; cf : integer):boolean;
  309.   VAR
  310.     curr_object:object_ptr;
  311.     curr_value: value_ptr;
  312.     is_100:boolean;
  313.   BEGIN
  314.     ok_add:=TRUE;
  315.     is_100:=FALSE;
  316.     curr_object:=find_object(f_object);
  317.     IF (curr_object <> NIL) THEN
  318.       begin
  319.         curr_value:=curr_object^.value_list;
  320.         WHILE (curr_value<>NIL) DO
  321.           begin
  322.             IF (curr_value^.cert=DEFINITE) THEN is_100:= TRUE;
  323.             curr_value:=curr_value^.next
  324.           end
  325.       end;
  326.     IF ((cf=DEFINITE) AND (is_100=TRUE) AND (curr_object^.multivald=FALSE))
  327.       THEN ok_add:=FALSE
  328.   END;
  329.  
  330. PROCEDURE make_multi(f_line:line_string);
  331.   VAR
  332.     curr_object:object_ptr;
  333.     dummy, f_object: word_string;
  334.   BEGIN
  335.     split(f_line,f_object,dummy);
  336.     curr_object:=find_object(f_object);
  337.     IF (curr_object=NIL) THEN make_node(curr_object);
  338.     curr_object^.name:=f_object;
  339.     curr_object^.multivald:=TRUE
  340.   END;
  341.  
  342. FUNCTION find_word(f_line:line_string;n:integer;VAR oneword:word_string):boolean;
  343.   VAR
  344.     x,com_place:integer;
  345.   BEGIN
  346.     find_word:=FALSE;
  347.     oneword:='';
  348.     FOR x:=1 to n DO
  349.       begin
  350.         com_place:= pos(COMMA,f_line);
  351.         IF (com_place=0) THEN
  352.           begin
  353.             com_place:=length(f_line)+1;
  354.             find_word:=TRUE
  355.           end;
  356.         oneword:=copy(f_line,1,com_place-1);
  357.         f_line:=copy(f_line,com_place+1,length(f_line)-com_place)
  358.       end
  359.   END;
  360.  
  361. PROCEDURE add_legal(f_object:word_string;curr_object:object_ptr);
  362.   VAR
  363.     curr_value, head: legal_ptr;
  364.   BEGIN
  365.     new(curr_value);
  366.     curr_value^.next:=NIL;
  367.     curr_value^.name:=f_object;
  368.     head:=curr_object^.legal_list;
  369.     IF (head<>NIL) THEN
  370.       begin
  371.         WHILE (head^.next<>NIL) DO
  372.           head:=head^.next;
  373.           Head^.next:=curr_value
  374.       end
  375.     ELSE curr_object^.legal_list:=curr_value
  376.   END;
  377.  
  378. FUNCTION find_legal(f_object:word_string;n:integer;VAR oneword:word_string)
  379.      :boolean;
  380.   VAR
  381.     curr_object:object_ptr;
  382.     curr_value:legal_ptr;
  383.     counter:integer;
  384.   BEGIN
  385.     curr_object:=find_object(f_object);
  386.     find_legal:=TRUE;
  387.     IF (curr_object<>NIL) THEN
  388.       begin
  389.         curr_value:=curr_object^.legal_list;
  390.         oneword:=curr_value^.name;
  391.         counter:=1;
  392.         IF (curr_value=NIL) THEN find_legal :=FALSE;
  393.         WHILE ((curr_value<>NIL) AND (counter<n)) DO
  394.           begin
  395.             curr_value:=curr_value^.next;
  396.             IF (curr_value<>NIL) THEN
  397.               begin
  398.                 oneword:=curr_value^.name;
  399.                 counter:=counter+1
  400.               end
  401.             ELSE find_legal:=FALSE;
  402.           end
  403.       end
  404.     ELSE find_legal:=FALSE
  405.   END;
  406.  
  407. PROCEDURE make_legals(f_line:line_string);
  408.   VAR
  409.     curr_object:object_ptr;
  410.     counter, st_place :integer;
  411.     new_line: line_string;
  412.     f_object, dummy, oneword: word_string;
  413.     done: boolean;
  414.   BEGIN
  415.     split(f_line,f_object,dummy);
  416.     curr_object:=find_object(f_object);
  417.     IF (curr_object=NIL) THEN make_node(curr_object);
  418.     curr_object^.name:=f_object;
  419.     st_place:=pos(EQUALS,f_line);
  420.     new_line:=copy(f_line,st_place+1,length(f_line)-st_place);
  421.     counter:=1;
  422.     done:=FALSE;
  423.     WHILE (done=FALSE) DO
  424.       begin
  425.         done:=find_word(new_line,counter,oneword);
  426.         add_legal(oneword,curr_object);
  427.         counter:=counter+1
  428.       end
  429.   END;
  430.  
  431. PROCEDURE add_question(f_line:line_string);
  432.   VAR
  433.     new_line:line_string;
  434.     curr_object:object_ptr;
  435.     f_object, dummy: word_string;
  436.     st_place: integer;
  437.   BEGIN
  438.     split(f_line,f_object,dummy);
  439.     curr_object:=find_object(f_object);
  440.     IF (curr_object=NIL) THEN make_node(curr_object);
  441.     curr_object^.name:=f_object;
  442.     st_place:=pos(EQUALS,f_line);
  443.     new_line:=copy(f_line,st_place+1,length(f_line)-st_place);
  444.     curr_object^.question:=new_line
  445.   END;
  446.  
  447.  
  448.  
  449.  
  450. PROCEDURE p_question(f_object:word_string);
  451.   VAR
  452.     curr_object:object_ptr;
  453.   BEGIN
  454.     TextColor(LightGreen);
  455.     curr_object:=find_object(f_object);
  456.     IF (curr_object<>NIL) THEN
  457.       begin
  458.         IF (curr_object^.question<>'') THEN
  459.           writeln(DressUp(curr_object^.question))
  460.         ELSE
  461.           writeln('What is the value of ',f_object,'?')
  462.       end
  463.     ELSE
  464.       writeln('What is the value of ',f_object,'?')
  465.   END;
  466.  
  467. PROCEDURE ask(f_object:word_string;VAR f_value:word_string);
  468.   VAR
  469.     pick, pick1, num_vals: integer;
  470.     okay: boolean;
  471.     oneword, select: word_string;
  472.   BEGIN
  473.     p_question(f_object);
  474.     IF find_legal(f_object,1,oneword)=FALSE THEN
  475.       readln(f_value)
  476.     ELSE
  477.       begin
  478.         num_vals:=1;
  479.         WHILE (find_legal(f_object,num_vals,oneword)<>FALSE) DO
  480.           begin
  481.             TextColor(LightBlue);
  482.             writeln(num_vals,'. ',DressUp(oneword));
  483.             num_vals:=num_vals+1
  484.           end;
  485.         pick:=0;
  486.         WHILE ((pick<1) OR (pick>=num_vals)) DO
  487.           begin
  488.             writeln('Please enter a number from 1 to ',num_vals-1);
  489.             readln(select);
  490.             pick:=ord(select[1])-48;
  491.             IF (length(select)>1) THEN
  492.               begin
  493.                 pick1:=ord(select[2])-48;
  494.                 IF ((pick1>=0) AND (pick1<10)) THEN pick:=pick*10+pick1
  495.               end
  496.           end;
  497.         okay:=find_legal(f_object,pick,oneword);
  498.         f_value:=oneword
  499.       end;
  500.       writeln;
  501.   END;
  502.  
  503. PROCEDURE p_read(VAR oline:line_string);
  504.   VAR
  505.     c:char;
  506.     cs:string[1];
  507.     len, counter,st_place: integer;
  508.     supress: boolean;
  509.     in_line: line_string;
  510.   BEGIN
  511.     readln(rules,in_line);
  512.     oline:='';
  513.     len:=length(in_line);
  514.     st_place:=pos(' and',in_line);
  515.     IF (st_place>0) THEN len:=st_place;
  516.     supress:=FALSE;
  517.     FOR counter:=1 to len DO
  518.       begin
  519.         c:=in_line[counter];
  520.         IF ((c=EQUALS) AND (pos('question',oline)>0)) THEN supress:=TRUE;
  521.         IF (ord(c)=9) THEN c:=' ';
  522.         IF ((c in ['A'..'Z']) AND (supress=FALSE)) THEN c:=chr(ord(c)+32);
  523.         cs:=' ';
  524.         cs[1]:=c;
  525.         IF ((c<>' ') OR (supress=TRUE)) THEN oline:=concat(oline,cs)
  526.       end
  527.   END;
  528.  
  529. FUNCTION add_prem(curr_prem:prem_ptr;f_line:line_string):prem_ptr;
  530.   VAR
  531.     temp, new_prem: prem_ptr;
  532.     f_object, f_value: word_string;
  533.   BEGIN
  534.     split(f_line,f_object,f_value);
  535.     add_prem:=curr_prem;
  536.     new(new_prem);
  537.     WITH new_prem^ DO
  538.       begin
  539.         object:=f_object;
  540.         value:=f_value;
  541.         next:=NIL
  542.       end;
  543.     IF (curr_prem=NIL) THEN
  544.       add_prem:=new_prem
  545.     ELSE
  546.       begin
  547.         WHILE (curr_prem^.next<>NIL) DO curr_prem:=curr_prem^.next;
  548.         curr_prem^.next:=new_prem
  549.       end
  550.   END;
  551.  
  552. FUNCTION add_con(curr_con:con_ptr;f_line:line_string):con_ptr;
  553.   VAR
  554.     temp, new_con: con_ptr;
  555.     f_object, f_value: word_string;
  556.   BEGIN
  557.     split(f_line,f_object,f_value);
  558.     add_con:=curr_con;
  559.     new(new_con);
  560.     WITH new_con ^ DO
  561.       begin
  562.         object:=f_object;
  563.         value:=f_value;
  564.         cert:=get_cf(f_line);
  565.         next:=NIL
  566.       end;
  567.     IF (curr_con=NIL) THEN add_con:=new_con
  568.     ELSE
  569.       begin
  570.         WHILE (curr_con^.next<>NIL) DO curr_con:=curr_con^.next;
  571.         curr_con^.next:=new_con
  572.       end
  573.   END;
  574.  
  575. PROCEDURE p_rule(curr_rule:rule_ptr);
  576.   VAR
  577.     curr_prem:prem_ptr;
  578.     curr_con:con_ptr;
  579.   BEGIN
  580.     writeln(curr_rule^.name,': if');
  581.     curr_prem:=curr_rule^.prem;
  582.     WHILE (curr_prem<>NIL) DO
  583.       begin
  584.         write(curr_prem^.object,'=');
  585.         write(curr_prem^.value);
  586.         curr_prem:=curr_prem^.next;
  587.         IF (curr_prem<>NIL) THEN writeln(' and') ELSE writeln
  588.       end;
  589.     writeln('then');
  590.     curr_con:=curr_rule^.con;
  591.     WHILE (curr_con<>NIL) DO
  592.       begin
  593.         write(curr_con^.object,'=');
  594.         write(curr_con^.value,' cf',curr_con^.cert);
  595.         curr_con:=curr_con^.next;
  596.         IF curr_con<>NIL THEN writeln(' and')  ELSE writeln;
  597.       end
  598.   END;
  599.  
  600. PROCEDURE enter_rule(rule_name:word_string);
  601.   VAR
  602.     new_rule, curr_rule: rule_ptr;
  603.     line: line_string;
  604.     done: boolean;
  605.   BEGIN
  606.     new(new_rule);
  607.     IF (top_rule<>NIL) THEN
  608.       begin
  609.         curr_rule:=top_rule;
  610.         WHILE (curr_rule^.next<>NIL) DO curr_rule:=curr_rule^.next;
  611.         curr_rule^.next:=new_rule
  612.       end
  613.     ELSE top_rule:=new_rule;
  614.     WITH new_rule^ DO
  615.       begin
  616.         name:=rule_name;
  617.         next:=NIL;
  618.         prem:=NIL;
  619.         con:=NIL
  620.       end;
  621.     p_read(line);
  622.     done:=FALSE;
  623.     WHILE ((NOT done) AND (NOT EOF(rules))) DO
  624.       begin
  625.         new_rule^.prem:=add_prem(new_rule^.prem,line);
  626.         p_read(line);
  627.         IF pos('then',line)>0 THEN done:=TRUE
  628.       end;
  629.     p_read(line);
  630.     done:=FALSE;
  631.     REPEAT
  632.       IF (Eof(rules)) THEN done:=TRUE;
  633.       new_rule^.con:=add_con(new_rule^.con,line);
  634.       IF line[length(line)]='.' THEN done:=TRUE ELSE p_read(line);
  635.     UNTIL (done);
  636.   END;
  637.  
  638. PROCEDURE read_file;
  639.   VAR
  640.     command: word_string;
  641.     m_line, f_line: line_string;
  642.     st_place: integer;
  643.   BEGIN
  644.     writeln(UpperCase(datfile),' Consultation.');writeln;
  645.      writeln;
  646.     TextColor(LightBlue);
  647.     writeln('Loading ',UpperCase(datfile),' rulebase.');
  648.     top_rule:=NIL;
  649.     command:='';
  650.     WHILE (NOT Eof(rules)) DO
  651.       begin
  652.         p_read(f_line);
  653.         st_place:=pos('(',f_line);
  654.         IF (st_place=0) then st_place:= (pos(COLON,f_line));
  655.         IF (st_Place>1) THEN
  656.           begin
  657.             command:=copy(f_line,1,st_place-1);
  658.             m_line:=copy(f_line,st_place+1,length(f_line)-st_place);
  659.             IF (command='objective') THEN
  660.                s_object:=copy(m_line,1,length(m_line)-1);
  661.             IF (command='multivalued') THEN make_multi(m_line);
  662.             IF (command='question') THEN add_question(m_line);
  663.             IF (command='legalvals') THEN make_legals(m_line);
  664.             IF (pos('rule',command)>0) THEN enter_rule(m_line);
  665.           end
  666.       end;
  667.       TextColor(red);
  668.       write('Ready.');
  669.       TextColor(LightBlue);
  670.   END;
  671.  
  672. FUNCTION find_rule(obj:word_string;curr_rule:rule_ptr):rule_ptr;
  673.   VAR
  674.     found: boolean;
  675.     curr_con: con_ptr;
  676.   BEGIN
  677.     found:=FALSE;
  678.     find_rule:=NIL;
  679.     WHILE ((curr_rule<>NIL) AND (found=FALSE)) DO
  680.       begin
  681.         curr_con:=curr_rule^.con;
  682.         WHILE (curr_con<>NIL) DO
  683.           begin
  684.             IF (curr_con^.object=obj) THEN
  685.               begin
  686.                 found:=TRUE;
  687.                 find_rule:=curr_rule
  688.               end;
  689.             curr_con:=curr_con^.next
  690.           end;
  691.         curr_rule:=curr_rule^.next
  692.       end
  693.   END;
  694.  
  695. PROCEDURE conclude(curr_rule:rule_ptr;prem_cert:integer);
  696.   VAR
  697.     curr_con: con_ptr;
  698.     cert: integer;
  699.   BEGIN
  700.     curr_con:=curr_rule^.con;
  701.     WHILE (curr_con<>NIL) DO
  702.       begin
  703.         add_object(curr_con^.object,curr_con^.value);
  704.         cert:=(prem_cert*curr_con^.cert) DIV 100;
  705.         add_cf(curr_con^.object,curr_con^.value,cert);
  706.         curr_con:=curr_con^.next
  707.       end
  708.   END;
  709.  
  710. PROCEDURE explain_how(curr_rule:rule_ptr);
  711.   VAR
  712.     curr_prem: prem_ptr;
  713.     curr_con: con_ptr;
  714.   BEGIN
  715.     writeln('Because:');
  716.     curr_prem:=curr_rule^.prem;
  717.     WHILE (curr_prem<>NIL) DO
  718.       Begin
  719.         write('The answer to ',UpperCase(DressUp(curr_prem^.object)),' was ');
  720.         write(UpperCase(DressUp(curr_prem^.value)));
  721.         curr_prem:=curr_prem^.next;
  722.         If (curr_prem<> NIL) then writeln(' and ') ElSE writeln
  723.       End;
  724.     Writeln('We can conclude that');
  725.     curr_con:=curr_rule^.con;
  726.     WHILE (curr_con<>NIL) DO
  727.       Begin
  728.         write(' the answer to ',UpperCase(DressUp(curr_con^.object)),' is ');
  729.         TextColor(White);
  730.         writeln(UpperCase(DressUp(curr_con^.value)));
  731.         TextColor(LightBlue);
  732.         write(' and the degree of certainty is ',curr_con^.cert,'.');
  733.         curr_con:=curr_con^.next;
  734.         IF curr_con<>NIL THEN writeln(' and ') ELSE writeln
  735.       End;
  736.       Wait;
  737.     writeln
  738.     End;
  739.  
  740. PROCEDURE pursue(f_object:word_string);
  741.   VAR
  742.     f_value: word_string;
  743.     curr_object: object_ptr;
  744.     curr_value: value_ptr;
  745.     curr_rule: rule_ptr;
  746.     curr_prem: prem_ptr;
  747.     bad, solved: boolean;
  748.     lowest: integer;
  749.   BEGIN
  750.     curr_object:=find_object(f_object);
  751.     IF curr_object=NIL THEN make_node(curr_object);
  752.     curr_object^.name:= f_object;
  753.     IF (curr_object^.sought<>TRUE) THEN
  754.       begin
  755.         solved:=FALSE;
  756.         curr_object^.sought:=TRUE;
  757.         curr_rule:=find_rule(f_object,top_rule);
  758.         WHILE ((curr_rule<>NIL) AND (ok_add(f_object,DEFINITE)=TRUE)) DO
  759.           begin
  760.             curr_prem:=curr_rule^.prem;
  761.             bad:=FALSE;
  762.             lowest:=DEFINITE;
  763.             WHILE ((curr_prem<>NIL) AND (bad=FALSE)) DO
  764.               begin
  765.                 pursue(curr_prem^.object);
  766.                 curr_value:=test(curr_prem^.object,curr_prem^.value);
  767.                 IF curr_value=NIL THEN
  768.                   bad:=TRUE
  769.                 ELSE IF curr_value^.cert<lowest THEN
  770.                   lowest:=curr_value^.cert;
  771.                 curr_prem:=curr_prem^.next
  772.               end;
  773.             IF (bad=FALSE) THEN
  774.               begin
  775.                 if (explain=TRUE) THEN explain_how(curr_rule);
  776.                 conclude(curr_rule,lowest);
  777.                 solved:=TRUE
  778.               end;
  779.             curr_rule:=find_rule(f_object,curr_rule^.next)
  780.           end;
  781.         IF (solved=FALSE) THEN
  782.           begin
  783.             ask(f_object,f_value);
  784.             add_object(f_object,f_value);
  785.             add_cf(f_object,f_value,DEFINITE)
  786.           end
  787.       end
  788.   END;
  789.  
  790. PROCEDURE p_result(f_object:word_string);
  791.   VAR
  792.     curr_object:object_ptr;
  793.   BEGIN
  794.     TextColor(White);
  795.     writeln;
  796.     writeln('  RESULTS OF CONSULTATION');
  797.     writeln;
  798.     curr_object:=find_object(f_object);
  799.     see_vals(curr_object);
  800.     writeln;
  801.     writeln('  END OF CONSULTATION')
  802.   END;
  803.  
  804. BEGIN {MAIN PROGRAM}
  805.   last_try:=NIL;
  806.   top_fact:=NIL;
  807.   choice:=0;
  808.   ClrScr;
  809.  
  810.   If ParamCount=0 then
  811.   repeat
  812.     writeln('What is the name of the knowlege base data file?');
  813.     readln(datfile);
  814.     assign(rules,datfile);
  815.     {$I-} reset(rules) {I+};
  816.     ok:= (IOresult = 0);
  817.     if not ok then writeln('Can''t find file ',datfile);
  818.   until ok
  819.   else
  820.   begin
  821.   datfile := ParamStr(1);
  822.   repeat
  823.   assign(rules,datfile);
  824.     {$I-} reset(rules) {I+};
  825.     ok:= (IOresult = 0);
  826.     if not ok then writeln('Can''t find file ',datfile);
  827.   until ok;
  828.   end;
  829.   read_file;
  830.   Beep(800,50);Beep(900,50);Beep(1000,50);Beep(1100,50);Beep(1200,50);
  831.   writeln;
  832.   writeln;
  833.   another:=TRUE;
  834.   REPEAT
  835.      repeat
  836.        write('Do you want my reasoning explained');
  837.        writeln(' during our consultation?');
  838.        writeln('1-yes');
  839.        writeln('2-no');
  840.        readln(choice);
  841.      until choice in [1..2];
  842.      writeln;
  843.      IF (choice = 1) THEN explain:=TRUE
  844.          ELSE explain:=false;
  845.      pursue(s_object);
  846.      p_result(s_object);
  847.      TextColor(LightBlue);
  848.      repeat
  849.        writeln('Do you want to have another consultation?');
  850.        writeln('1-yes');
  851.        writeln('2-no');
  852.        readln(choice);
  853.      until choice in [1..2];
  854.      writeln;
  855.      If (choice = 1) THEN
  856.      begin
  857.      clrscr;
  858.      clean;
  859.      end
  860.       else another:=FALSE;
  861.   Until another = FALSE
  862. END.
  863.