Schienenzaun Chiffre


10

Schreiben Sie zwei Programme:
- Eines, das eine Zeichenfolge und einen Schlüssel liest und die Zeichenfolge mit diesem Schlüssel in eine Rail-Zaun-Verschlüsselung codiert. - Schreiben Sie in ähnlicher Weise ein Programm für die Umkehrfunktion: Entschlüsseln eines Schienenzauns mit einem Schlüssel.

Für diejenigen, die nicht wissen, was eine Schienenzaun-Chiffre ist, ist es im Grunde eine Methode, einfachen Text so zu schreiben, dass ein lineares Muster spiralförmig erzeugt wird. Beispiel - wenn "FOOBARBAZQUX" mit dem Schlüssel 3 eingezäunt ist.

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

Wenn Sie die obige Spirale Zeile für Zeile lesen, wird der Chiffretext zu "FAZOBRAQXOBU".

Lesen Sie mehr unter - Rail Zaun Chiffre - Wikipedia .

Code in jeder Sprache ist willkommen.

Die kürzeste Antwort in Bytes gewinnt.


2
Was ist das Gewinnkriterium?
Paul R

Antworten:


9

Python 133 Bytes

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

Beispielnutzung:

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

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

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

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

Hinweis: Die Ergebnisse von geraden Schienenzählungen unterscheiden sich von denen für den von Ihnen angegebenen Code, scheinen jedoch korrekt zu sein. Zum Beispiel 6 Schienen:

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

entspricht AKUBJLTVCIMSWDHNRXEGOQYFPZund nicht AKUTBLVJICMSWXRDNHQYEOGZFPwie Ihr Code produziert.

Die Grundidee ist, dass jede Schiene direkt gefunden werden kann, indem String-Slices genommen werden [i::m], wobei idie Schienennummer ( 0-indexiert) ist und mist (num_rails - 1)*2. Die inneren Schienen müssen zusätzlich miteinander verwoben werden [m-i::m], was durch Reißverschluss und Verbinden der beiden Zeichensätze erreicht wird. Da das zweite Zeichen möglicherweise ein Zeichen kürzer sein kann, wird es mit einem Zeichen aufgefüllt, von dem angenommen wird, dass es nirgendwo erscheint ( _), und dieses Zeichen wird dann entfernt, falls erforderlich , in eine Liste konvertiert und mit einer leeren Zeichenfolge aufgefüllt.


Eine etwas besser lesbare 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

Eine Entschlüsselungsfunktion wird ebenfalls benötigt.
ShuklaSannidhya

@ShuklaSannidhya Warum hast du dann eine unvollständige Antwort akzeptiert?
Jo King

3
@JoKing aus Gründen der Klarheit wurde die Anforderung "zwei Programme" ein Jahr nach der Veröffentlichung meiner Lösung hinzugefügt .
Primo

2

APL 52 41

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

Wenn die Eingabetextzeichenfolge i und die Schlüsselnummer n vorinitialisiert sind, kann die Lösung um 9 Zeichen gekürzt werden. Wenn Sie die Lösung anhand der von primo angegebenen Beispiele ausführen, erhalten Sie identische Antworten:

FOOBARBAZQUX
3
FAZOBRAQXOBU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
4
AGMSYBFHLNRTXZCEIKOQUWDJPV

ABCDEFGHIJKLMNOPQRSTUVWXYZ
5
AIQYBHJPRXZCGKOSWDFLNTVEMU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
6
AKUBJLTVCIMSWDHNRXEGOQYFPZ

Bei weiterer Überlegung scheint es eine kürzere indexbasierte Lösung zu geben:

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

Eine Entschlüsselungsfunktion wird ebenfalls benötigt.
ShuklaSannidhya

1

Python 2 , 124 + 179 = 303 Bytes

Kodieren:

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

Probieren Sie es online aus!

Dekodieren:

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

Probieren Sie es online aus!


Sie benötigen auch eine Entschlüsselungsfunktion
Jo King

@ Jo King: Ich habe verspätet einen Entschlüsseler hinzugefügt.
Chas Brown

0

MATL, 70 Bytes (insgesamt)

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

Probieren Sie es mit MATL Online aus.
Probieren Sie mehrere Testfälle aus

Nimmt ein Flag als dritte Eingabe, Fum die Zeichenfolge zu verschlüsseln, Tum sie zu entschlüsseln (danke an Kevin Cruijssen für diese Idee).

Dies begann als Antwort von Julia, bis mir klar wurde, dass striktes Tippen zu viel störte, insbesondere für die Entschlüsselung. Hier ist der Julia-Code, den ich für die Verschlüsselung hatte (für TIO auf v0.6 zurückportiert):

Julia 0,6 , 191 Bytes

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

Probieren Sie es online aus!

Erläuterung:

Der Schienenzaunbetrieb

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

kann als Lesen von r = 3 Zeichen der Eingabe, dann Lesen von r-2 Zeichen und Präfixieren und Suffixieren dieser mit Dummy-Werten (Nullen), dann erneutes Lesen von r Zeichen usw. angesehen werden, wobei jedes Mal eine neue Spalte erstellt wird:

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

dann jede zweite Spalte umkehren (da der Zack- Teil des Zickzacks nach oben statt nach unten geht, was einen Unterschied macht, wenn r> 3 ist), dann diese Matrix entlang der Zeilen lesen und die Dummy-Zeichen entfernen.

Die Entschlüsselung schien keine offensichtlichen Muster wie dieses zu haben, aber als ich mich danach umsah , stieß ich auf diesen Beitrag , der mir sagte, dass (a) dies ein bekannter und (möglicherweise?) Veröffentlichter Algorithmus für Schienenchiffren war und ( b) Die Entschlüsselung war eine einfache Wiederverwendung derselben Methode, bei der die Indizes der Zeichenfolge angegeben und die Indizes dieser Indizes nach der Verschlüsselung abgerufen und der Chiffretext an diesen Stellen gelesen wurden.

Da die Entschlüsselung Dinge tun muss, indem an Indizes gearbeitet wird, verschlüsselt dieser Code auch, indem er die Indizes der Zeichenfolge sortiert und in diesem Fall nur an diesen neu angeordneten Indizes indiziert.

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

Ich möchte in diesem Code erklärt werden.


Da dies Code-Golf ist , sollten Sie versuchen, Ihren Code zu verkürzen. Außerdem sollten Sie der Einreichung die Sprache und die Anzahl der Bytes hinzufügen
Jo King

Zusätzlich zu den Aussagen von Jo King können Sie einen Onlinedienst wie TIO in Betracht ziehen, damit andere Personen Ihren Code problemlos testen können.
ousurous

0

Java 10, 459 451 445 439 327 Bytes

(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 Bytes dank @ceilingcat .
-112 Bytes, die die beiden Funktionen mit einem zusätzlichen Modus-Flag als Eingabe kombinieren.

Die Funktion nimmt eine dritte Eingabe entgegen M. Wenn dies der trueFall ist, wird es verschlüsselt, und wenn dies der Fall ist, wird falsees entschlüsselt.

Probieren Sie es online aus.

Erläuterung:

(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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.