I have seen some examples of cyrptarithmetic puzzle solver using Prolog's clfpd library. For instance if I have a puzzle AM + PM = DAY, it can assign different set of values from 0 to 9 to different alphabets so that A*10+M + P*10+M = D*100+A*10+Y. I am trying to write a generalized version of it. Please note that I have very little experience with either Prolog or clfpd.
I intend to generate constraints based on input. For instance A*10+M + P*10+M = D*100+A*10+Y is to be generated based in input puzzle1([A,M]+[P,M]=[D,A,Y]). But I have no idea how to do it. I have written a Prolog function (called convert) which based on input creates a constraint. But its not working and I keep getting error
clpfd_expression' expected, found `convert([_818,_894])
:- use_module(library(clpfd)).
%calculate correct multiplier
%For example if AM, multipler of A is 10 and of M is 1
multiple(1,10).
multiple(N,F) :-
N#>0,
N1 #= N-1,
multiple(N1,F1),
F #= 10 * F1.
%convert accepts input as a list. For instance [A,M]
%outputs a constraint of the form A*10 + M*1
convert([H|T], Ans):-
length(T, Len),
Len #= 0,
Ans #= H * 1.
convert([H|T], Ans):-
length([H|T], Len1),
Len2 #= Len1-1,
multiple(Len2,Multiplier),
convert(T, Ans1),
Ans #= Ans1 + H * Multiplier.
%add should imply constraint A*10+M+P*10+M=D*100+A*10+Y.
add(Exp1, Exp2, Exp3):-
Exp1 + Exp2 #= Exp3.
puzzle1(As + Bs = Cs) :-
append([As,Bs,Cs],Ds),
term_variables(Ds,Var), %% this will get all Var
Var ins 0..9,
all_different(Var),
Exp01 #= convert(As),
Exp02 #= convert(Bs),
Exp03 #= convert(Cs),
add(Exp01, Exp02, Exp03),
%add constraint first member of each list cant be asigned a value 0
As #= [H1|_],
Bs #= [H2|_],
Cs #= [H3|_],
H1 #\=0,
H2 #\=0,
H3 #\=0.
Can someone steer me in correct direction.
There are two mistakes in your code. First, convert/2 is a predicate with two arguments -- you cannot use it as a function. So, instead of
Exp01 #= convert(As)
simply write
convert(As, Exp01)
The other mistake is
As #= [H1|_]
Here you want to structurally decompose the list As
and extract its first element. The way to do that is with simple unification, i.e.
As = [H1|_]
The difference is that #=
implements (integer) arithmetic equality (meaning that it interprets both sides as arithmetic expressions), while =
is pure symbolic manipulation, which is what you want here.
You can find a program similar to yours at http://eclipseclp.org/examples/cryptarith.ecl.txt