¿Qué ROT es esto? - descifrar ROT-n

25

Aquí están las letras del alfabeto inglés en orden por frecuencia:

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

Es decir, ees la letra más utilizada y zes la menos común. (Datos de Wikipedia ).

Su desafío es tomar un texto ROT-n'd, como:

ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz

Este es el texto "este es un mensaje secreto que es muy seguro y seguro" que está "encriptado" a través de ROT-21 (la mitad de 42). Su programa, utilizando la tabla de frecuencias anterior, debería poder determinar cuánto se rotó cada carácter y el texto original.

(Si no está familiarizado con ROT-n, esencialmente está cambiando cada carácter por n. Por ejemplo, en ROT-2,. a -> c, b -> d, ..., x -> z, y -> a, z -> b)

¿Cómo preguntas? El algoritmo (muy ingenuo) que debe usar es:

  • para cada ndesde 0hasta 25inclusivo, aplique ROT- -na la cadena de entrada. (Negativo nporque queremos revertir el cifrado. ROT- -nes equivalente a ROT- 26-n, si eso es más fácil).
  • Convierta cada cadena de entrada en un número sumando las frecuencias relativas de los caracteres. ees 0, tes 1, aes 2, etc. Por ejemplo, el número correspondiente para la cadena "hello"es 7 + 0 + 10 + 10 + 3 = 30.
  • encuentra la cadena que tiene el número correspondiente más bajo.
  • salida esa cadena y su correspondiente n.

Reglas:

  • la entrada puede ser razonable (STDIN, argumentos de función, desde un archivo, etc.) y, por lo tanto, puede salir (STDOUT, valor de retorno de función, a un archivo, etc.)
  • puede usar un algoritmo diferente, siempre y cuando siempre produzca resultados idénticos. Por ejemplo, tener z0 y e25 y elegir el número más alto también está bien.
  • Si dos cadenas tienen puntajes idénticos, puede elegir generar uno (o ambos) de ellos. Este es un caso extremo y no tiene que dar cuenta de ello.
  • Este es el , por lo que el código más corto en bytes ganará.

Casos de prueba:

Entrada: ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz
Salida:21 thisisaverysecretmessagethatisverysecureandsafe

Entrada: pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom
Salida:8 hellopeopleofprogrammingpuzzlescodegolfstackexchange

Entrada: ftueimeqzodkbfqpiuftdaffiqxhqeaufygefnqbqdrqofxkemrq
Salida:12 thiswasencryptedwithrottwelvesoitmustbeperfectlysafe

Entrada: jgtgkuvjghkpcnvguvecugvjcvaqwowuvfgetarv
Salida:2 hereisthefinaltestcasethatyoumustdecrypt

En caso de que se lo pregunte, aquí hay un JSFiddle del código de prueba de JavaScript que escribí, que descifró con éxito todos los casos de prueba que le arrojé.

Pomo de la puerta
fuente
Puede ser útil tener en cuenta los casos extremos. Por ejemplo, wtaaddebería dar 0 wtaadcomo resultado, y vszzcdebería dar 25 wtaadcomo resultado.
mellamokb
Debería dar puntos extra para detectar la implementación de TrippleROT-N.
user19713
@ user19713 ¿Qué es triplerot? Quiero decir, ¿cuál es la diferencia entre ROT-6 y tres veces ROT-2?
Sr. Lister
2
@mrlister es una vieja broma de criptografía que saca de quicio a TripleDES.
user19713
¿Podemos generar la raíz n después de la cadena descifrada?
MayorMonty

Respuestas:

6

GolfScript - 87

El truco aquí es construir cada rotación simultáneamente. Dado que necesitamos recorrer cada ROT y luego cada carácter, simplemente recorramos cada carácter, cortemos el alfabeto completo y luego lo comprimamos. A partir de ahí, proceda como se esperaba: cuente la puntuación para cada ROT y elija el mínimo.

Golf extra:

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

Solo un poco de 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=
couchand
fuente
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])

Corriendo

% ./rot-n <<< "pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom"
8 hellopeopleofprogrammingpuzzlescodegolfstackexchange
silbido
fuente
En lugar de sumar longitudes, puede formar listas que representan los números en unario, por ejemplo [1,1,1,1], y esto dará el mismo orden. El mapeo y la suma se convierten en lo concatMapque se puede escribir de manera sucinta utilizando una lista de comprensión. En combinación con algunos otros trucos, lo acorté a 152 caracteres: 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 caracteres

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

No estoy contento con la repetición con el descifrado al final, pero meh.

Ungolfed (si eso tiene algún sentido: P) y una versión ligeramente anterior

# 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+}%''+
Pomo de la puerta
fuente
"la entrada puede ser razonable" ayuda GolfScript. Al principio no pude entender por qué nuestros guiones parecían imprimir un carácter adicional al final, hasta que me di cuentaecho coloca una nueva línea por defecto, que el intérprete recoge.
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)

Creo que todavía se puede jugar un poco más, así que las sugerencias son bienvenidas.

Algunas notas para ayudar a entender la solución.

  • m, ny orastrea la puntuación más alta.
  • uy wrastrear el resultado de carácter y valor, respectivamente para el actuali
  • (a+a) ayuda a prevenir el desbordamiento cuando se envuelve z y es más corto que hacerlo%26
  • Tengo la frecuencia en orden inverso para poder buscar max en lugar de min.

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

mellamokb
fuente
4

C # + Linq - 273 264

Como una función que toma la cadena de entrada y devuelve la cadena decodificada y el desplazamiento (según los requisitos):

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 comentarios:

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
}

Pequeño controlador de prueba (recuerde compilar referencias System.Corepara 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
Thomas
fuente
Creo que has contado mal: tu solución actual es en realidad 263 caracteres. También puede guardar un Tuple<string,int> d
personaje
Aquí está mi versión que está muy cerca en la implementación pero un poco más corta: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
Creo que deberías estar usando Range(0, 26), no 25.
Rawling
4

dg - 137 130 129 128 bytes

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)

Ejemplos:

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

Código sin golf:

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)
rubik
fuente
¿No puedes eliminar esos espacios alrededor c - 97y (0..26)?
mniip
Solo puedo eliminar el segundo. Haciéndolo ahora. Agregaré algunos ejemplos también.
rubik
1
Nunca he oído hablar de dgantes. ¿Podría proporcionar un enlace?
TheDoctor
@TheDoctor: ¡Claro! pyos.github.io/dg es la página de inicio y pyos.github.com/dg/tutorial el tutorial.
rubik
Puede guardar un personaje sumando 7 en lugar de restar 97. Módulo 26 son lo mismo.
hammar
4

J - 92 char

Un poco de un patito feo, pero funciona. Emite el número y luego la cadena, en dos líneas.

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

Si desea que estén en la misma línea, separados por espacios, esto solo sube a 93 caracteres , pero toma una ruta más fea.

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

Una explicación para (/:'ctljapqhewvknfdsyigbmuoxrz') : En este verbo, operamos en los valores de letras como A = 0, B = 1, C = 2, etc. Para codificar los valores de letras de la cadena etaoinshrdlcumwfgypbvkjxqz, la forma más corta es tomar la permutación de clasificación para esto cuerda rara Esto se debe a que A está en el índice 4, B en el índice 19, C en 0, D en 14, y así sucesivamente; por lo tanto, la permutación de clasificación es 4 19 0 14 8 13 ...cuando la califica ( /:) y obtiene exactamente los valores numéricos paraetaoin... .

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
Algoritmo de tiburón
fuente
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"
tmartin
fuente
2

APL - 70 caracteres

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

Ejemplo:

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

Estoy seguro de que hay formas de comprimir esto aún más, e invito a cualquier otro usuario de APL a encontrar soluciones para eso.

Elias Mårtenson
fuente
66
También debe generar la cadena decidida ...
Pomo de la puerta
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)])
gcq
fuente
1

Perl: 256 caracteres (más nuevas líneas para facilitar la lectura), incluida la tabla de frecuencias:

@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;

El texto se proporciona así:

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

Quítese 12 caracteres si desea hornear los valores de ord (a) y la longitud de @f

OJW
fuente
1

Elm - 465

No va a ganar ningún premio de golf, pero crea una página web estática que muestra una lista del formulario a [(rotation number, rotated string)]medida que escribe.

Nota: todavía no funciona aquí, pero puede copiarlo y pegarlo en el editor oficial y ejecutarlo.

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)
hoosierEE
fuente
1

Pitón 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)]
dieter
fuente