users-prolog
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: Gnu prolog as rule evaluator for small C virtual-world game.


From: Gerstmann, Jerry P
Subject: RE: Gnu prolog as rule evaluator for small C virtual-world game.
Date: Wed, 9 Apr 2003 09:19:09 -0700

Uffe,

I built a generic interface to C (C++) years ago that allowed me to build and 
run any prolog predicates through C.  I also built a generic interface that 
allowed me to call back out to C from prolog but this is a little out of scope. 
 This was written in Quintus Prolog but would work for any other Prolog.

I will try to explain it simply.  I basically built an engine (could be very 
simple) to execute whatever was defined in the interface input arguments.  The 
engine was configured to load a config file that defined where the working 
directory was, where the logs should be written to, what rule (prolog) files 
should be loaded, what the DB connection was, etc.  The Prolog engine interface 
was built as follows:

execute_engine(+Action, +InData, -OutData)

+Action  - atom, "initialize", "close", "run_predicate", <some rule name>

+InData - list, could be a simple list of arguments or a complex data structure.
          I build a data structure explained below.

+OutData - list, could be a simple list of arguments or a complex data 
structure.
          I build a data structure explained below.
  

Data Structure:

Based on attribute:value pairs:
   Simple argument is argName:value
   <containerName>:[arg1Name:val1, arg2Name:val2,...]
   <sequence>:[[arg1Name:val1,...],[arg1Name:valN,...]]
A container can hold any number of arguments, containers, sequences or named 
list


Create C++ interface: 

class PrologInt : public PrologIntBase {
    
private:
               
protected:
    
public:
 
                          
    long execute_engine(const char *action,
                        QP_term_ref in,
                        QP_term_ref out);

    int initialize();
    int close_server();

    PrologInt() { };

    ~PrologInt() { };
    
};

long PrologInt::execute_engine(const char *action, QP_term_ref in, QP_term_ref 
out)
{
   // Create prolog predicate call to execute_engine/3 in Prolog

   // Call Prolog execute_engine/3
}


PrologIntBase is a base class that includes methods for mapping all data types 
to the data container and getting all values in a data container out by name.  
Example of methods include:

put_string(const char* name, const char *value, QP_term_ref listTerm)
get_string(const char* name, QP_term_ref listTerm, char **value)
put_integer, get_integer
put_real, get_real
put_date, get_date
put_object, get_object  // named list of attribute:value pairs (Prolog term)
...

These methods are used in C++ to put the data into the data container and 
retrieve data from the returning data container by name.  They are each written 
to handle a specific data type between the two languages.


Example of C++ main:

int
main (int argc, char **argv)
{
    long status;
    prologInt  pint;
    
    // Initialize Prolog so it can be called - Quintus requirment.
    if ((status = QP_initialize (argc, argv) == QP_SUCCESS)) {
        // Initialize the Prolog server so it is ready to recieve calls.   
        if (pint.initialize() != 0)
            exit(-1);
          
        // Initialize prolog terms used to pass input and output
        QP_term_ref in = QP_new_term_ref ();
        QP_term_ref out = QP_new_term_ref ();

        // Create representation of "credits(john, 1000)"
        QP_term_ref AssertArgTerm = QP_new_term_ref ();
        QP_term_ref parentArglist = QP_new_term_ref ();
        pint.put_string("player1", "john", parentArglist); 
        pint.put_string("credit", "1000", parentArglist);
        pint.put_object("credits", parentArglist, AssertArgTerm);
        pint.put_object("term", AssertArgTerm, in);

        // Put in an action predicate name.
        pint.put_string("predicate", "assertz", in);
        

        // in = [predicate:assertz, term:[credits:[player1:john, credit:1000]]]
        //
        // You could have simplified this if you did it all as a string and
        // changed it to a term in Prolog: 
        // pint.put_string("term", "credits(john, 1000)", in);
        // pint.put_string("predicate", "assertz", in);
        // in = [predicate:assertz, term:'credits(john, 1000)']
        // Depends how flexible you want your engine to be.
        
        status = pint.execute_engine ("run_predicate", in, out);
    
    
        if (pint.close_server() != 0)  
            exit(-1);
        return 0;
    }
 
    else {
        cerr << "Prolog: initialization failed (" << status << ")." << endl;
        exit(-1);
        }
}


Prolog implementation of execute_engine/3:

execute_engine(initialize, _, _):-
    % Load config file if changed
    % open all log files if necessary...
    % load rules if changed - could be a prolog .pl file you are working on.
    !.

execute_engine(close_server, _, _):-
    % close all log files
    % ...
    !.

execute_engine(run_predicate, In, Out):-
    % 
    memberchk(predicate:Pred, In),  // or use remove_list_item/3
    build_arg_list(In, ArgList, ReturnVars), // ReturnVars in list of name:var
                                             // pairs that share ArgList 
variables
    Predicate =.. [Pred | ArgList],
    call_my_predicate(Predicate),    // handle all exceptions and error 
conditions
    Out = ReturnVars,
    !.

execute_engine(_, _, _).  // Can handle failure state as required


This is one way to handle implementation; you can decide what is best for you.  
Additional execute_engine/3 predicates can handle required high level 
functionality.

This mechanism has given me a standard call interface to and from C++ that has 
been flexible enough to handle many very complex problems.  The interface is 
very simple to implement and reuse from project to project.  It has given me 
access to a Prolog engine as required that fits seemlessly for maintenance by C 
programmers.  The only Gotcha in this framework is the coordination of data 
names between the two sides (C & Prolog); however, this has not turned out to 
be a problem.  Employ simple standards that everyone follows and mistakes are 
few and easy to find and fix if it does occur.  


Jerry Gerstmann
Advanced Computing Technologist
Boeing Airplane Company


> -----Original Message-----
> From: address@hidden [mailto:address@hidden
> Sent: Wednesday, April 09, 2003 7:35 AM
> To: address@hidden
> Subject: Gnu prolog as rule evaluator for small C virtual-world game.
> 
> 
> 
> Hi.
> 
> I've asked this thing before, but got no answer.. I'll try 
> making it brief;
> 
> How do I make a program able to interoperate with gnu-prolog 
> as if the program
> itself was the user?
> 
> I am trying this with C, to make it easier for myself.
> I am aware of Pl_Query, the problem is that I do not know in 
> advance (compile-time)
> which facts will be asserted to prolog.
> I am only trying to add new facts runtime, not present new queries.
> 
> Example:
> During play, it is suddenly decided that due to game-balance, 
> some of the
> players should have more money.
> So the following new facts should be added to the rule engine:
> 
> 'credits(player1,1000)'
> 'credits(player2,1000)'
> ...
> 'credits(player100,1000)'
> 
> How can I state these facts to prolog runtime?
> 
> 
> Regards, 
>   Uffe Wassmann.
> 
> 
> ________________________________________
> Få din egen webmail på http://solmail.sol.dk - gratis og med 
> dig overalt!
> Træt af virus? Få gratis beskyttelse her: http://antivirus.sol.dk
> 
> 
> 
> 
> _______________________________________________
> Users-prolog mailing list
> address@hidden
> http://mail.gnu.org/mailman/listinfo/users-prolog
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]