Шифр залізничної огорожі


10

Напишіть дві програми:
- Один, який читає рядок і ключ і кодує рядок у шифрі за допомогою залізничного огорожі за допомогою цього ключа. - Аналогічно напишіть програму зворотної функції: розшифровка залізничної огорожі за допомогою ключа.

Для тих, хто не знає, що таке шифр залізничної огорожі, це в основному метод написання простого тексту таким чином, що він створює спіральний лінійний малюнок. Приклад - коли "FOOBARBAZQUX" залізнично огороджений за допомогою ключа 3.

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

Читаючи вищевказану спіраль по рядку, текст шифру стає "FAZOBRAQXOBU".

Детальніше читайте на - Шифр залізничного паркану - Вікіпедія .

Код на будь-якій мові вітається.

Найкоротша відповідь у байтах виграє.


2
Який критерій виграшу?
Пол Р

Відповіді:


9

Python 133 байт

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

Використання зразка:

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

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

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

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

Примітка: результати рівних підрахунків залізниць відрізняються, ніж для коду, який ви надали, але вони здаються правильними. Наприклад, 6 рейок:

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

відповідає AKUBJLTVCIMSWDHNRXEGOQYFPZ, а не так, AKUTBLVJICMSWXRDNHQYEOGZFPяк створюється ваш код.

Основна ідея полягає в тому, що кожну рейку можна знайти безпосередньо, взявши шматочки рядків [i::m], де iномер рейки ( 0-вкладений) і mє (num_rails - 1)*2. Внутрішні рейки необхідно додатково переплести [m-i::m], що досягається застібкою та з'єднанням двох наборів символів. Оскільки другий з них потенційно може бути на один символ коротшим, він заповнений символом, який, як вважається, ніде не з’являється ( _), а потім цей символ знімається, якщо потрібно, він перетворюється на список і заливається порожнім рядком.


Трохи зручніша для людини форма:

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

Також потрібна функція розшифровки.
ShuklaSannidhya

@ShuklaSannidhya Тоді чому ви прийняли неповну відповідь?
Джо Кінг

3
@JoKing для наочності, вимога "дві програми" була додана через рік після того, як я опублікував своє рішення.
примо

2

APL 52 41

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

Якщо вхідний текстовий рядок i та номер ключа n є попередньо ініціалізованими, рішення можна скоротити на 9 символів. Запуск рішення на прикладах, наведених primo, дає однакові відповіді:

FOOBARBAZQUX
3
FAZOBRAQXOBU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
4
AGMSYBFHLNRTXZCEIKOQUWDJPV

ABCDEFGHIJKLMNOPQRSTUVWXYZ
5
AIQYBHJPRXZCGKOSWDFLNTVEMU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
6
AKUBJLTVCIMSWDHNRXEGOQYFPZ

При подальшому роздумі з'являється коротше рішення на основі індексу:

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

Також потрібна функція розшифровки.
ShuklaSannidhya

1

Python 2 , 124 + 179 = 303 байт

Кодування:

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

Спробуйте в Інтернеті!

Розшифруйте:

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

Спробуйте в Інтернеті!


Вам також потрібна функція розшифровки
Jo King

@Jo King: Я із запізненням додав дешифровщик.
Час Браун

0

MATL, 70 байт (всього)

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

Спробуйте на MATL Online
Спробуйте кілька тестових випадків

Візьме прапор як третій вхід, Fщоб Tрозшифрувати рядок, розшифрувати його (спасибі Кевіну Круйссену за цю ідею).

Це почалося як відповідь Джулії, поки я не зрозумів, що суворий набір тексту заважає занадто багато, особливо для розшифровки. Ось код Юлії, який я мав для шифрування (підтримується версією v0.6 для TIO):

Юлія 0,6 , 191 байт

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

Спробуйте в Інтернеті!

Пояснення:

Операція залізничної огорожі

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

можна розглядати як читання r = 3 символи введення, потім зчитування символів r-2 та префіксацію та суфікс, що має фіктивні значення (нулі), потім знову читання r символів тощо, створюючи кожен стовпець щоразу:

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

потім обертається кожен другий стовпчик (оскільки заг- частина зигзагу йде вгору замість вниз, що має значення при r> 3), потім читаючи цю матрицю по рядках і видаляючи фіктивні символи.

Розшифровка, схоже, не мала подібних очевидних зразків, але, обшукуючи це, я натрапив на цю посаду , яка мені сказала, що (а) це добре відомий і (можливо?) Опублікований алгоритм для шифрів залізниць, б) розшифровка - це просте повторне використання того ж методу, присвоєння йому індексів рядка та отримання індексів цих індексів після шифрування та зчитування шифротексту в цих місцях.

Оскільки розшифровкою потрібно займатися, працюючи над індексами, цей код виконує шифрування також шляхом сортування індексів рядка, а потім у цьому випадку просто індексування цих переставлених індексів.

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

Я хочу пояснити в цьому коді.


Оскільки це код-гольф , вам слід спробувати скоротити код. Крім того, ви повинні додати мову та кількість байтів до цього подання
Jo King

На додаток до того, що сказав Джо Кінг, ви можете розглянути можливість використання Інтернет-сервісу типу TIO, щоб інші люди могли легко перевірити ваш код.
Οurous

0

Java 10, 459 451 445 439 327 байт

(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 байт завдяки @ceilingcat .
-112 байт, що поєднує дві функції з додатковим прапором режиму як входом.

Функція займає третій вхід M. Якщо це true, то falseвін розшифрується , а якщо це - він розшифрує.

Спробуйте в Інтернеті.

Пояснення:

(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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.