[Top][All Lists]
[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
>