Szyfr ogrodzeniowy

10

Napisz dwa programy:
- Jeden, który odczytuje ciąg i klucz i koduje ciąg w szyfr szynowy za pomocą tego klucza. - Podobnie napisz program dla funkcji odwrotnej: odszyfrowanie ogrodzenia za pomocą klucza.

Dla tych, którzy nie wiedzą, czym jest szyfr ogrodzeniowy, jest to w zasadzie metoda pisania zwykłego tekstu w sposób, w jaki tworzy liniowy wzór w spiralny sposób. Przykład - gdy ogrodzenie z szyny „FOOBARBAZQUX” jest ogrodzone przy użyciu klucza 3.

F . . . A . . . Z . . . .
  O . B . R . A . Q . X
    O . . . B . . . U

Odczytując powyższą spiralę linia po linii, tekst szyfru zmienia się w „FAZOBRAQXOBU”.

Czytaj więcej na stronie - Szyfr ogrodzeniowy - Wikipedia .

Kod w dowolnym języku jest mile widziany.

Najkrótsza odpowiedź w bajtach wygrywa.

ShuklaSannidhya
źródło
2
Jakie jest kryterium wygranej?
Paul R

Odpowiedzi:

9

Python 133 bajty

def cipher(t,r):
 m=r*2-2;o='';j=o.join
 for i in range(r):s=t[i::m];o+=i%~-r and j(map(j,zip(s,list(t[m-i::m])+[''])))or s
 return o

Przykładowe użycie:

>>> print cipher('FOOBARBAZQUX', 3)
FAZOBRAQXOBU

>>> print cipher('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 4)
AGMSYBFHLNRTXZCEIKOQUWDJPV

>>> print cipher('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 5)
AIQYBHJPRXZCGKOSWDFLNTVEMU

>>> print cipher('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 6)
AKUBJLTVCIMSWDHNRXEGOQYFPZ

Uwaga: wyniki z parzystej liczby szyn są inne niż dla kodu, który podałeś, ale wydają się poprawne. Na przykład 6 szyn:

A         K         U
 B       J L       T V
  C     I   M     S   W
   D   H     N   R     X
    E G       O Q       Y
     F         P         Z

odpowiada AKUBJLTVCIMSWDHNRXEGOQYFPZ, a nie AKUTBLVJICMSWXRDNHQYEOGZFPjak tworzony jest kod.

Podstawową ideą jest to, że każdą szynę można znaleźć bezpośrednio, biorąc wycinki łańcuchów [i::m], gdzie ijest numer szyny ( 0-indexed) i mjest (num_rails - 1)*2. Wewnętrzne szyny dodatkowo muszą się przeplatać [m-i::m], osiągnięte przez zapięcie i połączenie dwóch zestawów znaków. Ponieważ drugi z nich może potencjalnie być o jeden znak krótszy, jest dopełniany znakiem, który zakłada się, że nigdzie się nie pojawia ( _), a następnie znak ten jest usuwany, jeśli to konieczne , jest konwertowany na listę i uzupełniany pustym łańcuchem.


Nieco bardziej czytelna dla człowieka forma:

def cipher(text, rails):
  m = (rails - 1) * 2
  out = ''
  for i in range(rails):
    if i % (rails - 1) == 0:
      # outer rail
      out += text[i::m]
    else:
      # inner rail
      char_pairs = zip(text[i::m], list(text[m-i::m]) + [''])
      out += ''.join(map(''.join, char_pairs))
  return out
primo
źródło
Potrzebna jest również funkcja odszyfrowywania.
ShuklaSannidhya
@ShuklaSannidhya Więc dlaczego zaakceptowałeś niepełną odpowiedź?
Jo King
3
@JoKing dla jasności, wymóg „dwóch programów” został dodany rok po opublikowaniu mojego rozwiązania.
primo
2

APL 52 41

i←⍞⋄n←⍎⍞⋄(,((⍴i)⍴(⌽⍳n),1↓¯1↓⍳n)⊖(n,⍴i)⍴(n×⍴i)↑i)~' '

Jeśli wejściowy ciąg tekstowy i oraz numer klucza n są wstępnie zainicjalizowane, rozwiązanie można skrócić o 9 znaków. Uruchomienie rozwiązania na przykładach podanych przez primo daje identyczne odpowiedzi:

FOOBARBAZQUX
3
FAZOBRAQXOBU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
4
AGMSYBFHLNRTXZCEIKOQUWDJPV

ABCDEFGHIJKLMNOPQRSTUVWXYZ
5
AIQYBHJPRXZCGKOSWDFLNTVEMU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
6
AKUBJLTVCIMSWDHNRXEGOQYFPZ

Po dalszej refleksji wydaje się, że istnieje rozwiązanie oparte na krótszym indeksie:

i[⍋+\1,(y-1)⍴((n←⍎⍞)-1)/1 ¯1×1 ¯1+y←⍴i←⍞]
Graham
źródło
Potrzebna jest również funkcja odszyfrowywania.
ShuklaSannidhya,
1

Python 2 , 124 + 179 = 303 bajty

Kodować:

lambda t,k:''.join(t[i+j]for r in R(k)for i in R(k-1,len(t)+k,2*k-2)for j in[r-k+1,k+~r][:1+(k-1>r>0)]if i+j<len(t))
R=range

Wypróbuj online!

Rozszyfrować:

lambda t,k:''.join(t[dict((b,a)for a,b in enumerate(i+j for r in R(k)for i in R(k-1,len(t)+k,2*k-2)for j in[r-k+1,k+~r][:1+(k-1>r>0)]if i+j<len(t)))[m]]for m in R(len(t)))
R=range

Wypróbuj online!

Chas Brown
źródło
Potrzebujesz także funkcji odszyfrowywania
Jo King
@Jo King: Z opóźnieniem dodałem deszyfrator.
Chas Brown
0

MATL, 70 bajtów (ogółem)

f'(.{'iV'})(.{1,'2GqqV'})'5$h'$1'0'$2'0K$hYX2Get2LZ)P2LZ(!tg)i?&S]1Gw)

Wypróbuj w MATL Online.
Wypróbuj wiele przypadków testowych

Pobiera flagę jako trzecie wejście, Faby zaszyfrować ciąg, Todszyfrować go (dzięki Kevin Cruijssen za ten pomysł).

Zaczęło się to od odpowiedzi Julii, dopóki nie zdałem sobie sprawy, że ścisłe pisanie stało się zbyt duże, szczególnie do rozszyfrowania. Oto kod Julii, który miałem do szyfrowania (przeniesiony do wersji V0.6 dla TIO):

Julia 0.6 , 191 bajtów

!M=(M[2:2:end,:]=flipdim(M[2:2:end,:],2);M)
s|n=replace(String((!permutedims(reshape([rpad(replace(s,Regex("(.{$n})(.{1,$(n-2)})"),s"\1ø\2ø"),length(s)*n,'ø')...],n,:),(2,1)))[:]),"ø","")

Wypróbuj online!

Wyjaśnienie:

Operacja ogrodzenia szynowego

F . . . A . . . Z . . . .
  O . B . R . A . Q . X
    O . . . B . . . U

może być postrzegany jako odczyt r = 3 znaki wejściowe, następnie odczytanie znaków r-2 oraz przedrostek i przyrostek z wartościami pozornymi (wartości zerowe), a następnie ponowne odczytanie znaków r itp., za każdym razem tworząc nową kolumnę:

F.A.Z.
OBRAQX
O.B.U.

następnie odwracanie co drugą kolumnę (ponieważ zag zygzak idzie w górę zamiast w dół, co robi różnicę, gdy r> 3), następnie odczytywanie tej macierzy wzdłuż wierszy i usuwanie fałszywych znaków.

Odszyfrowanie nie wydawało się mieć takich oczywistych wzorców, ale kiedy szukałem tego, natknąłem się na ten post , który powiedział mi, że (a) był to dobrze znany i (być może?) Algorytm szyfrów szynowych oraz ( b) rozszyfrowanie było prostym ponownym użyciem tej samej metody, nadaniem mu wskaźników ciągu i uzyskaniem wskaźników tych wskaźników po zaszyfrowaniu i odczytaniu tekstu zaszyfrowanego w tych miejscach.

Ponieważ odszyfrowanie musi działać w oparciu o indeksy, kod ten szyfruje również przez sortowanie indeksów ciągu, a następnie w tym przypadku po prostu indeksuje te uporządkowane indeksy.

              % implicit first input, say 'FOOBARBAZQUX'
f             % indices of input string (i.e. range 1 to length(input)
'(.{'iV'})(.{1,'2GqqV'})'5$h
              % Take implicit second input, say r = 3
              % Create regular expression '(.{$r})(.{1,$(r-2)})'
              % matches r characters, then 1 to r-2 characters
              %  (to allow for < r-2 characters at end of string)
'$1'0'$2'0K$h % Create replacement expression, '$1\0$2\0'
YX            % Do the regex replacement
2Ge           % reshape the result to have r rows (padding 0s if necessary)
t2LZ)         % extract out the even columns of that
P             % flip them upside down
2LZ(          % assign them back into the matrix
!             % transpose
tg)           % index into the non-zero places (i.e. remove dummy 0s)
i?            % read third input, check if it's true or false
&S]           % if it's true, decipherment needed, so get the indices of the 
              %  rearranged indices
1Gw)          % index the input string at those positions
sundar - Przywróć Monikę
źródło
0
int r=depth,len=plainText.length();
int c=len/depth;
char mat[][]=new char[r][c];
int k=0;
String cipherText="";
for(int i=0;i< c;i++)
{
 for(int j=0;j< r;j++)
 {
  if(k!=len)
   mat[j][i]=plainText.charAt(k++);
  else
   mat[j][i]='X';
 }
}
for(int i=0;i< r;i++)
{
 for(int j=0;j< c;j++)
 {
  cipherText+=mat[i][j];
 }
}
return cipherText;
}

Chcę wyjaśnić w tym kodzie.

gihadsaad
źródło
Ponieważ jest to gra w golfa , powinieneś spróbować skrócić swój kod. Ponadto należy dodać język i liczbę bajtów do tego zgłoszenia
Jo King
Oprócz tego, co powiedział Jo King, możesz rozważyć skorzystanie z usługi online takiej jak TIO, aby inne osoby mogły z łatwością przetestować Twój kod.
Οurous,
0

Java 10, 459 451 445 439 327 bajtów

(s,k,M)->{int l=s.length,i=-1,f=0,r=0,c=0;var a=new char[k][l];for(;++i<l;a[r][c++]=M?s[i]:1,r+=f>0?1:-1)f=r<1?M?f^1:1:r>k-2?M?f^1:0:f;for(c=i=0;i<k*l;i++)if(a[i/l][i%l]>0)if(M)System.out.print(a[i/l][i%l]);else a[i/l][i%l]=s[c++];if(!M)for(r=c=i=0;i++<l;f=r<1?1:r>k-2?0:f,r+=f>0?1:-1)if(a[r][c]>1)System.out.print(a[r][c++]);}

-12 bajtów dzięki @ceilingcat .
-112 bajtów łączących dwie funkcje z dodatkową flagą trybu jako wejście.

Funkcja przyjmuje trzecie wejście M. Jeśli tak, trueto szyfruje, a jeśli tak, falseto rozszyfrowuje.

Wypróbuj online.

Wyjaśnienie:

(s,k,M)->{              // Method with character-array, integer, and boolean parameters
                        // and no return-type
  int l=s.length,       //  Length of the input char-array
      i=-1,             //  Index-integer, starting at -1
      f=0,              //  Flag-integer, starting at 0
      r=0,c=0;          //  Row and column integers, starting both at 0
  var a=new char[k][l]; //  Create a character-matrix of size `k` by `l`
  for(;++i<l            //  Loop `i` in the range (-1, `l`):
      ;                 //    After every iteration:
       a[r][c++]=       //     Set the matrix-cell at `r,c` to:
         M?s[i++]       //      If we're enciphering: set it to the current character
         :1,            //      If we're deciphering: set it to 1 instead
       r+=f>0?          //     If the flag is 1:
           1            //      Go one row down
          :             //     Else (flag is 0):
           -1)          //      Go one row up
    f=r<1?              //   If we're at the first row:
       M?f^1            //    If we're enciphering: toggle the flag (0→1; 1→0)
       :1               //    If we're deciphering: set the flag to 1
      :r>k-2?           //   Else-if we're at the last row:
       M?f^1            //    If we're enciphering: toggle the flag (0→1; 1→0)
       :0               //    If we're deciphering: set the flag to 0
      :                 //   Else (neither first nor last row):
       f;               //    Leave the flag unchanged regardless of the mode
  for(c=i=0;            //  Reset `c` to 0
            i<k*l;i++)  //  Loop `i` in the range [0, `k*l`):
    if(a[i/l][i%l]>0)   //   If the current matrix-cell is filled with a character:
      if(M)             //    If we're enciphering:
        System.out.print(a[i/l][i%l]);}
                        //     Print this character
      else              //    Else (we're deciphering):
        a[r][i]=s[c++]; //     Fill this cell with the current character
  if(!M)                //  If we're deciphering:
    for(r=c=i=0;        //   Reset `r` and `c` both to 0
        i++<l           //   Loop `i` in the range [0, `l`)
        ;               //     After every iteration:
         f=r<1?         //      If we are at the first row:
            1           //       Set the flag to 1
           :r>k-2?      //      Else-if we are at the last row:
            0           //       Set the flag to 0
           :            //      Else:
            f,          //       Leave the flag the same
         r+=f>0?        //      If the flag is now 1:
             1          //       Go one row up
            :           //      Else (flag is 0):
             -1)        //       Go one row down
      if(a[r][c]>1)     //    If the current matrix-cell is filled with a character:
        System.out.print(a[r][c++]);}
                        //     Print this character
Kevin Cruijssen
źródło