Che ROT è questo? - decodifica ROT-n


25

Ecco le lettere dell'alfabeto inglese in ordine di frequenza:

e t a o i n s h r d l c u m w f g y p b v k j x q z

Cioè, eè la lettera più usata ed zè la meno comune. (Dati da Wikipedia .)

La tua sfida è prendere del testo ROT-n'd, come:

ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz

Questo è il testo "thisisaverysecretmessagethatisverysecureandsafe" che è "crittografato" tramite ROT-21 (metà di 42). Il tuo programma, usando la tabella delle frequenze sopra, dovrebbe essere in grado di determinare di quanto è stato ruotato ogni carattere e il testo originale.

(Se non si ha familiarità con ROT-n, sta essenzialmente spostando ciascun carattere di n. Ad esempio, in ROT-2 a -> c, b -> d, ..., x -> z, y -> a, z -> b).

Come lo chiedi? L'algoritmo (molto ingenuo) che devi usare è:

  • per ciascuno nda 0a 25incluso, applicare ROT- -nalla stringa di input. (Negativo nperché vogliamo invertire la crittografia. ROT- -nè equivalente a ROT- 26-n, se è più semplice.)
  • converte ogni stringa di input in un numero sommando le frequenze relative dei caratteri. eè 0, tè 1, aè 2, ecc. Ad esempio, il numero corrispondente per la stringa "hello"è 7 + 0 + 10 + 10 + 3 = 30.
  • trova la stringa che ha il numero corrispondente più basso.
  • output quella stringa e la sua corrispondente n.

Regole:

  • l'input può essere ovunque ragionevole (STDIN, argomenti di funzione, da un file, ecc.), così come l'output (STDOUT, valore di ritorno della funzione, in un file, ecc.)
  • è possibile utilizzare un algoritmo diverso, purché produca sempre risultati identici. Ad esempio, avere z0 e e25 e anche scegliere il numero più alto va bene.
  • se due stringhe hanno punteggi identici, puoi scegliere di emetterne una (o entrambe). Questo è un caso limite e non è necessario tenerne conto.
  • questo è , quindi vincerà il codice più breve in byte!

Casi test:

Ingresso: ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz
Uscita:21 thisisaverysecretmessagethatisverysecureandsafe

Ingresso: pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom
Uscita:8 hellopeopleofprogrammingpuzzlescodegolfstackexchange

Ingresso: ftueimeqzodkbfqpiuftdaffiqxhqeaufygefnqbqdrqofxkemrq
Uscita:12 thiswasencryptedwithrottwelvesoitmustbeperfectlysafe

Ingresso: jgtgkuvjghkpcnvguvecugvjcvaqwowuvfgetarv
Uscita:2 hereisthefinaltestcasethatyoumustdecrypt

Nel caso ti stavi chiedendo, ecco un JSFiddle del codice di test JavaScript che ho scritto, che ha decifrato con successo tutti i casi di test che ho lanciato.


Potrebbe essere utile annotare i casi limite. Ad esempio, wtaaddovrebbe dare 0 wtaadcome risultato e vszzcdovrebbe dare 25 wtaadcome risultato.
mellamokb,

Dovresti dare punti extra per rilevare l'implementazione di TrippleROT-N.
user19713

@ user19713 Che cos'è triplerot? Voglio dire, qual è la differenza tra ROT-6 e tre volte ROT-2?
Lister

2
@mrlister è una vecchia battuta cripto che fa arrabbiare TripleDES.
user19713

Possiamo emettere n-root dopo la stringa decifrata?
MayorMonty,

Risposte:


6

GolfScript - 87

Il trucco qui è costruire ogni rotazione contemporaneamente. Dal momento che abbiamo bisogno di eseguire il ciclo su ogni ROT, quindi su ogni carattere, eseguiamo il ciclo su ogni carattere, suddividiamo l'intero alfabeto, quindi comprimilo. Da lì procedere come previsto: contare il punteggio per ciascun ROT e scegliere il minimo.

Extra golf:

{97- 26,{97+}%.+''+>}/]{27<}%zip:d{{"etaoinshrdlcumwfgypbvkjxqz"?}%{+}*}%.$0=?.26\-\d=

Solo un po 'di golf:

# the alphabet, and by frequency
26,{97+}%.+''+:a;
"etaoinshrdlcumwfgypbvkjxqz":f;

# build evey ROT decryption
{97-a>}/]{27<}%zip:d

# calculate likelihood
{{f?}%{+}*}%.

# find min
$0=

# output rotation factor and decryption
?.26\-\d=

8

Haskell - 192 175

f y=sum.map(\x->length.fst$break(==x)y)
main=interact(\s->snd$minimum$[(f"etaoinshrdlcumwfgypbvkjxqz"r,show(26-n)++" "++r)|n<-[0..25],let r=map(\x->([x..'z']++['a'..])!!n)s])

In esecuzione

% ./rot-n <<< "pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom"
8 hellopeopleofprogrammingpuzzlescodegolfstackexchange

Invece di sommare le lunghezze, puoi formare elenchi che rappresentano i numeri in unario, ad esempio [1,1,1,1], e questo darà lo stesso ordine. La mappatura e la somma diventano quindi concatMapche possono essere scritte in modo succinto usando una comprensione della lista. In combinazione con alcuni altri trucchi, ho accorciato a 152 caratteri: main=interact(\s->snd$minimum[([1|x<-r,_<-fst$span(/=x)"etaoinshrdlcumwfgypbvkjxqz"],show(26-n)++' ':r)|n<-[0..25],r<-[[([x..'z']++['a'..])!!n|x<-s]]]).
Hammar,

7

GolfScript, 112 108 102 100 caratteri

{{}/]{97-}%}:b~:|;"etaoinshrdlcumwfgypbvkjxqz"b:f,:&,{:x[|{&x-+&%f?}%{+}*\]}%$0=1=:x|{&x-+&%97+}%''+

Non sono contento della ripetizione con la ri-decodifica alla fine, ma meh.

Ungolfed (se questo ha un senso: P) e versione leggermente più vecchia:

# store input IDs (a = 0, b = 1, etc.) in s
[{}/]{97-}%:s;
# store frequency data IDs in f (blah, repetition)
"etaoinshrdlcumwfgypbvkjxqz"[{}/]{97-}%:f

# for each number from 0 to 26 (length of previous string left unpopped)...
,,{
  # the number is x
  :x;
  # return an array of...
  [
    # the score
    s{x 26\-+26%f?}%{+}*
    # and the n
    x
  ]
}%

# use $ort to find the n to output
$0=1=:x

# get the string that the n corresponded to (blah, more repetition)
s{x 26\-+26%97+}%''+

"l'input può essere ovunque ragionevole" aiuta GolfScript. All'inizio non riuscivo a capire perché entrambi i nostri script sembravano stampare un personaggio in più alla fine, fino a quando ho realizzato di echomettere una nuova riga di default, che l'interprete prende.
couchand

6

JavaScript (205)

f='zqxjkvbpygfwmucldrhsnioate';a='abcdefghijklmnopqrstuvwxyz';for(s=prompt(o=m=n=0)
,i=27;i--;w>m&&(m=w,n=i,o=u))for(u='',w=c=0;c<s.length;w+=f.indexOf(x))u+=x=(a+a)[a
.indexOf(s[c++])+i];alert((26-n)+' '+o)

Penso che possa ancora essere giocato un po 'di più, quindi benvenuti suggerimenti!

Alcune note per aiutare a capire la soluzione

  • m, ne otraccia il punteggio più alto.
  • ue wtraccia il carattere e il risultato del valore, rispettivamente per la correntei
  • (a+a)aiuta a prevenire lo straripamento quando si passa da una parte all'altra z, ed è più breve di così%26
  • Ho la frequenza in ordine inverso, quindi posso cercare max anziché min.

Prova: http://jsfiddle.net/J9ZyV/5/



4

C # + Linq - 273 264

Come funzione che accetta la stringa di input e restituisce la stringa decodificata e l'offset (secondo i requisiti):

static Tuple<string,int> d(string s){var r=Enumerable.Range(0,25).Select(i=>string.Concat(from c in s select (char)((c-97+i)%26+97))).OrderBy(x=>(from c in x select "etaoinshrdlcumwfgypbvkjxqz".IndexOf(c)).Sum()).First();return Tuple.Create(r,(s[0]-r[0]+26)%26);}

Ungolfed con commenti:

static Tuple<string,int> d(string s)
{
    var r=Enumerable.Range(0,25)                                               // for every possible offset i
          .Select(i=>string.Concat(from c in s select (char)((c-97+i)%26+97))) // calculate rot_i(input string)
          .OrderBy(                                                            // order these by their score
              x=>(
              from c in x select "etaoinshrdlcumwfgypbvkjxqz".IndexOf(c)       // lookup frequency of each character
              ).Sum()                                                          // and sum each frequency to get the score
           ).First();                                                          // get the first one (lowest score)

    return Tuple.Create(r,(s[0]-r[0]+26)%26);                                  // compute offset and return results
}

Piccolo driver di test (ricorda di compilare i riferimenti System.Coreper Linq):

using System;
using System.Linq;

namespace codegolf
{
    class Program
    {
        static Tuple<string,int> d(string s){var r=Enumerable.Range(0,25).Select(i=>string.Concat(from c in s select (char)((c-97+i)%26+97))).OrderBy(x=>(from c in x select "etaoinshrdlcumwfgypbvkjxqz".IndexOf(c)).Sum()).First();return Tuple.Create(r,(s[0]-r[0]+26)%26);}

        static void Main(string[] args)
        {
            while (true)
            {
                var input = Console.ReadLine();
                if (input == null) break;
                var retval = d(input);
                Console.WriteLine(String.Format("{0} {1}", retval.Item2, retval.Item1));
            }
        }
    }
}

Dando:

$ mcs /reference:System.Core.dll main.cs && mono ./main.exe
ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz
21 thisisaverysecretmessagethatisverysecureandsafe
pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom
8 hellopeopleofprogrammingpuzzlescodegolfstackexchange
ftueimeqzodkbfqpiuftdaffiqxhqeaufygefnqbqdrqofxkemrq
12 thiswasencryptedwithrottwelvesoitmustbeperfectlysafe
jgtgkuvjghkpcnvguvecugvjcvaqwowuvfgetarv
2 hereisthefinaltestcasethatyoumustdecrypt
thisisaverysecretmessagethatisverysecureandsafe
0 thisisaverysecretmessagethatisverysecureandsafe

Penso che tu abbia contato male - la tua soluzione attuale è in realtà 263 caratteri. Inoltre puoi salvare un altro carattere rimuovendo lo spazio traTuple<string,int> d
mellamokb

Ecco la mia versione che è molto vicina all'implementazione ma un po 'più breve:Tuple<int,string>f(string x){return Enumerable.Range(0,25).Select(n=>Tuple.Create(26-n,string.Concat(x.Select(c=>(char)((c-97+n)%26+97))))).OrderBy(t=>(t.Item2.Select(c=>"etaoinshrdlcumwfgypbvkjxqz".IndexOf(c))).Sum()).First();}
porges

Penso che dovresti usare Range(0, 26), no 25.
Rawling

4

dg - 137 130 129 128 byte

f=t->min key:(t->sum$map 'etaoinshrdlcumwfgypbvkjxqz'.index$snd t)$map(n->n,''.join$map(c->chr$((ord c + 7-n)%26+ 97))t)(0..26)

Esempi:

>>> f 'ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz'
(21, 'thisisaverysecretmessagethatisverysecureandsafe')
>>> f 'pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom'
(8, 'hellopeopleofprogrammingpuzzlescodegolfstackexchange')
>>> f 'ftueimeqzodkbfqpiuftdaffiqxhqeaufygefnqbqdrqofxkemrq'
(12, 'thiswasencryptedwithrottwelvesoitmustbeperfectlysafe')
>>> f 'jgtgkuvjghkpcnvguvecugvjcvaqwowuvfgetarv'
(2, 'hereisthefinaltestcasethatyoumustdecrypt')

Codice non golfato:

func = t ->
  #: Compute the score of the text `t` with respect to the frequency table.
  #: score :: (int, str) -> int
  score = t ->
    sum $ map 'etaoinshrdlcumwfgypbvkjxqz'.index $ snd t

  #: Compute rot-n of the string `t`. Return the offset and the shifted text.
  #: rot :: int -> (int, str)
  rot = n ->
    n, ''.join $ map (c->chr $ ((ord c + 7 - n) % 26 + 97)) t

  # return the minimum (computed by `score`) amongst all shifted messages
  min key: score $ map rot (0..26)

Non riesci a rimuovere quegli spazi intorno c - 97e (0..26)?
mniip,

Posso solo rimuovere il secondo. Fallo ora. Aggiungerò anche alcuni esempi.
rubik,

1
Mai sentito parlare dgprima. Può fornire un link?
TheDoctor

@TheDoctor: Certo! pyos.github.io/dg è la homepage e pyos.github.com/dg/tutorial il tutorial.
rubik,

Puoi salvare un personaggio aggiungendo 7 invece di sottrarre 97. Modulo 26 sono la stessa cosa.
Hammar,

4

J - 92 char

Un brutto anatroccolo, ma funziona. Emette il numero e quindi la stringa, su due righe.

(26|](-1!:2&2&.":)(/:'ctljapqhewvknfdsyigbmuoxrz')+/@i."1(i.<./@:)26|(i.-27)+/])&.(_97+3&u:)

Se vuoi che siano sulla stessa linea, separati da spazio, questo arriva solo a 93 caratteri , ma prende una strada più brutta.

((":@],[:u:32,97+26|-)(/:'ctljapqhewvknfdsyigbmuoxrz')+/@i."1(i.<./@:)26|(i.-27)+/])@(7+3&u:)

Una spiegazione per (/:'ctljapqhewvknfdsyigbmuoxrz'): In questo verbo, operiamo sui valori delle lettere come A = 0, B = 1, C = 2, ecc. Per codificare i valori delle lettere della stringa etaoinshrdlcumwfgypbvkjxqz, il modo più breve è effettivamente prendere la permutazione di ordinamento per questo stringa strana. Questo perché A è all'indice 4, B all'indice 19, C a 0, D a 14 e così via; quindi la permutazione dell'ordinamento è 4 19 0 14 8 13 ...quando la classifichi ( /:) e ottieni esattamente i valori numerici per etaoin....

Uso:

   (26|](-1!:2&2&.":)(/:'ctljapqhewvknfdsyigbmuoxrz')+/@i."1(i.<./@:)26|(i.-27)+/])&.(_97+3&u:) 'ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz'
21
thisisaverysecretmessagethatisverysecureandsafe

   NB. naming for convenience
   f =: (26|](-1!:2&2&.":)(/:'ctljapqhewvknfdsyigbmuoxrz')+/@i."1(i.<./@:)26|(i.-27)+/])&.(_97+3&u:)
   f 'pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom'
8
hellopeopleofprogrammingpuzzlescodegolfstackexchange
   f 'wtaad'
0
wtaad

3

q, 97

{(w;m w:g?min g:(+/')("etaoinshrdlcumwfgypbvkjxqz"!t)m:(t!u!/:rotate[;u:.Q.a]'[(-)t:(!)26])@\:x)}

.

q) tests:(
    "ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvazocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz";
    "pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom";
    "ftueimeqzodkbfqpiuftdaffiqxhqeaufygefnqbqdrqofxkemrq";
    "jgtgkuvjghkpcnvguvecugvjcvaqwowuvfgetarv")

q) f:{(w;m w:g?min g:(+/')("etaoinshrdlcumwfgypbvkjxqz"!t)m:(t!u!/:rotate[;u:.Q.a]'[(-)t:(!)26])@\:x)}

q) f each tests
21 "thisisaverysecretmessagethatisverysecureandsafethisisaverysecretmessagethatisverysecureandsafe"
8  "hellopeopleofprogrammingpuzzlescodegolfstackexchange"
12 "thiswasencryptedwithrottwelvesoitmustbeperfectlysafe"
2  "hereisthefinaltestcasethatyoumustdecrypt"

2

APL - 70 caratteri

F←{↑⍋+/'etaoinshrdlcumwfgypbvkjxqz'⍳⊃(⍳26){l[(⍺⌽l←⎕UCS 97+⍳26)⍳⍵]}¨⊂⍵}

Esempio:

      F 'ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz'
21
      F 'pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom'
8
      F 'ftueimeqzodkbfqpiuftdaffiqxhqeaufygefnqbqdrqofxkemrq'
12
      F 'jgtgkuvjghkpcnvguvecugvjcvaqwowuvfgetarv'
2

Sono sicuro che ci sono modi per comprimerlo ulteriormente e invito tutti gli altri utenti APL a trovare soluzioni per questo.


6
Devi anche emettere la stringa decisa ...
Maniglia della porta

2

Python 188

x="abcdefghijklmnopqrstuvwxyz"
y=input()
r=lambda n:"".join(x[x.find(i)-n]for i in y)
s={sum("etaoinshrdlcumwfgypbvkjxqz".find(b)for b in r(a)):(a,r(a))for a in range(26)}
print(s[min(s)])

1

Perl: 256 caratteri (più newline per la leggibilità) inclusa la tabella delle frequenze:

@f=unpack("W*","etaoinshrdlcumwfgypbvkjxqz");
@c=unpack("W*",<>);$m=ord("a");$b=1E10;
for$n(0..25){$s=0;$t="";
for$x(0..scalar@c){$r=($c[$x]-$n-$m)%26+$m;$t.=chr($r);
for(0..scalar@f){if($r==$f[$_]){$s+=$_}}}
if($s<$b){$b=$s;$w=$t;$a=$n}}
printf"%d %s\n",$a,$w;

Il testo viene fornito in questo modo:

echo "ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz" | perl ./freq.pl 
21 thisisaverysecretmessagethatisverysecureandsafewm

Togli 12 caratteri se desideri inserire i valori di ord (a) e la lunghezza di @f


1

Olmo - 465

Non vincerà alcun premio di golf, ma crea una pagina Web statica che visualizza un elenco del modulo [(rotation number, rotated string)]durante la digitazione.

Nota: non funziona ancora qui ma è possibile copiarlo e incollarlo nell'editor ufficiale ed eseguirlo.

import String as S
import Char (..)
import Graphics.Input (..)
import Graphics.Input.Field (..)
f="ETAOINSHRDLCUMWFGYPBVKJXQZ"
r s n=let t c=mod(toCode c-65+n)26+65 in map(fromCode . t)(S.toList s)
w s=case s of 
 ""->0
 s->sum(S.indexes(S.left 1 s)f)+w(S.dropLeft 1 s)
b s=sort<|map(\x->((w . S.fromList . r s)x,(26-x,S.fromList<|r s x)))[0..25]
c=input noContent
main=above<~(field defaultStyle c.handle id""<~c.signal)~(asText . b . .string<~c.signal)

1

Python 2, 171

f,R,i='zqxjkvbpygfwmucldrhsnioate',{},raw_input();a=sorted(f)*2
for n in range(26):_=''.join(a[ord(x)-71-n]for x in i);R[sum(2**f.index(x)for x in _)]=n,_
print R[max(R)]
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.