Caesar Cipher Cracking
Antonio Corbi via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sun Aug 14 02:35:37 PDT 2016
Hi folks,
I was just following Graham Hutton's excellent book "Programming
in Haskell" (http://www.cs.nott.ac.uk/~pszgmh/book.html) and in
chapter 5 He implements a Caesar-Cipher cracking algorithm in a
few lines of Haskell code
(http://www.cs.nott.ac.uk/~pszgmh/cipher.lhs).
So, as I'm also learning D, I decided to port it to D using the
very little functional-programming in D that I know.
No attempt to optimize it has been made, only following the
original Haskell code and rewrite it into D so there's room
(plenty) for optimization and usage of functional-programming
(I'm just learning here) techniques to make it more D-ish.
Hope this is useful to someone that is also learning D.
Happy message-cracking!
Antonio
---------------8><---------------------------------------
import std.stdio, std.conv;
import std.algorithm, std.algorithm.searching, std.range;
import std.ascii, std.string : countchars;
int let2int (char c) {
return cast(int) (c - 'a');
}
char int2let (int n) {
if (n >= 0)
return cast(char) ('a' + n);
else
return cast(char) ('z' + n + 1);
}
char shift (int n, char c) {
return isLower (c) ? int2let ((let2int (c) + n) % 26) : c;
}
string encode (int n, string s) {
string r;
s.each!(c => r ~= shift(n, c));
return r;
}
alias decode = (int n, string s) { return encode (-n, s); };
float percent (int n, int m) {
return (n / cast(float) m) * 100;
}
int[] positions (float x, float[] fl) {
int[] il;
auto r = zip (fl, iota(fl.length)).filter!(t => t[0]==x).map!(t
=> t[1]);
r.each!(a => il ~= cast(int)a);
return il;
}
int lowers (string s) {
return cast(int) count!(a => a.isLower)(s);
}
int cccount (char c, string s) {
return cast(int) countchars(s, to!string(c));
}
float[] freqs (string s) {
float[] f;
auto allChars = "abcdefghijklmnopqrstuvwxyz";
auto n = lowers(s);
auto r = allChars.map!(a => percent (cccount(to!char(a), s), n)
);
r.each!(a => f ~= a);
return f;
}
float chisqr (float[] os, float[] es) {
return zip(os, es).map!(t => ((t[0]-t[1])^^2)/t[1]).sum;
}
float[] rotate (int n, float[] fl) {
float[] f;
auto r = fl.drop(n) ~ fl.take(n);
r.each!(a => f ~= a);
return f;
}
string crack (string s) {
// ASCII letters frequency from 'a'..'z'
float[] table = [8.2, 1.5, 2.8, 4.3, 12.7, 2.2, 2.0, 6.1, 7.0,
0.2, 0.8, 4.0, 2.4,
6.7, 7.5, 1.9, 0.1, 6.0, 6.3, 9.1, 2.8, 1.0,
2.4, 0.2, 2.0, 0.1];
float[] table2 = s.freqs;
auto chitabr = iota(26).map!(n => rotate(n,
table2).chisqr(table));
float[] chitab;
chitabr.each!(a => chitab ~= a);
auto minval = reduce!(min)(chitab);
auto factor = positions (minval, chitab)[0];
return decode (factor, s);
}
void main()
{
writeln ("wyvnyhttpun pu kshun pz clyf mbu! = ",
crack ("wyvnyhttpun pu kshun pz clyf mbu!"));
}
More information about the Digitalmars-d-learn
mailing list