凯撒密码,我如何传递参数?

时间:2014-12-02 22:06:15

标签: prolog

我在Prolog中写了一个密码,但我不确定如何传递参数,所以我可以加密和解密输入。

caesar(L1,L2,L3) :-
    maplist(cipher, L1, PC), string_to_list(L2,PC),
    maplist(decipher,L2,PC), string_to_list(L3,PC).

cipher(A,B) :-
    B is A+1.
decipher(A,B) :-
    B is A-1.

2 个答案:

答案 0 :(得分:2)

我认为您的代码存在一些问题。

你的描述说, ...所以我可以加密和解密输入。这意味着L3应该是L1的解密。您的代码会解密L2(这是加密L1的输出)。

第二个问题是您重用PC变量。一旦变量在一个谓词子句中在Prolog中实例化,就无法在没有回溯的情况下重新实例化。所以你需要一个新的变量,或者你的子句中的第二行会失败。

如果您只是处理列表,那么更正后的版本可能会是这样的:

caesar(L1, L2, L3) :-
    maplist(cipher, L1, Encode), string_to_list(L2, Encode),
    maplist(decipher, L1, Decode), string_to_list(L3, Decode).

如果您确实打算L3解密L1被加密的结果,请在最后一行中将L1替换为L2。此外,正如@false说明的那样,SWI Prolog中不推荐使用string_to_list/2,而是string_codes/2

请注意,在Prolog中,表达式"abc"[97, 98, 99]表示相同的内容。 Prolog将它们视为等效物,您实际上可以互换使用。如果你想使用原子(单引号),那么你可以使用atom_codes/2

caesar2(L1, L2, L3) :-
    atom_codes(L1, List1),
    maplist(cipher, List1, Encoded), atom_codes(L2, Encoded),
    maplist(decipher, List1, Decoded), atom_codes(L3, Decoded).

哪个会产生相同的结果,但你会使用单引号作为原子。

答案 1 :(得分:1)

您提供可以通过多种方式处理的测试用例?- caesar("hello",L2).。 由于SWI 7默认为字符串。但这不是常见的编码。对于其他编码 see this

最直接和最传统的方法是。

:- set_prolog_flag(double_quotes,codes).

将此指令放入您的文件后,或在顶层发出:

?- set_prolog_flag(double_quotes,codes).
true.

?- L = "hello".
L = [104, 101, 108, 108, 111].

现在,可以直接应用编码方法。 Julius Caesar使用的方法与您指出的方法略有不同。特别是他使用模数,有时是不同的偏移量。此外,他不知道ASCII,只有大写字母,没有数字(只有像XVII)。允许我包括新的字母G(C与马尾),J(我与马尾),U(花式V),W(花式VV)。否则我们需要一个明确的表。

以下是使用library(clpfd)的一般密码关系。 0'A是A的字符代码,0'Z是Z的字符代码。

:- use_module(library(clpfd)).

cypher(Code, A,B) :-
   [A,B] ins 0'A..0'Z, % only letters!
    B #= 0'A+((A-0'A)+Code)mod 26.

请注意,这是一种关系;它可以用来编码:

?- cypher(1, 0'A, Y).
Y = 0'B.

...还要解码:

?- cypher(1, X, 0'B).
X = 0'A.

所以最后我们可以将这种关系应用于代码列表:

?- maplist(cypher(1),"ABC",L), atom_codes(A, L).
L = [66, 67, 68],
A = 'BCD'.

?- maplist(cypher(1),"ABC","BCD").
true.

?- maplist(cypher(1),X,"BCD"), atom_codes(A, X).
X = [65, 66, 67],
A = 'ABC'.

总是被迫将整数转换回可读的东西,这很烦人。不是吗?嗯,有一个更好的方法:

:- set_prolog_flag(double_quotes, chars).

另一种方法是使用字符,它们具有很大的优势,即答案现在更具可读性,但使用library(double_quotes)它们是完全可读的。简单下载吧。

?- set_prolog_flag(double_quotes, chars).
true.

?- L = "ABC".
L = ['A', 'B', 'C'].

?- use_module(double_quotes).
true.

?- L = "ABC", L = [C|Cs].
L = "ABC",
C = 'A',
Cs = "BC".

然而,我们的密码关系现在变得更加复杂,因为我们必须将字符转换为代码:

xcypher(Code, ACh, BCh) :-
   ( nonvar(ACh) -> char_code(ACh, A) ; char_code(BCh, B) ),
   cypher(Code, A, B),
   char_code(ACh, A),
   char_code(BCh, B). 

这就是凯撒阅读的内容(proof):

?- maplist(xcypher(1),Xs, "SPNBOFTFWOUEPNWT").
Xs = "ROMANESEVNTDOMVS".