Raylı çit şifresi


10

İki program yazın:
- Bir dizeyi ve bir anahtarı okuyan ve dizeyi bu tuşu kullanarak bir demiryolu çiti şifresine kodlayan bir program. - Benzer şekilde, ters fonksiyon için bir program yazın: bir anahtar kullanarak bir demiryolu çitinin deşifre edilmesi.

Raylı çit şifresinin ne olduğunu bilmeyenler için, temel olarak düz metni spiral bir şekilde doğrusal desen oluşturacak şekilde yazma yöntemidir. Örnek - 3 tuşuyla "FOOBARBAZQUX" raylı çitle çevrildiğinde.

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

Yukarıdaki sarmal satır satır okunarak şifre metni "FAZOBRAQXOBU" olur.

- Raylı çit şifresi - Vikipedi .

Herhangi bir dilde kod kabul edilir.

Bayt cinsinden en kısa cevap kazanır.


2
Kazanan kriter nedir?
Paul R

Yanıtlar:


9

Python 133 bayt

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

Örnek kullanım:

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

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

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

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

Not: çift sayı sayımı sonuçları sağladığınız koddan farklıdır, ancak doğru görünüyorlar. Örneğin, 6 ray:

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

kodunuzun ürettiği gibi AKUBJLTVCIMSWDHNRXEGOQYFPZdeğil, karşılık gelir AKUTBLVJICMSWXRDNHQYEOGZFP.

Temel fikir, her raylı dize dilim alarak doğrudan bulunabilir olmasıdır [i::m], burada i(ray sayıdır 0-indexed) ve mbir (num_rails - 1)*2. İç rayların ek olarak [m-i::m]iki karakter kümesinin sıkıştırılması ve birleştirilmesiyle elde edilmesi gerekir . Bunlardan ikincisi potansiyel olarak bir karakter daha kısa olabileceğinden, hiçbir yerde görünmediği varsayılan bir karakterle doldurulur ( _) ve daha sonra gerekirse bu karakter çıkarılır , bir listeye dönüştürülür ve boş bir dize ile doldurulur.


Biraz daha insan tarafından okunabilir bir form:

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

Bir deşifre etme fonksiyonu da gereklidir.
ShuklaSannidhya

@ShuklaSannidhya O zaman neden eksik bir cevabı kabul ettiniz?
Jo King

3
@ Netlik için, çözümümü yayınladıktan bir yıl sonra "iki program" gereksinimi eklendi .
primo

2

APL 52 41

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

Giriş metni dizesi i ve anahtar numarası n önceden başlatılırsa, çözüm 9 karakterle kısaltılabilir. Çözeltinin primo tarafından verilen örneklere karşı çalıştırılması aynı cevapları verir:

FOOBARBAZQUX
3
FAZOBRAQXOBU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
4
AGMSYBFHLNRTXZCEIKOQUWDJPV

ABCDEFGHIJKLMNOPQRSTUVWXYZ
5
AIQYBHJPRXZCGKOSWDFLNTVEMU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
6
AKUBJLTVCIMSWDHNRXEGOQYFPZ

Daha fazla yansıma üzerine daha kısa bir endeks tabanlı çözüm var gibi görünüyor:

i[⍋+\1,(y-1)⍴((n←⍎⍞)-1)/1 ¯1×1 ¯1+y←⍴i←⍞]

Bir deşifre etme fonksiyonu da gereklidir.
ShuklaSannidhya

1

Python 2,124 + 179 = 303 bayt

kodlama:

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

Çevrimiçi deneyin!

Kod Çözme:

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

Çevrimiçi deneyin!


Ayrıca bir deşifre etme fonksiyonuna da ihtiyacınız var
Jo King

@Jo King: Geç de olsa bir şifre çözücü ekledim.
Chas Brown

0

MATL, 70 bayt (toplam)

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

MATL Online'da deneyin Birden fazla test senaryosunu
deneyin

FDize Tşifresini çözmek , deşifre etmek için üçüncü girdi olarak bir bayrak alır ( bu fikir için Kevin Cruijssen'e teşekkürler ).

Bu, özellikle deşifre olmak için katı yazmanın çok fazla yol aldığını anlayana kadar Julia'nın cevabı olarak başladı. Şifreleme için sahip olduğum Julia kodu (TIO için v0.6'ya aktarıldı):

Julia 0.6 , 191 bayt

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

Çevrimiçi deneyin!

Açıklama:

Raylı çit operasyonu

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

r = 3 giriş karakterinin okunması, ardından r-2 karakterlerinin okunması ve kukla değerlerle (null) ön eklenmesi ve son eklenmesi, ardından r karakterlerinin okunması vb. her seferinde yeni bir sütun oluşturularak görülebilir:

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

daha sonra her ikinci sütunu ters çevirir ( zigzagın zag kısmı aşağı yerine yükselir, bu da r> 3 olduğunda bir fark yaratır), daha sonra bu matrisi satırlar boyunca okur ve kukla karakterleri kaldırır.

Deşifre, bunun gibi bariz bir örüntüye sahip gibi görünmüyordu, ancak bu konuda etrafa bakarken , (a) bunun demiryolu şifreleri için iyi bilinen ve (muhtemelen?) Yayınlanmış bir algoritma olduğunu ve ( b) deşifre, aynı yöntemin basit bir şekilde yeniden kullanılmasıydı, ona dizenin indekslerini verdi ve şifrelemeden sonra bu indekslerin indekslerini aldı ve bu yerlerde şifreleme metnini okudu.

Deşifre, indeksler üzerinde çalışarak bir şeyler yapmak gerektiğinden, bu kod dizenin indekslerini sıralayarak ve daha sonra bu durumda sadece yeniden düzenlenmiş endekslerde indeksleyerek şifreleme yapar.

              % 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

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;
}

Bu kodda açıklamak istiyorum.


Bu kod golf olduğundan , kodunuzu kısaltmaya çalışmalısınız. Ayrıca, bu gönderime dil ve bayt sayımı eklemelisiniz
Jo King

Jo King'in söylediklerine ek olarak, TIO gibi bir çevrimiçi hizmet kullanmayı düşünebilirsiniz, böylece diğer insanlar kodunuzu kolayca test edebilir.
Οurous

0

Java 10, 459 451 445 439 327 bayt

(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++]);}

@Ceilingcat sayesinde -12 bayt .
İki işlevi giriş olarak ek bir mod işaretiyle birleştiren -112 bayt.

Fonksiyon üçüncü bir giriş alır M. Bu ise trueşifrelenir ve eğer çözülürse falsedeşifre edilir.

Çevrimiçi deneyin.

Açıklama:

(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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.