Rail rail cipher

10

Tulis dua program:
- Satu yang membaca string dan kunci dan mengkodekan string ke cipher pagar-pagar menggunakan kunci itu. - Demikian pula, tulis program untuk fungsi terbalik: menguraikan pagar pagar menggunakan kunci.

Bagi mereka yang tidak tahu apa itu rail rail cipher, pada dasarnya metode menulis teks biasa dengan cara menciptakan pola linier dengan cara spiral. Contoh - ketika "FOOBARBAZQUX" dipagari menggunakan kunci 3.

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

Membaca baris demi baris spiral di atas, teks sandi menjadi "FAZOBRAQXOBU".

Baca lebih lanjut di - Rail rail cipher - Wikipedia .

Selamat datang di kode dalam bahasa apa pun.

Jawaban terpendek dalam byte menang.

ShuklaSannidhya
sumber
2
Apa kriteria kemenangan?
Paul R

Jawaban:

9

Python 133 byte

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

Penggunaan sampel:

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

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

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

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

Catatan: hasil dari penghitungan kereta api genap berbeda dari kode yang Anda berikan, tetapi hasilnya tampaknya benar. Misalnya, 6 rel:

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

sesuai dengan AKUBJLTVCIMSWDHNRXEGOQYFPZ, dan bukan AKUTBLVJICMSWXRDNHQYEOGZFPsaat kode Anda menghasilkan.

Ide dasarnya adalah bahwa setiap kereta api dapat ditemukan secara langsung dengan mengambil irisan tali [i::m], di mana iadalah jumlah rel ( 0-indexed), dan madalah (num_rails - 1)*2. Rel bagian dalam juga perlu terjalin dengan [m-i::m], dicapai dengan zip dan bergabung dengan dua set karakter. Karena yang kedua ini berpotensi menjadi satu karakter lebih pendek, itu diisi dengan karakter yang dianggap tidak muncul di mana pun ( _), dan kemudian karakter itu dilucuti jika perlu dikonversi ke daftar, dan diisi dengan string kosong.


Bentuk yang sedikit lebih bisa dibaca manusia:

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
sumber
Fungsi penguraian juga diperlukan.
ShuklaSannidhya
@ShuklaSannidhya Lalu mengapa Anda menerima jawaban yang tidak lengkap?
Jo King
3
@JoKing untuk kejelasan, persyaratan "dua program" ditambahkan satu tahun setelah saya memposting solusi saya.
primo
2

APL 52 41

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

Jika string teks input i dan nomor kunci n diinisialisasi, solusi dapat dipersingkat menjadi 9 karakter. Menjalankan solusi melawan contoh yang diberikan oleh primo memberikan jawaban yang identik:

FOOBARBAZQUX
3
FAZOBRAQXOBU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
4
AGMSYBFHLNRTXZCEIKOQUWDJPV

ABCDEFGHIJKLMNOPQRSTUVWXYZ
5
AIQYBHJPRXZCGKOSWDFLNTVEMU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
6
AKUBJLTVCIMSWDHNRXEGOQYFPZ

Pada refleksi lebih lanjut tampaknya ada solusi berbasis indeks yang lebih pendek:

i[⍋+\1,(y-1)⍴((n←⍎⍞)-1)/1 ¯1×1 ¯1+y←⍴i←⍞]
Graham
sumber
Fungsi penguraian juga diperlukan.
ShuklaSannidhya
1

Python 2 , 124 + 179 = 303 byte

Menyandi:

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

Cobalah online!

Membaca sandi:

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

Cobalah online!

Chas Brown
sumber
Anda juga membutuhkan fungsi penguraian
Jo King
@ Jo King: Saya terlambat menambahkan sebuah deciphererer.
Chas Brown
0

MATL, 70 byte (total)

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

Cobalah di MATL Online
Coba beberapa uji kasus

Mengambil bendera sebagai input ketiga F, Tuntuk menguraikan string, untuk menguraikannya (terima kasih kepada Kevin Cruijssen untuk ide itu).

Ini dimulai sebagai jawaban Julia sampai saya menyadari pengetikan yang ketat terlalu banyak, terutama untuk penguraian. Berikut kode Julia yang saya miliki untuk penyandian (backported ke v0.6 untuk TIO):

Julia 0,6 , 191 byte

!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)))[:]),"ø","")

Cobalah online!

Penjelasan:

Operasi pagar pagar

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

dapat dilihat sebagai membaca r = 3 karakter input, kemudian membaca r-2 karakter dan awalan dan suffix dengan nilai dummy (nulls), kemudian membaca r karakter lagi, dll., membuat kolom baru setiap kali:

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

kemudian membalikkan setiap kolom kedua (karena bagian zag dari zigzag naik bukan ke bawah, yang membuat perbedaan ketika r> 3), kemudian membaca matriks ini di sepanjang baris, dan menghapus karakter dummy.

Penguraian tampaknya tidak memiliki pola yang jelas seperti ini, tetapi ketika mencari-cari tentang hal ini saya menemukan posting ini , yang mengatakan kepada saya bahwa (a) ini adalah algoritma yang terkenal dan (mungkin?) Dipublikasikan untuk cipher kereta api, dan ( b) penguraian adalah penggunaan kembali yang sederhana dari metode yang sama, memberikannya indeks string dan mendapatkan indeks indeks tersebut setelah pengodean, dan membaca ciphertext di tempat-tempat itu.

Karena penguraian perlu melakukan hal-hal dengan mengerjakan indeks, kode ini melakukan pengodean juga dengan menyortir indeks string, dan kemudian dalam hal ini hanya mengindeks pada indeks yang disusun ulang.

              % 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 - Pasang kembali Monica
sumber
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;
}

Saya ingin dijelaskan dalam kode ini.

gihadsaad
sumber
Karena ini adalah kode-golf , Anda harus berusaha mempersingkat kode Anda. Juga, Anda harus menambahkan bahasa dan jumlah byte pada kiriman ini
Jo King
Selain apa yang dikatakan Jo King, Anda mungkin mempertimbangkan untuk menggunakan layanan online seperti TIO sehingga orang lain dapat dengan mudah menguji kode Anda.
Surous
0

Java 10, 459 451 445 439 327 byte

(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 byte terima kasih kepada @ceilingcat .
-112 byte menggabungkan dua fungsi dengan flag mode tambahan sebagai input.

Fungsi ini mengambil input ketiga M. Jika ini dia akan menguraikan true, dan jika falseitu akan menguraikan.

Cobalah online.

Penjelasan:

(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
sumber