remove([(C,1)|Coins], C, Coins).
remove([(C,N)|Coins], C, [(C,N1)|Coins]) :- N > 1, N1 is N - 1.
remove([(X,N)|Coins], C, [(X,N)|R]) :- remove(Coins, C, R).

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

change(0, _, []).
change(X, Av, Coins) :-
  remove(Av, C, Av1),
  C =< X, X1 is X - C,
  change(X1, Av1, Coins1),
  put(Coins1, C, Coins).

changeNoDups(0, _, []) :- !.
changeNoDups(X, [(C,N)|Av], Coins) :-
  remove([(C,N)|Av], C, Av1),
  C =< X, X1 is X - C,
  changeNoDups(X1, Av1, Coins1),
  put(Coins1, C, Coins).
changeNoDups(X, [_|Av], Coins) :- changeNoDups(X, Av, Coins).

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(_,_,_).

caesar(_,[],[]).
caesar(S,[P|Ps],[C|Cs]) :- shifted(S, P, C), caesar(S, Ps, Cs).

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

vigenere(_,[],[]).
vigenere([S|Ss],[P|Ps],[C|Cs]) :-
  shifted(S, P, C),
  append(Ss, [S], Ss1),
  vigenere(Ss1, Ps, Cs).

subseq(S,L) :- append(_,S,X), append(X,_,L).

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(K, 8), subseq("procedure", Y), vigenere(K, Y, X), vigenere(K, Y2, X), writef(Y2).
