/*
priklad sifry
cislo znamena pozici v mrizce kde je dira
1 X X X
X X 7 X
9 X X12
X X X X
*/
sifra(X):- X = [1,7,9,12].
/rotace cteci mrizky/
otoc(1,4).
otoc(2,8).
otoc(3,12).
otoc(4,16).
otoc(5,3).
otoc(6,7).
otoc(7,11).
otoc(8,15).
otoc(9,2).
otoc(10,6).
otoc(11,10).
otoc(12,14).
otoc(13,1).
otoc(14,5).
otoc(15,9).
otoc(16,13).
/* quicksort na trideni sifry po rotaci */
split1(_,[],[],[]).
split1(P,[A|Za],[A|S1],S2):- A < P , split1(P,Za,S1,S2).
split1(P,[A|Za],S1,[A|S2]):- A >= P , split1(P,Za,S1,S2).
qsort([],[]).
qsort([A|Za],X):- split1(A,Za,M,V), qsort(M,Ms), qsort(V,Vs), conc(Ms,[A|Vs],X).
/* zretezeni seznamu */
conc([],B,B).
conc([A|Za],B,[A|Zb]):- conc(Za,B,Zb).
/* rotace mrizky */
rotate([A,B,C,D],[E,F,G,H]):-otoc(A,E),otoc(B,F),otoc(C,G),otoc(D,H).
/*
desifruj(Zasifrovany,Nezasifrovany).
-funguje obema smery
priklad volani:
desifruj([a,e,m,f,i,n,b,j,c,k,g,d,o,h,p,l],X),write(X).
[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p]
*/
desifruj(X,Res):- sifra(S),cti(X,S,R1), rotate(S,S1),cti(X,S1,R2), rotate(S1,S2),cti(X,S2,R3), rotate(S2,S3),cti(X,S3,R4), conc(R1,R2,H1),conc(R3,R4,H2),conc(H1,H2,Res).
/* vybere n-ty prvek seznamu */
taken(1,[A|],A).
taken(N,[|Za],X):- N > 0,N1 is N - 1,taken(N1,Za,X).
/*
obraspoj(S1,S2,S).
obrati S1 a pripoji za nej S2
vysledek v S
*/
obraspoj([],B,B).
obraspoj([A|Za],B,Res):- obraspoj(Za,[A|B],Res).
/*
precte to "co je videt" pri aktualnim natoceni mrizky
pomoci read(+TextZasifrovany,+SetridenaSifra,-TextNezasifrovany)*/
cti(TZ,S,TN):- qsort(S,SS),read(TZ,SS,TN).
read(_,[],[]).
read(T,[A|Za],[Zn|Zb]):- taken(A,T,Zn),read(T,Za,Zb).