Qu'est-ce que c'est ROT? - déchiffrer ROT-n


25

Voici les lettres de l'alphabet anglais par ordre de fréquence:

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

C'est-à-dire que ec'est la lettre la plus utilisée et zla moins courante. (Données de Wikipedia .)

Votre défi est de prendre du texte ROT-n'd, tel que:

ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz

Il s'agit du texte "thisisaverysecretmessagethatisverysecureandsafe" qui est "crypté" via ROT-21 (la moitié de 42). Votre programme, en utilisant le tableau des fréquences ci-dessus, devrait être en mesure de déterminer la rotation de chaque caractère et le texte d'origine.

(Si vous n'êtes pas familier avec ROT-n, il déplace essentiellement chaque caractère de n. Par exemple, dans ROT-2,. a -> c, b -> d, ..., x -> z, y -> a, z -> b)

Comment, demandez-vous? L'algorithme (très naïf) que vous devez utiliser est:

  • pour chacun nde 0à 25inclusif, appliquez ROT- -nà la chaîne d'entrée. (Négatif nparce que nous voulons inverser le cryptage. ROT- -nest équivalent à ROT- 26-n, si c'est plus facile.)
  • convertir chaque chaîne d'entrée en nombre en additionnant les fréquences relatives des caractères. eest 0, test 1, aest 2, etc. Par exemple, le nombre correspondant pour la chaîne "hello"est 7 + 0 + 10 + 10 + 3 = 30.
  • recherchez la chaîne qui a le plus petit nombre correspondant.
  • sortie cette chaîne et son correspondant n.

Règles:

  • l'entrée peut être n'importe où raisonnable (STDIN, arguments de fonction, à partir d'un fichier, etc.), tout comme la sortie (STDOUT, valeur de retour de fonction, dans un fichier, etc.)
  • vous pouvez utiliser un algorithme différent, tant qu'il produit toujours des résultats identiques. Par exemple, avoir z0 et e25 et choisir le nombre le plus élevé est également acceptable.
  • si deux chaînes ont des scores identiques, vous pouvez choisir d'en sortir une (ou les deux). Il s'agit d'un cas de pointe et vous n'avez pas à en tenir compte.
  • c'est le , donc le code le plus court en octets gagnera!

Cas de test:

Entrée: ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz
Sortie:21 thisisaverysecretmessagethatisverysecureandsafe

Entrée: pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom
Sortie:8 hellopeopleofprogrammingpuzzlescodegolfstackexchange

Entrée: ftueimeqzodkbfqpiuftdaffiqxhqeaufygefnqbqdrqofxkemrq
Sortie:12 thiswasencryptedwithrottwelvesoitmustbeperfectlysafe

Entrée: jgtgkuvjghkpcnvguvecugvjcvaqwowuvfgetarv
Sortie:2 hereisthefinaltestcasethatyoumustdecrypt

Au cas où vous vous poseriez la question, voici un JSFiddle du code de test JavaScript que j'ai écrit, qui a réussi à décrypter tous les cas de test que je lui ai lancés.


Il pourrait être utile de noter les cas marginaux. Par exemple, wtaaddevrait donner 0 wtaadcomme résultat et vszzcdevrait donner 25 wtaadcomme résultat.
mellamokb

Vous devez donner des points supplémentaires pour détecter la mise en œuvre de TrippleROT-N.
user19713

@ user19713 Qu'est-ce que le triplerot? Je veux dire, quelle est la différence entre ROT-6 et trois fois ROT-2?
M. Lister

2
@mrlister c'est une vieille blague crypto qui enlève la pisse de TripleDES.
user19713

Pouvons-nous sortir la n-racine après la chaîne déchiffrée?
MayorMonty

Réponses:


6

GolfScript - 87

La triche ici est de construire chaque rotation simultanément. Étant donné que nous devons parcourir chaque ROT puis chaque caractère, passons simplement en revue chaque caractère, coupons l'alphabet entier, puis zippons-le. De là, procédez comme prévu: comptez le score pour chaque ROT et choisissez le minimum.

Extra golf:

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

Seulement un peu 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=

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])

Fonctionnement

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

Au lieu de sommer les longueurs, vous pouvez former des listes représentant les nombres en unaire, par exemple [1,1,1,1], et cela donnera le même ordre. La cartographie et la somme deviennent alors concatMapce qui peut être écrit succinctement en utilisant une compréhension de liste. Combiné avec quelques autres trucs, j'écourté à 152 caractères: 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 caractères

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

Je ne suis pas content de la répétition avec le re-décryptage à la fin, mais meh.

Version non golfée (si cela a du sens: P) et version légèrement plus ancienne:

# 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'entrée peut être n'importe où raisonnable" aide GolfScript. Au début, je ne pouvais pas comprendre pourquoi nos deux scripts semblaient imprimer un caractère supplémentaire à la fin, jusqu'à ce que je réalise que echomet une nouvelle ligne par défaut, que l'interprète reprend.
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)

Je pense qu'il peut encore être joué un peu plus, alors les suggestions sont les bienvenues!

Quelques notes pour aider à comprendre la solution

  • m, nEt osuivre le score le plus élevé.
  • uet wsuivre le résultat du caractère et de la valeur, respectivement pour le couranti
  • (a+a)aide à prévenir le débordement lors du passage dans le passé z, et est plus court que de le faire%26
  • J'ai la fréquence dans l'ordre inverse afin que je puisse rechercher max au lieu de min.

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



4

C # + Linq - 273 264

En tant que fonction qui prend la chaîne d'entrée et renvoie la chaîne décodée et le décalage (selon les exigences):

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

Non golfé avec des commentaires:

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
}

Petit pilote de test (pensez à compiler le référencement System.Corepour 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));
            }
        }
    }
}

Donnant:

$ 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

Je pense que vous avez mal compté - votre solution actuelle est en fait 263 caractères. Vous pouvez également enregistrer un autre caractère en supprimant l'espace entreTuple<string,int> d
mellamokb

Voici ma version qui est très proche de l'implémentation mais un peu plus courte: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

Je pense que vous devriez utiliser Range(0, 26), non 25.
Rawling

4

dg - 137 130 129 128 octets

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)

Exemples:

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

Code non 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)

Vous ne pouvez pas supprimer ces espaces autour c - 97et (0..26)?
mniip

Je ne peux que supprimer le second. Faire maintenant. J'ajouterai également quelques exemples.
rubik

1
Jamais entendu parler dgauparavant. Pourriez-vous fournir un lien?
TheDoctor

@TheDoctor: Bien sûr! pyos.github.io/dg est la page d'accueil et pyos.github.com/dg/tutorial le tutoriel.
rubik

Vous pouvez enregistrer un caractère en ajoutant 7 au lieu de soustraire 97. Modulo 26 c'est la même chose.
hammar

4

J - 92 car

Un petit vilain petit canard, mais ça marche. Sort le nombre puis la chaîne, sur deux lignes.

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

Si vous voulez qu'ils soient sur la même ligne, séparés par des espaces, cela ne monte que jusqu'à 93 caractères , mais prend un itinéraire plus laid.

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

Une explication pour (/:'ctljapqhewvknfdsyigbmuoxrz'): Dans ce verbe, nous opérons sur les valeurs des lettres comme A = 0, B = 1, C = 2, etc. Pour encoder les valeurs des lettres de la chaîne etaoinshrdlcumwfgypbvkjxqz, le moyen le plus court est en fait de prendre la permutation de tri pour chaîne étrange. En effet, A est à l'index 4, B à l'index 19, C à 0, D à 14, etc. par conséquent, la permutation de tri est 4 19 0 14 8 13 ...lorsque vous la notez ( /:) et que vous obtenez exactement les valeurs numériques pour etaoin....

Usage:

   (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 caractères

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

Exemple:

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

Je suis sûr qu'il existe des moyens de compresser davantage cela, et j'invite tous les autres utilisateurs APL à trouver des solutions pour cela.


6
Vous devez également sortir la chaîne choisie ...
Poignée de porte

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 caractères (plus de nouvelles lignes pour la lisibilité), y compris le tableau des fréquences:

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

Le texte est fourni comme suit:

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

Enlevez 12 caractères si vous voulez incorporer les valeurs de ord (a) et la longueur de @f


1

Orme - 465

Ne va pas gagner de prix de golf, mais il crée une page Web statique qui affiche une liste du formulaire [(rotation number, rotated string)]que vous tapez.

Remarque: ne fonctionne pas encore ici, mais vous pouvez le copier-coller dans l'éditeur officiel et l'exécuter.

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)]
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.