function [] = decrypt(trainingfilename, cipherfilename)
% DECRYPT(TRAININGFILENAME, CIPHERFILENAME): print decryption of file 
% CIPHERFILENAME using file TRAININGFILENAME as training text
% example 1: decrypt('genesis.txt', 'cryptannounce.txt')
% example 2: decrypt('oldannounce.txt','scramble.txt')

tic % time how long it takes to read files

[traintot, whocares, trainbi] = tally(fopen(trainingfilename));
[ciphertot, whocares, cipherbi] = tally(fopen(cipherfilename));
cipheralpha = [' ' char('a'+0:'z'+0)]; % labels for cipher bigram table
toc

tic % time how long it takes to crack substitution cipher
% search: keep looking as long as improvements are made
%     for each position i
%        search for position j such that "swap i&j" yields the best table
%        commit "swap i&j"
d = distance(trainbi, cipherbi); % current distance
go = 1; % whether to keep looking == "were any improvements made?"
while go
    go = 0; % assume no improvements made
    for i = 2:27
        % search for best j
            bestd = inf; % best distance so far
	    use = [];    % indices for best swap so far
            for j = 2:27
            	bi = cipherbi;
            	bi(:,[i j]) = bi(:,[j i]); bi([i j],:) = bi([j i],:);
            	testd = distance(bi, trainbi);
            	if testd < bestd, bestd = testd; use = [i j]; end
            end
	% if made an improvement, update GO and commit "swap i&j"
            if bestd<d
                go = 1; % yes, made an improvement
                d = bestd;
                esu = fliplr(use); 
                fprintf('swap %c<-->%c; distance %6.4f; labels %s\n', ...
		    cipheralpha(use),bestd, cipheralpha);
                cipheralpha(use) = cipheralpha(esu);
                cipherbi(:,use)=cipherbi(:,esu); 
		cipherbi(use,:)=cipherbi(esu,:);
            end
    end
end
toc

% "compute" and print decryption key with no spaces
    bottom = char('a'+0:'z'+0);
    top = cipheralpha; top(1) = []; % throw out space
    disp('decryption key:')
    disp(top);
    disp(bottom);
    disp('');
% decrypt ciphertext

transform(top, bottom, cipherfilename, 10)

function d = distance(a,b)
% D = DISTANCE(A,B): return L1 distance D between equal-sized matrices A, B
    d = sum(sum(abs(a-b)));