remove([(X,N)|Xs], X, [(X,N1)|Xs]) :- N > 0, N1 is N - 1.
remove([(X,N)|Xs], Y, [(X,N)|R]) :- remove(Xs, Y, R).

put([], X, [(X,1)]).
put([(X,N)|Xs], X, [(X,N1)|Xs]) :- !, N1 is N + 1.
put([(X,N)|Xs], Y, [(X,N)|R]) :- put(Xs, Y, R).

change(0, _, []).
change(X, Av, Change) :-
  remove(Av, C, R),
  X1 is X - C,
  X1 >= 0,
  change(X1, R, Change1),
  put(Change1, C, Change).

changeNoDups(0, _, []) :- !.
changeNoDups(X, [(C,N)|Av], Change) :-
  X >= C, N > 0,
  remove([(C,N)|Av], C, R),
  X1 is X - C,
  X1 >= 0,
  changeNoDups(X1, R, Change1),
  put(Change1, C, Change).
changeNoDups(X, [_|Av], Change) :- changeNoDups(X, Av, Change).

shifted(S,P,C) :- integer(S), integer(P), !, C is mod(P + S, 256).
shifted(S,P,C) :- integer(S), integer(C), !, P is mod(C - S, 256).
shifted(S,P,C) :- integer(P), integer(C), !, S is mod(C - P, 256).
shifted(_,_,_).

caeser(_, [], []).
caeser(S, [X|Xs], [Y|Ys]) :- shifted(S,X,Y), caeser(S,Xs,Ys).

generate(X,X).
generate(X,Z) :- X1 is X + 1, X1 =< 255, generate(X1,Z).

vigenere(_, [], []).
vigenere([S|Ss], [X|Xs], [Y|Ys]) :- shifted(S,X,Y), append(Ss, [S], S2), vigenere(S2,Xs,Ys).

%subseq(S, L) :- append(_, S, S2), append(S2, _, L).
subseq([], _).
subseq([S|Ss], [S|Ls]) :- subseq2(Ss, Ls).
subseq(S, [_|Ls]) :- subseq(S, Ls).
subseq2([], _).
subseq2([S|Ss], [S|Ls]) :- subseq2(Ss, Ls).

encrypted([140,146,95,96,96,80,170,147,97,81,115,171,82,164,
  153,151,83,168,146,171,94,80,165,154,152,81,164,147,
  159,149,81,162,165,160,148,151,150,165,163,151,83,
  146,164,82,158,145,164,166,83,170,150,147,164,92,81,
  127,156,164,164,82,133,159,161,154,156,150,112,82,95,
  80,133,154,152,81,164,147,159,149,81,162,165,160,148,
  151,150,165,163,151,83,146,164,82,151,166,150,164,172,
  81,170,151,147,162,81,124,148,158,150,165,83,80,94,82,
  138,150,157,158,94,80,122,89,159,157,81,150,161,80,158,
  171,83,167,150,164,171,80,147,151,166,165,82]).

% encrypted(X), length(S, 8), subseq("procedure", P), vigenere(S, P, X).
% Liefert S = [51, 49, 49, 50, 50, 48, 49, 50]
% encrypted(X), vigenere([51, 49, 49, 50, 50, 48, 49, 50], P, X), writef(P).
