Cifrado de valla ferroviaria

10

Escriba dos programas:
- Uno que lea una cadena y una clave y codifique la cadena en un cifrado de riel utilizando esa clave. - Del mismo modo, escriba un programa para la función inversa: descifrar una cerca de riel con una tecla.

Para aquellos que no saben qué es el cifrado de valla de riel, es básicamente un método de escribir texto plano de una manera que crea un patrón lineal en forma de espiral. Ejemplo: cuando "FOOBARBAZQUX" cercado con riel con la tecla 3.

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

Al leer la espiral de arriba línea por línea, el texto cifrado se convierte en "FAZOBRAQXOBU".

Lea más en - Cifrado de cerca de riel - Wikipedia .

El código en cualquier idioma es bienvenido.

La respuesta más corta en bytes gana.

ShuklaSannidhya
fuente
2
¿Cuál es el criterio ganador?
Paul R

Respuestas:

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

Uso de la muestra:

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

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

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

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

Nota: los resultados de recuentos pares de rieles son diferentes a los del código que proporcionó, pero parecen ser correctos. Por ejemplo, 6 rieles:

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

corresponde a AKUBJLTVCIMSWDHNRXEGOQYFPZ, y no AKUTBLVJICMSWXRDNHQYEOGZFPcomo produce su código.

La idea básica es que cada riel se puede encontrar directamente tomando segmentos de cadena [i::m], donde iestá el número de riel ( 0-indexado) y mes (num_rails - 1)*2. Además, los rieles internos deben entrelazarse [m-i::m], lo que se logra al comprimir y unir los dos conjuntos de caracteres. Debido a que el segundo de estos puede ser potencialmente un carácter más corto, se rellena con un carácter que se supone que no aparece en ningún lado ( _), y luego ese carácter se elimina si es necesario , se convierte en una lista y se rellena con una cadena vacía.


Una forma ligeramente más legible para los humanos:

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
fuente
También se necesita una función de descifrado.
ShuklaSannidhya
@ShuklaSannidhya Entonces, ¿por qué aceptaste una respuesta incompleta?
Jo King
3
@JoKing para mayor claridad, el requisito de "dos programas" se agregó un año después de que publiqué mi solución.
primo
2

APL 52 41

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

Si la cadena de texto de entrada i y el número de clave n están preinicializados, la solución puede acortarse en 9 caracteres. Ejecutar la solución contra los ejemplos dados por primo da respuestas idénticas:

FOOBARBAZQUX
3
FAZOBRAQXOBU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
4
AGMSYBFHLNRTXZCEIKOQUWDJPV

ABCDEFGHIJKLMNOPQRSTUVWXYZ
5
AIQYBHJPRXZCGKOSWDFLNTVEMU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
6
AKUBJLTVCIMSWDHNRXEGOQYFPZ

En una reflexión posterior, parece haber una solución basada en índices más corta:

i[⍋+\1,(y-1)⍴((n←⍎⍞)-1)/1 ¯1×1 ¯1+y←⍴i←⍞]
Graham
fuente
También se necesita una función de descifrado.
ShuklaSannidhya
1

Python 2 , 124 + 179 = 303 bytes

Codificar:

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

Pruébalo en línea!

Descodificar:

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

Pruébalo en línea!

Chas Brown
fuente
También necesita una función de descifrado
Jo King
@Jo King: he añadido tardíamente un descifrador.
Chas Brown
0

MATL, 70 bytes (total)

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

Pruébelo en MATL en línea
Pruebe múltiples casos de prueba

Toma una bandera como tercera entrada, Fpara cifrar la cadena, Tpara descifrarla (gracias a Kevin Cruijssen por esa idea).

Esto comenzó como una respuesta de Julia hasta que me di cuenta de que la mecanografía estricta se interponía demasiado, especialmente para descifrarla. Aquí está el código de Julia que tenía para el cifrado (respaldado a v0.6 para TIO):

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

Pruébalo en línea!

Explicación:

La operación de valla ferroviaria

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

puede verse como lectura de r = 3 caracteres de entrada, luego lectura de caracteres r-2 y prefijos y sufijos con valores ficticios (nulos), luego lectura de caracteres r nuevamente, etc., creando una nueva columna cada vez:

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

a continuación, invirtiendo cada segunda columna (desde la zag parte de zigzag sube en lugar de hacia abajo, lo que hace una diferencia cuando r> 3), entonces la lectura de esta matriz a lo largo de las filas, y la eliminación de los personajes ficticios.

El desciframiento no parecía tener ningún patrón obvio como este, pero cuando busqué sobre esto me encontré con esta publicación , que me decía que (a) este era un algoritmo bien conocido y (¿posiblemente?) Publicado para cifrado de riel, y ( b) el descifrado fue una simple reutilización del mismo método, dándole los índices de la cadena y obteniendo los índices de esos índices después del cifrado, y leyendo el texto cifrado en esos lugares.

Dado que el descifrado necesita hacer cosas al trabajar en índices, este código también cifra al clasificar los índices de la cadena y, en este caso, simplemente indexa esos índices reorganizados.

              % 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 - Restablecer a Monica
fuente
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;
}

Quiero ser explicado en este código.

gihadsaad
fuente
Como se trata de código de golf , debe intentar acortar su código. Además, debe agregar el idioma y el recuento de bytes a esta presentación
Jo King
Además de lo que dijo Jo King, podría considerar usar un servicio en línea como TIO para que otras personas puedan probar fácilmente su código.
Precioso
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 gracias a @ceilingcat .
-112 bytes que combinan las dos funciones con un indicador de modo adicional como entrada.

La función toma una tercera entrada M. Si es trueasí, lo cifrará, y si lo es false, lo descifrará.

Pruébalo en línea.

Explicación:

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