假设这是我们正在谈论的简单替换密码(只是为了好玩),我会尝试一下。请注意,这是完全未经测试的。
我将以通用方式进行设置,因此您可以这样说:
substitution_cipher( CipherExpr , CipherResult , Expr , Result , Key ).
我们将制定规则,加密的东西由原子表示,所以你可以这样说:
substitution_cipher( ping + pong + fun , ignip , Expr , Sum , Key ) .
并获得您期望的结果。
所以...
首先,您需要在密文中找到的集合(离散的、唯一的)字符:
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 确保结果列表已排序且唯一。
一旦你有了它,你就需要一种方法来生成所有可能的键(键 == 字符和数字之间的映射)。我们希望能够说类似
generate_key( [a,b,c] , Key )
然后回来
Key = [a:1,b:2,c:3]
等等
所以:
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_chars(CipherExpression,Cs) ,
findall( D , ( 成员 (C,Cs), 成员(C:D,Key) -> true ; D=C ) , Ds ) ,
number_chars(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
.