Я видел несколько примеров криптарифметических решателей головоломок, использующих библиотеку Prolog clfpd. Например, если у меня есть головоломка AM + PM = DAY, она может присвоить разный набор значений от 0 до 9 разным алфавитам, так что A*10+M + P*10+M = D*100+A*10+Y . Я пытаюсь написать его обобщенную версию. Обратите внимание, что у меня очень мало опыта работы ни с Prolog, ни с clfpd.
Я намерен генерировать ограничения на основе ввода. Например, A*10+M + P*10+M = D*100+A*10+Y должно быть сгенерировано на основе входной головоломки1([A,M]+[P,M]=[D,A,Y ]). Но я понятия не имею, как это сделать. Я написал функцию Prolog (называемую convert), которая на основе ввода создает ограничение. Но это не работает, и я продолжаю получать ошибку
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.
Может ли кто-нибудь направить меня в правильном направлении.
См. это для вдохновения
Взгляните на мой предыдущий ответ stackoverflow.com/a/30346715/4609915! Что 2 теряют?-)
В вашем коде две ошибки. Во-первых, convert/2 — это предикат с двумя аргументами — вы не можете использовать его как функцию. Итак, вместо
Exp01 #= convert(As)
просто напишите
convert(As, Exp01)
Другая ошибка
As #= [H1|_]
Здесь вы хотите структурно разложить список As
и извлечь его первый элемент. Способ сделать это с помощью простой унификации, т.е.
As = [H1|_]
Разница в том, что #=
реализует (целочисленное) арифметическое равенство (это означает, что обе стороны интерпретируются как арифметические выражения), а =
— это чистая символическая манипуляция, что вам и нужно.
Вы можете найти программу, похожую на вашу, на http://eclipseclp.org/examples/cryptarith.ecl.txt
Я смог выделить эти ошибки с некоторой отладкой. Спасибо за объяснение.
Рабочий код:
:- 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 is N-1,
multiple(N1,F1),
F is 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 is Len1-1,
multiple(Len2,Multiplier),
convert(T, Ans1),
Ans = Ans1 + H * Multiplier.
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),
convert(As, Ans1),
convert(Bs, Ans2),
convert(Cs, Ans3),
%Generates a constraint depending on the input
%For instance if input is puzzle1([A,M] + [P,M] = [D,A,Y])
%Output constraint = A*10 + M + P*10 + M = D*100 + A*10 + Y
Ans1 + Ans2 #= Ans3,
As = [H1|_],
Bs = [H2|_],
H1 #\=0,
H2 #\=0,
label(Var),
write("Solution: "),
write(As + Bs = Cs).
%puzzle1([A,M]+[P,M]=[D,A,Y]).
%puzzle1([A,M]+[I]=[O,K]).
%puzzle1([Y,O,U]+[A,R,E]=[D,O,N,E]).
%puzzle1([S,E,N,D]+[M,O,R,E]=[M,O,N,E,Y]).
%puzzle1([R,O,A,D]+[I,N]=[U,S,A]).
%puzzle1([B,I,K,E]+[F,O,R]=[R,I,D,E]).
Итак, каково ваше желаемое поведение? Можете ли вы опубликовать несколько примеров?