Edit I’ve changed [60,61]
to “<=” and similarly other codes I was using to strings thanks to @jan pointing out that works.
After a bit of a hiatus, I’ve started tinkering around with automating the conversion of some of the game rules from Stanford’s General Game Playing project written in kif to Prolog.
Here’s how far I’ve got so far:
#!/usr/bin/env swipl
:- use_module(library(dcg/basics)).
:- initialization(main, main).
main(Argv) :-
last(Argv, File),
phrase_from_file(terms(Terms), File),
maplist(format('~w.~n'), Terms).
terms([Term|Terms]) --> blanks, term(Term), blanks, !, terms(Terms).
terms([]) --> [].
term(Comment) --> comment(Cs), { string_codes(Comment, Cs) }.
term(Compound) --> compound_term(L), { Compound =.. L }.
term(Variable) --> variable(Cs), { string_codes(Variable, Cs) }.
term(Constant) --> constant(Cs), { atom_codes(Constant, Cs) }.
term(':-') --> "<=".
compound_term(Terms) --> "(", terms(Terms) ,")".
variable([U|Ls]) --> [63,L], { to_upper(L, U) }, word_rest(Ls).
constant([L|Ls]) --> [L], { code_type(L, alnum) }, word_rest(Ls).
word_rest([L|Ls]) --> [L], { code_type(L, alnum) }, word_rest(Ls).
word_rest([]) --> [].
comment([37|Cs]) --> ";", comment_rest(Cs).
comment_rest([37|Cs]) --> ";", comment_rest(Cs).
comment_rest([C|Cs]) --> [C], { \+ code_type(C, end_of_line) }, comment_rest(Cs).
comment_rest([]) --> [C], { code_type(C, end_of_line) }.
Using TicTacToe as an example, running
./kif2prolog.pl ticTacToe.kif > test.pl
produces
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
%%% Tictactoe.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
%% Roles.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
role(xplayer).
role(oplayer).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
%% Base & Input.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
index(1).
index(2).
index(3).
:-(base(cell(X,Y,b)),index(X),index(Y)).
:-(base(cell(X,Y,x)),index(X),index(Y)).
:-(base(cell(X,Y,o)),index(X),index(Y)).
base(control(P)):-role(P).
:-(input(P,mark(X,Y)),index(X),index(Y),role(P)).
input(P,noop):-role(P).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
%% Initial State.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
init(cell(1,1,b)).
init(cell(1,2,b)).
init(cell(1,3,b)).
init(cell(2,1,b)).
init(cell(2,2,b)).
init(cell(2,3,b)).
init(cell(3,1,b)).
init(cell(3,2,b)).
init(cell(3,3,b)).
init(control(xplayer)).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
%% Dynamic Components.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
%% Cell.
:-(next(cell(M,N,x)),does(xplayer,mark(M,N)),true(cell(M,N,b))).
:-(next(cell(M,N,o)),does(oplayer,mark(M,N)),true(cell(M,N,b))).
:-(next(cell(M,N,W)),true(cell(M,N,W)),distinct(W,b)).
:-(next(cell(M,N,b)),does(W,mark(J,K)),true(cell(M,N,b)),or(distinct(M,J),distinct(N,K))).
next(control(xplayer)):-true(control(oplayer)).
next(control(oplayer)):-true(control(xplayer)).
:-(row(M,X),true(cell(M,1,X)),true(cell(M,2,X)),true(cell(M,3,X))).
:-(column(N,X),true(cell(1,N,X)),true(cell(2,N,X)),true(cell(3,N,X))).
:-(diagonal(X),true(cell(1,1,X)),true(cell(2,2,X)),true(cell(3,3,X))).
:-(diagonal(X),true(cell(1,3,X)),true(cell(2,2,X)),true(cell(3,1,X))).
line(X):-row(M,X).
line(X):-column(M,X).
line(X):-diagonal(X).
open:-true(cell(M,N,b)).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
:-(legal(W,mark(X,Y)),true(cell(X,Y,b)),true(control(W))).
legal(xplayer,noop):-true(control(oplayer)).
legal(oplayer,noop):-true(control(xplayer)).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
goal(xplayer,100):-line(x).
:-(goal(xplayer,50),not(line(x)),not(line(o)),not(open)).
goal(xplayer,0):-line(o).
goal(oplayer,100):-line(o).
:-(goal(oplayer,50),not(line(x)),not(line(o)),not(open)).
goal(oplayer,0):-line(x).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.
terminal:-line(x).
terminal:-line(o).
terminal:-not(open).
Loading that into swipl produces lots of warnings about singleton variables and clauses not being together, but it does work.
One horrible hack I’ve done is using format to place the full stop at the end of clauses. I find DCGs fun, but also pretty frustrating because I really struggle to find some simple examples to try understand stuff from.