Как я могу выполнять криптоарифметику на Прологе?

Каждая из 7 разных букв обозначает разные цифры. Цель состоит в том, чтобы найти такую ​​замену цифр на буквы, чтобы полученная сумма была арифметически правильной. Затем решение должно давать все комбинации цифр, которые удовлетворяют приведенной выше задаче сложения. Ввод такого запроса, как crypto(P,I,N,G,O,F,U), должен вернуть ваше решение.

Загадка криптоарифметики выглядит так:

  P I N G
  P O N G
+   F U N
---------
I G N I P

person konopoly    schedule 18.05.2015    source источник
comment
хм .... вы пытались Google для Prolog отправить больше денег? И, согласно рекомендациям stackoverflow, ваш вопрос не может быть настоящим вопросом.   -  person    schedule 18.05.2015
comment
Я не вижу вопроса. В конце утверждения стоит вопросительный знак, который образует подлежащее, но не вопрос. Что вы пробовали и где вы застряли в своих усилиях по решению проблемы?   -  person lurker    schedule 18.05.2015
comment
См. эти вопросы.   -  person false    schedule 18.05.2015
comment
@false: ссылка, по-видимому, разрешается правильно только в том случае, если вы вошли в систему!   -  person mat    schedule 19.05.2015


Ответы (2)


Используйте clpfd! На основе на мой предыдущий ответ на очень похожий вопрос, мы запускаем следующий запрос:

?- Eq = ([P,I,N,G] + [P,O,N,G] + [F,U,N] #= [I,G,N,I,P]),
   crypt_arith_(Eq,Zs),
   labeling([],Zs).
  Eq = ([7,1,9,4] + [7,0,9,4] + [6,2,9] #= [1,4,9,1,7]), Zs = [7,1,9,4,0,6,2]
; Eq = ([8,1,4,7] + [8,3,4,7] + [9,2,4] #= [1,7,4,1,8]), Zs = [8,1,4,7,3,9,2]
; Eq = ([8,1,4,7] + [8,9,4,7] + [3,2,4] #= [1,7,4,1,8]), Zs = [8,1,4,7,9,3,2]
; false.
person repeat    schedule 13.08.2015

Предполагая, что это простой шифр замены, о котором мы говорим (и просто для удовольствия), я попробую его. Следует отметить, что это совершенно не проверено.

Я собираюсь настроить это в общем виде, чтобы вы могли сказать что-то вроде:

substitution_cipher( CipherExpr , CipherResult , Expr , Result , Key ).

Мы возьмем за правило, что зашифрованный материал представлен атомами, так что вы можете сказать что-то вроде этого:

substitution_cipher( ping + pong + fun , ignip , Expr , Sum , Key ) .

И получить ожидаемые результаты.

So...

Во-первых, вам нужен набор (дискретный, уникальный) символов, найденных в зашифрованном тексте:

character_set( Expr , Charset ) :-
  setof( C , A^Cs^( atoms_in_expression( Expr , A ) , atom_chars(A,Cs) , member(C,Cs) ) , Charset ) .

atom_in_expression( Expr , Value ) :- atom(Expr) .
atom_in_expression( Expr , Value ) :-
  Expr =.. [ _ , Left , Right ] ,
  (
    values( Left  , Value )
  ;
    values( Right, Value
  ) .

Вышеупомянутое просматривает дерево синтаксического анализа выражения, подобного a * b + c * d, находя каждый из листовых узлов (атомов), разлагая их на символы, которые их составляют. setof/3 гарантирует, что результирующий список будет отсортирован и уникален.

Как только вы это сделаете, вам понадобится способ сгенерировать все возможные ключи (key == сопоставление между символом и цифрой). Мы хотим иметь возможность сказать что-то вроде

generate_key( [a,b,c] , Key )

и вернуться

Key = [a:1,b:2,c:3]

и Т. Д.

So:

generate_key( Charset , Key ) :-
  generate_key( Charset , [] , Key ) .

generate_key( [] , Key , Key ) .      % when we've exhausted the character set, we're done.
generate_key( [C|Cs] , Acc , Key ) :-  % otherwise...for each character
  digit(D) ,                           % find a digit
  \+ member( _:D , Acc ) ,             % that hasn't yet been used
  generate_key( Cs , [C:D|Acc] , Key ) % map it to the character and recurse down.
  .

digit(D) :- between(0,9,X) , atom_number(D,X).

Тогда вам нужен способ декодировать выражение шифра, например

ping + pong + fun

и [попытаться] превратить его обратно в правильные числа. Это не сильно отличается от обхода дерева синтаксического анализа и перечисления атомов конечных узлов, но здесь нам нужно вернуть их в числовую форму.

Если выражение является атомом, мы

  • разложить его на составляющие его символы,
  • используя наш ключ, сопоставьте каждый символ с соответствующей цифрой,
  • затем мы превращаем этот список цифр обратно в число

    декодировать(Ключ, CipherExpr, PlainExpr):- atom(CipherExpression), atom_chars(CipherExpression,Cs), findall(D, (member(C,Cs), member(C:D,Key) -> true; D=C) , Ds ), число_символов ( PlainExpr , Ds ) .

Общий случай прост. Инфиксное выражение вроде ping + pong на самом деле является термином пролога +(ping,pong). Мы:

  • Разложите инфиксный термин, например ping + pong, на оператор (+) и его левое и правое подвыражения.
  • Затем мы рекурсивно декодируем левое и правое подвыражения
  • Наконец, мы собираем выражение [decoded].

    декодировать(Ключ, CipherExpr, PlainExpr) :- CipherExpr =.. [Op,L,R] , декодировать(L,L1) , декодировать(R,R1) , PlainExpr =.. [Op,L1,R1] .

Затем вы можете собрать все это вместе:

substitition_cipher( CipherExpr , CipherResult , PlainExpr , PlainResult , Key ) :-
  character_set( CipherExpr = CipherResult , Charset ) ,
  generate_key( Charset, Key ) ,
  decode( Key , CipherExpr   , PlainExpr   ) ,
  decode( Key , CipherResult , PlainResult ) ,
  PlainResult =:= PlainExpr
  .
person Nicholas Carey    schedule 19.05.2015