Cifra del recinto ferroviario


10

Scrivi due programmi:
- Uno che legge una stringa e una chiave e codifica la stringa in un codice rail-fence usando quella chiave. - Allo stesso modo, scrivere un programma per la funzione inversa: decifrare una guida di binario usando un tasto.

Per coloro che non sanno cosa sia il codice binario, è fondamentalmente un metodo per scrivere testo semplice in modo da creare un motivo lineare a spirale. Esempio - quando "FOOBARBAZQUX" recintato su rotaia usando il tasto 3.

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

Leggendo la spirale sopra riga per riga, il testo della cifra diventa "FAZOBRAQXOBU".

Maggiori informazioni su - Rail fence cifratura - Wikipedia .

Il codice in qualsiasi lingua è il benvenuto.

Vince la risposta più breve in byte.


2
Qual è il criterio vincente?
Paul R,

Risposte:


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

Esempio di utilizzo:

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

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

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

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

Nota: i risultati del conteggio dei binari pari sono diversi rispetto al codice fornito, ma sembrano essere corretti. Ad esempio, 6 binari:

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

corrisponde AKUBJLTVCIMSWDHNRXEGOQYFPZe non AKUTBLVJICMSWXRDNHQYEOGZFPcome il codice produce.

L'idea di base è che ogni binario può essere trovato direttamente prendendo sezioni di stringa [i::m], dove si itrova il numero del binario ( 0-indexed), ed mè (num_rails - 1)*2. Inoltre, è necessario intrecciare le rotaie interne [m-i::m], ottenute zippando e unendo le due serie di caratteri. Poiché il secondo di questi può potenzialmente essere più corto di un carattere, viene riempito con un carattere che si presume non appaia da nessuna parte ( _), quindi quel carattere viene rimosso se necessario viene convertito in un elenco e riempito con una stringa vuota.


Una forma leggermente più leggibile dall'uomo:

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

È inoltre necessaria una funzione di decodifica.
ShuklaSannidhya,

@ShuklaSannidhya Allora perché hai accettato una risposta incompleta?
Jo King,

3
@JoKing per chiarezza, il requisito "due programmi" è stato aggiunto un anno dopo aver pubblicato la mia soluzione.
primo

2

52 APL 41

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

Se la stringa di testo di input i e il numero chiave n sono preinizializzati, la soluzione può essere abbreviata di 9 caratteri. L'esecuzione della soluzione rispetto agli esempi forniti da primo fornisce risposte identiche:

FOOBARBAZQUX
3
FAZOBRAQXOBU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
4
AGMSYBFHLNRTXZCEIKOQUWDJPV

ABCDEFGHIJKLMNOPQRSTUVWXYZ
5
AIQYBHJPRXZCGKOSWDFLNTVEMU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
6
AKUBJLTVCIMSWDHNRXEGOQYFPZ

Su ulteriori riflessioni sembra esserci una soluzione basata su indici più breve:

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

È inoltre necessaria una funzione di decodifica.
ShuklaSannidhya,

1

Python 2 , 124 + 179 = 303 byte

Codificare:

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

Provalo online!

Decodificare:

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

Provalo online!


È inoltre necessaria una funzione di decodifica
Jo King,

@Jo King: ho tardivamente aggiunto un decifratore.
Chas Brown,

0

MATL, 70 byte (totale)

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

Provalo su MATL Online
Prova più casi di test

Prende una bandiera come terzo input, Fper crittografare la stringa, Tper decifrarla (grazie a Kevin Cruijssen per quell'idea).

Questo è iniziato come una risposta di Julia fino a quando ho capito che la battitura rigorosa mi ha ostacolato troppo, specialmente per la decifrazione. Ecco il codice Julia che avevo per la crittografia (backported alla v0.6 per 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)))[:]),"ø","")

Provalo online!

Spiegazione:

L'operazione di recinzione ferroviaria

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

può essere visto come lettura di r = 3 caratteri di input, quindi lettura di r-2 caratteri e prefisso e suffisso quello con valori fittizi (null), quindi lettura di nuovo r caratteri, ecc., creando una nuova colonna ogni volta:

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

quindi inverte ogni seconda colonna (poiché il zag parte zigzag sale anziché verso il basso, che fa la differenza quando r> 3), allora la lettura di questa matrice lungo le righe e rimuovendo i caratteri fittizi.

La decifrazione non sembrava avere schemi ovvi come questo, ma quando ho cercato in questo mi sono imbattuto in questo post , che mi ha detto che (a) questo era un algoritmo ben noto e (forse?) Pubblicato per i codici ferroviari, e ( b) la decifrazione era un semplice riutilizzo dello stesso metodo, dandogli gli indici della stringa e ottenendo gli indici di quegli indici dopo la crittografia, e leggendo il testo cifrato in quei punti.

Poiché la decifrazione deve fare le cose lavorando sugli indici, questo codice esegue la crittografia anche ordinando gli indici della stringa, e quindi in questo caso semplicemente indicizzando quegli indici riorganizzati.

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

Voglio essere spiegato in questo codice.


Dato che si tratta di code-golf , dovresti provare ad accorciare il tuo codice. Inoltre, è necessario aggiungere la lingua e il conteggio dei byte a questo invio
Jo King,

Oltre a ciò che ha detto Jo King, potresti prendere in considerazione l'utilizzo di un servizio online come TIO in modo che altre persone possano facilmente testare il tuo codice.
Οuroso

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 grazie a @ceilingcat .
-112 byte combinando le due funzioni con un flag di modalità aggiuntivo come input.

La funzione accetta un terzo input M. In tal caso true, verrà codificato e in tal falsecaso verrà decifrato.

Provalo online.

Spiegazione:

(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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.