Chiffrement incrémental

19

Cette tâche est assez simple et utilise trois caractères "d'opérateur" distincts. Votre tâche est, étant donné une simple séquence de lettres, effectuer la tâche suivante pour encoder en utilisant <, >, *. Vous pouvez choisir d'utiliser des lettres majuscules ou minuscules, vous n'avez pas à gérer les deux.


Explication du chiffre

Le chiffrement est simple, vous utilisez des opérations d'incrémentation et de décrémentation pour passer de la lettre 1 à la lettre de fin, en *étant votre fonction "soumettre". L'opérateur pour "incrémenter" sera >et "décrémenter" sera <.

Un exemple utilisant le mot adbc:

  • Commencez par la première lettre du mot, sortez cette lettre. a
  • Ensuite, utilisez >et <(comme brainfuck) pour "naviguer" de la lettre actuelle à la suivante. a>entraînerait une «augmentation» ade 1 à la lettre b. a<entraînerait zparce que vous abaissez la lettre (il encapsule, vous devez toujours choisir la direction résultant dans le nombre MOINS d'opérations).
  • Après avoir sorti la combinaison minimisée correcte de <et >sorti un *pour indiquer que nous avons atteint la lettre suivante.

Les étapes à coder adbcseraient les suivantes:

a          # a
a>>>*      # ad
a>>>*<<*   # adb
a>>>*<<*>* # adbc

Exemples

Les étapes à coder azaseraient les suivantes:

a       # a
a<*     # az
a<*>*   # aza

Plus d'exemples:

"abcdef"    =  "a>*>*>*>*>*"
"zyaf"      =  "z<*>>*>>>>>*"
"zzzzzz"    =  "z*****"
"z"         =  "z"
"zm"        =  "z<<<<<<<<<<<<<*" or "z>>>>>>>>>>>>>*" (equidistant)
"zl"        =  "z>>>>>>>>>>>>*"
"alphabet"  =  "a>>>>>>>>>>>*>>>>*<<<<<<<<*<<<<<<<*>*>>>*<<<<<<<<<<<*"
"banana"    =  "b<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*" OR "b<*<<<<<<<<<<<<<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*>>>>>>>>>>>>>*"
"abcdefghijklmnopqrstuvwxyz" = "a>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*"
"abcdefz"   =  "a>*>*>*>*>*<<<<<<*"

Règles

  • Nous n'encodons pas, nous ne décodons donc pas.
  • Vous pouvez supposer que le message contiendra des lettres [A-Z]ou [a-z], votre choix.
  • Vous pouvez utiliser n'importe quel caractère non-lettre / numérique / réservé pour indiquer *(EG $).
  • Vous devez avoir la fin *, ce n'est pas implicite sur les répétitions.
  • Vous ne pouvez supposer aucune chaîne vide, mais un seul caractère est possible.
  • S'il est équidistant dans un sens ou dans l'autre jusqu'à la lettre suivante, vous pouvez choisir une direction.
  • Il s'agit du , le plus petit nombre de victoires d'octets.

Veuillez expliquer votre réponse, cela aide les autres à apprendre de cette façon.

Urne de poulpe magique
la source
Juste pour être clair, le dernier cas de test représente abcdefghijklmnopqrstuvwxyzet n'est pas sa propre entrée?
Nick Clifford
1
@ NickClifford oui.
Urne de poulpe magique
Je pense que zldevrait utiliser >.
xnor
4
Pourriez-vous s'il vous plaît vérifier les exemples? alphabetest à mon avis a>>>>>>>>>>>*>>>>*<<<<<<<<*<<<<<<<*>*>>>*<<<<<<<<<<<*et zldevrait être z>>>>>>>>>>>>*et pour bananasi une deuxième solution existeb<*<<<<<<<<<<<<<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*>>>>>>>>>>>>>*
Jörg Hülsermann
@xnor correct, était une faute de frappe manuelle de zm. @jorg de bonnes captures, toutes corrigées, était un effort manuel.
Urne de poulpe magique

Réponses:

2

Gelée , 17 octets

OIżN$ẋ"@€⁾><;€⁶ṭḢ

Utilise un caractère espace à la place de *(un espace , ou une nouvelle ligne , enregistre un octet de plus ”*).

Fonctionne avec une entrée en majuscules uniquement ou en minuscules uniquement.

Essayez-le en ligne! ou consultez une suite de tests (où ces espaces sont post-remplacés par*pour faciliter la lecture).

Comment?

OIżN$ẋ"@€⁾><;€⁶ṭḢ - Main link: string s          e.g. "adbc"
O                 - cast s to ordinals                [97,100,98,99]
 I                - incremental differences           [3,-2,1]
    $             - last two links as a monad:
   N              -     negate                        [-3,2,-1]
  ż               -     zip together                  [[3,-3],[-2,2],[1,-1]]
         ⁾><      - literal ['>','<']                 "><"
      "@€         - using reversed @arguments for €ach zip with("):
     ẋ            -     repeat (-n are like zeros)    [[">>>",""],["","<<"],[">",""]]
            ;€    - concatenate €ach with:
              ⁶   -     literal ' '                   [[">>>","",' '],["","<<",' '],[">","",' ']]
               ṭ  - tack to:
                Ḣ -     head of s (1st char)          [['a'],[">>>","",' '],["","<<",' '],[">","",' ']]
                  - implicit print   (" not printed:) "a>>> << > "
Jonathan Allan
la source
11

8086 code machine, 70 68 67 octets

00000000  be 82 00 bf 43 01 57 31  d2 ac 3c 0d 74 2c 89 d1  |....C.W1..<.t,..|
00000010  88 c2 aa e3 f4 4f 28 c1  9f 88 e7 79 02 f6 d9 83  |.....O(....y....|
00000020  f9 0d 9f 76 05 83 e9 1a  f6 d9 30 fc 9e b0 3c 78  |...v......0...<x|
00000030  02 b0 3e f3 aa b0 2a aa  eb cf c6 05 24 b4 09 5a  |..>...*.....$..Z|
00000040  cd 21 c3                                          |.!.|
00000043

Comment ça fonctionne:

            |   org 0x100
            |   use16
be 82 00    |       mov si, 0x82        ; source = command line arguments
bf 43 01    |       mov di, result      ; destination = result
57          |       push di
31 d2       |       xor dx, dx          ; clear dx
ac          |   n:  lodsb               ; al = *si++
3c 0d       |       cmp al, 0x0d        ; end of input reached? (newline)
74 2c       |       je q                ; jump to exit in that case
89 d1       |   @@: mov cx, dx          ; store last char in cl
88 c2       |       mov dl, al          ; and store the current char in dl
aa          |       stosb               ; *di++ = al
e3 f4       |       jcxz n              ; skip encoding this char if cx == 0 (only happens for the first char)
4f          |       dec di              ; move di pointer back
28 c1       |       sub cl, al          ; take the difference between this char and the last one
9f          |       lahf                ; store flags from last subtraction in bh
88 e7       |       mov bh, ah
79 02       |       jns @f
f6 d9       |       neg cl              ; make sure cl is positive
83 f9 0d    |   @@: cmp cl, 13          ; which way is shorter?
9f          |       lahf                ; also store these flags
76 05       |       jbe @f
83 e9 1a    |       sub cl, 26          ; invert cl if we're going backwards
f6 d9       |       neg cl
30 fc       |   @@: xor ah, bh          ; xor saved flags together
9e          |       sahf                ; load flags register with the result
b0 3c       |       mov al, '<'
78 02       |       js @f               ; now the sign flag tells us which operator to use
b0 3e       |       mov al, '>'
f3 aa       |   @@: rep stosb           ; while (cx--) *di++ = al
b0 2a       |       mov al, '*'         ; mark the end with an asterisk
aa          |       stosb
eb cf       |       jmp n               ; repeat
c6 05 24    |   q:  mov byte [di], '$'  ; mark end of string
b4 09       |       mov ah, 0x09        ; dos function: print string
5a          |       pop dx              ; dx = string pointer
cd 21       |       int 0x21            ; syscall
c3          |       ret
            |   result rb 0
user5434231
la source
Cette. C'est plus que cool. Vous l'avez fait VRAIMENT rapidement aussi, dang.
Urne de poulpe magique
Merci. C'est à peu près la solution triviale. Il se trouve que c'est assez court en 8086.
user5434231
10

Python 3 , 87 octets

r,*s=input();p=r
for c in s:d=(ord(p)-ord(c)-13)%26-13;r+='<'*d+'>'*-d+'*';p=c
print(r)

Essayez-le en ligne!

Fonctionne avec des minuscules ou des majuscules.

Le programme crée la chaîne de sortie ren itérant sur les caractères de la chaîne d'entrée. Il stocke le caractère précédent sous la forme pet calcule l'opération d'incrémentation pour passer du pnouveau caractère c.

L'intervalle entre les caractères est ord(c)-ord(p), et le (ord(c)-ord(p)-13)%26-13prend modulo 26 à l'intervalle [-13..12]. Un résultat négatif signifie qu'il est plus court de démissionner, et un résultat positif signifie de passer à l'étape supérieure. Cela doit être converti en une chaîne de >ou en <fonction du signe. Plutôt que d'utiliser absou un conditionnel, nous profitons de la multiplication de chaînes de Python s*ndonnant la chaîne vide quand nest négatif. Dans l'expression '<'*-d+'>'*d, la partie mal signée ne contribue pas.

L'état initial est géré en divisant l'entrée en son premier caractère et le reste avec le déballage de Python 3 r,*s=input(). Le caractère initial est utilisé pour commencer la construction de la chaîne, ainsi que le caractère "précédent" initial.

Merci aux ovs d'avoir suggéré de passer à Python 3 pour faire ce déballage.

xnor
la source
6

Python 3 , 110 93 octets

r,*s=input()
b=r
for a in s:d=(ord(a)-ord(b))%26;r+=['>'*d,'<'*(26-d)][d>13]+'*';b=a
print(r)

Essayez-le en ligne!

ovs
la source
Ooo ... Fonctionne à la fois en bas et en majuscule, sympa (mais je pense que vous pouvez raser les octets en supposant l'un ou l'autre).
Urne de poulpe magique
Explication s'il vous plaît?
Camarade SparklePony
3

JavaScript (ES6), 118 109 107 octets

La chaîne d'entrée n'est pas sensible à la casse.

s=>s.replace(/./g,(c,i)=>(d=~~s-(s=parseInt(c,36)),i)?'<><>'[k=d/13+2|0].repeat([d+26,-d,d,26-d][k])+'*':c)

Comment ça fonctionne

Contrairement à Python, l'opérateur JS modulo renvoie un nombre ayant le même signe que le dividende plutôt que le diviseur. En outre, la repeat()méthode JS génère une erreur lorsqu'elle reçoit un nombre négatif, plutôt que de renvoyer une chaîne vide (et c'est de toute façon beaucoup plus long qu'une simple *).

Ce sont des comportements plutôt défavorables pour ce défi. Donc, nous ferions mieux d'identifier dans quel cas exact nous sommes plutôt que de compter sur des astuces mathématiques. (Ce qui ne signifie pas que de telles astuces n'existent pas, mais plutôt que je n'ai pas réussi à les trouver.)

Ci-dessous un tableau décrivant les 4 cas possibles, où dest la distance signée entre le caractère actuel et le précédent:

d           | floor(d / 13) + 2 | direction | repeat
------------+-------------------+-----------+-------
-25 ... -14 |         0         |     <     | d + 26
-13 ... -1  |         1         |     >     | -d  
 +0 ... +12 |         2         |     <     | +d  
+13 ... +25 |         3         |     >     | 26 - d

Cas de test

Arnauld
la source
2

PHP, 127 octets

for($l=ord($r=($s=$argn)[0]);$x=ord($s[++$i]);$l=$x)$r.=str_pad("",($a=abs($n=$l-$x))<14?$a:26-$a,"><"[$n>0^$a>13])."*";echo$r;

Cas de test

PHP, 137 octets

for($l=$r=($s=$argn)[0];$s[++$i];$l=$s[$i])$r.=str_pad("",$d=min($a=abs(ord($l)-ord($s[$i])),$b=26-$a),"><"[$d<$b^$l<$s[$i]])."*";echo$r;

Cas de test

Jörg Hülsermann
la source
2

JavaScript (ES6), 111 103 octets

f=
s=>s.replace(/./g,(c,i)=>(p=(n+26-(n=parseInt(c,36)))%26,i?'<>'[p+3>>4].repeat(p>13?26-p:p)+'*':c),n=0)
<input oninput=o.textContent=f(this.value)><pre id=o>

s=>[...s].map(c=>(n=parseInt(c,36),p&&(p=(n+26-p)%26,s+='><'[p+3>>4].repeat(p>13?26-p:p)+'*'),p=n),s=s[p=0])&&s

Version à l'origine qui prenait 111 octets avant que j'adapte l'astuce de configuration @ Arnauld nlors du calcul p, je pense qu'il y a probablement une autre astuce à utiliser à la splace, nmais il se fait tard, donc je ne m'embêterai pas .:

Neil
la source
2

Haskell (lambdabot), 161 153 octets

w(s:n)=s:(join.snd$mapAccumL(ap(,).g)s n);g c n|q<-[c..'z']++['a'..c],(Just l,s)<-minimum$first(elemIndex n)<$>[(q,'>'),(reverse q,'<')]=(s<$[1..l])++"*"

Essayez-le en ligne!


Explication:

-- Encode a single letter
g c n | q          <- [c..'z']++['a'..c]        -- The alphabet starting from letter c, looping around
      , (Just l,s) <- minimum                   -- Choose the smallest of ..
                    $ first(elemIndex n)        -- the index of the letter n ..
                  <$> [(q,'>'),(reverse q,'<')] -- from the alphabet q and its reverse

      = (s<$[1..l]) -- Repeat < or > the same number of times as the index of n ..
     ++ "*"         -- and append *

-- Encode the whole string
w (s:n) = s                                -- Yield the first char of the input
        : ( join . snd                     -- Concatinate the result of ..
          $ mapAccumL (\a b->(b,g a b))s n -- executing the g function on each letter of the input string ..
                                           -- except the first, passing the previous letter as the 'c' ..
                                           -- argument on each iteration
          )
BlackCap
la source
2

EXCEL VBA 130 octets

s="":p=Mid(s,1,1):For i=1 To Len(s)-1:b=Asc(Mid(s,i+1,1)):a=Asc(Mid(s,i,1)):p=p &String(abs(b-a),IIf(b>a,">","<"))&"*":Next:[a1]=p

Exécutez-le à partir de la fenêtre Excel VBA Immediate.

Explication:

Simple pour la boucle qui, avec la fonction String, répète le nombre ">" ou "<" n de fois où n est la différence ascii entre la chaîne de caractères i et i + 1.

Rohan
la source
2

Java 7, 232 octets

class C{static void main(String[]a)throws Exception{int i=System.in.read(),j,d,c;p(i);while((j=System.in.read())>10){d=(j-i+26)%26;c=d>13?-1:1;while(d%26>0){d-=c;p(61+c);}p(42);i=j;}}static void p(int k){System.out.print((char)k);}}

À peu près la solution triviale. Non golfé et commenté:

class C {
    static void main(String[] a) throws Exception {
        int i = System.in.read(), j, d, c; // i is the last character. j is the current character. d is the difference. c is the direction (-1 is left, 1 is right)
        p(i); // print the starting character first
        while ((j = System.in.read()) > 10) { // keep going until a newline is hit (or an EOF/EOL for -1)
            d = (j - i + 26) % 26; // get the difference (always positive) by wrapping around
            c = d > 13 ? -1 : 1; // get the direction by finding which way is shorter, going right when it's a tie
            while (d % 26 > 0) { // keep going until the current character is reached
                d -= c; // reduce d in the right direction
                p(61 + c); // < is 60 = 61 + (-1), > is 62 = 61 - (-1)
            }
            p(42); // print an asterisk
            i = j; // set the current character to the new reference point
        }
    }

    static void p(int k) {
        System.out.print((char) k);
    }
}
HyperNeutrino
la source
2

C, 170 octets

e(c){putchar(c);}i;m(a,b){i=b-a?a>b?b-a<14?b-a:-(a+26-b):a-b<14?-(a-b):b+26-a:0;while(i>0)e(62),i--;while(i<0)e(60),i++;}f(char*l){e(*l);while(l[1])m(*l,l[1]),e(42),l++;}

Live détaillée

e(c){ putchar(c); } // encode

g(a,b) // obtain required transition
{
    return (b-a) // calculate distance

         ? (a > b // distance is non-zero

             // if b comes after a
             ? (b-a < 14 // if forward is a shorter path
                 ? b-a // go forward
                 : -(a+26-b)) // otherwise go backward

             // if b comes before a
             : (a-b < 14 // if backward is a shorter path
                 ? -(a-b) // go backward
                 : b+26-a)) // otherwise go forward

         : 0; // if distance is 0
}

// transition
i;m(a,b)
{
    // obtain required transition
    i=g(a,b);

    // encode forward transition
    while(i>0)e('>'), i--;

    // encode backward transition
    while(i<0)e('<'),i++;
}

// incremental cipher function
f(char*l)
{
    e(*l); // encode first character

    while(*(l+1)) // while next character is not END-OF-STRING
        m(*l,*(l+1)), // do transition from current to next character
        e('*'), // encode
        l++; // next
}
Khaled.K
la source
Solution cool. Ce qui suit est probablement plus facile à comprendre, mais 1 octet de plus:#define x q<14?q:q+26 e(c){putchar(c);}i,q;m(a,b){q=b-a;i=q?(a>b?x:-x):0;while(i>0)e('>'),i--;while(i<0)e('<'),i++;}f(char*l){e(*l);while(*(l+1))m(*l,*(l+1)),e('*'),l++;}
Moreaki
1
@Moreaki Thx, mais c'est un code-golf, donc nous visons toujours à réduire le nombre d'octets, de toute façon j'ai ajouté des explications détaillées sur le fonctionnement de mon code.
Khaled.K
2

JavaScript (ES6), 140 128 129 111 113 octets

J'ai emprunté une voie différente vers les autres solutions JS mais cela n'a pas trop bien fonctionné - voici ce que j'ai jusqu'à présent:

f=

([x,...s])=>x+s.map(y=>`<><>`[r=(d=y[c=`charCodeAt`]()-x[c](x=y))/13+2|0].repeat([d+26,-d,d,26-d][r])+`*`).join``

i.addEventListener("input",()=>o.innerText=i.value&&f(i.value))
console.log(f("adbc"))
console.log(f("aza"))
console.log(f("abcdef"))
console.log(f("zyaf"))
console.log(f("zzzzzz"))
console.log(f("z"))
console.log(f("zm"))
console.log(f("zl"))
console.log(f("alphabet"))
console.log(f("banana"))
console.log(f("abcdefghijklmnopqrstuvwxyz"))
console.log(f("abcdefz"))
<input id=i>
<pre id=o>

  • Enregistré 12 octets grâce à une suggestion de Luke sur la déstructuration de la chaîne.
  • Ajout d'un octet corrigeant une lecture erronée du défi, ce qui, à mon avis, permettait un caractère d'impression final implicite.
  • Sauvegardé encore 18 octets grâce à une réécriture complète par Luke.
  • Ajout de 2 octets car il semble que les chiffres ne soient pas des caractères d'impression valides.

Original, 131 octets

Hirsute
la source
1
([x,...s])=>x+s.map(...)enregistre 12 octets. Notez que vous devez également ajouter un caractère d'impression à la fin. Je suggère d'utiliser un nombre, qui ne coûtera que 2 octets `1`+1au lieu de `*`.
Luke
Merci, Luke; J'avais oublié que je pouvais détruire une entrée de chaîne comme ça. J'ai dû mal interpréter le défi hier soir; J'aurais pu jurer que le dernier caractère imprimé était implicite. Malheureusement, le simple fait de le coller après joinaurait entraîné une sortie non valide pour les entrées à lettre unique. Cependant, le déplacement du caractère d'impression dans la mapméthode ne coûte qu'un octet.
Shaggy
1
([x,...s])=>x+s.map(y=>'<><>'[r=(d=y[c='charCodeAt']()-x[c](x=y))/13+2|0].repeat([d+26,-d,d,26-d][r])+0).join``pour 111 octets
Luke
Merci, encore une fois, @Luke. Avant de le modifier, préférez-vous publier ce qui précède comme votre propre réponse? Je pense qu'il diffère suffisamment du mien (presque un hybride de celui-ci et d'Arnauld) pour que cela soit OK.
Shaggy
Non, vous pouvez le modifier. J'ai essayé une reducesolution de golf , mais cela s'est avéré être de 115 octets.
Luke
2

C ++, 210 190 octets

Mon premier essai au golf!

#include<iostream>
int g(char*a){char k,j,d;std::cout<<*a;a++;for(;*a;a++){for(j=*(a-1),d=j-*a,k=d>0?d>13?62:60:d<-13?60:62;j!=*a;j+=k-61,j=j<97?122:j>122?97:j)std::cout<<k;std::cout<<'*';}}

k stocke lequel de <,> ou * à imprimer. Au début, il imprime simplement le premier élément du tableau, puis exécute une boucle pour un du premier au dernier élément du tableau. j stocke l'élément précédent puis en comparant si j plus proche de * a en <ou> définissez k sur <,> respectivement, puis imprimons k puis exécutez cette boucle jusqu'à ce que j devienne égal à p. Ensuite, après chaque fin de la deuxième boucle, imprimez *.

0x81915
la source
2
Bienvenue sur le site! Si je me souviens bien *p!=0peut être remplacé par *p. Je suis sûr que l'espace char *an'est pas nécessaire non plus. Vous devrez également #include <iostream>et using namespace std;(bien que je pense qu'il serait peut-être moins cher d'ajouter simplement std::) pour en faire une réponse complète.
Wheat Wizard
2
Bienvenue sur le site! Je pense que vous devez inclure std::ou using namespace std;vous aurez probablement aussi besoin #include <iostream>de votre nombre d'octets.
DJMcMayhem
+1, mais corrigez les deux choses susmentionnées, bienvenue chez PPCG;). Découvrez quelques-unes des langues du TIO Nexus ( tio.run/nexus ) lorsque vous en aurez l'occasion! Peut-être vous présenter à Dennis, il est un mec clé flottant ici.
Urne de poulpe magique
Merci à tous pour vos suggestions et pour avoir signalé les erreurs. Je mettrai à jour le code sous peu.
0x81915
1

05AB1E , 17 octets

¬sÇ¥v„<>y0›èyÄ×ðJ

Essayez-le en ligne!

Explication

Utilise >, <et <space>pour indiquer incrémenter , décrémenter , soumettre

¬                  # get the first letter of the input string
 sǥ               # push a list of delta's of the character codes in the input string
    v              # for each delta
     „<>           # push the string "<>"
        y0›        # check if the delta is positive
           è       # use this to index into the string
            yÄ×    # repeat it abs(delta) times
               ðJ  # join to string with a space
Emigna
la source
Et perdu celui-ci de 3 heures 😉.
Magic Octopus Urn
1

Haskell , 167 168 126 octets

f=fromEnum
r=replicate
a?b=mod(f a-f b-13)26-13
c#x=r(c?x)'<'++r(-c?x)'>'
s(c,s)x=(x,s++c#x++"*")
e(x:y)=x:snd(foldl s(x,[])y)

Nous utilisons maintenant la solution arithmétique de xnor. Appelez avec e strstr :: Stringest la chaîne à encoder.

Julian Wolf
la source
1

Haskell , 109 octets

a#b=mod(a-b-13)26-13
r=replicate
h(a:b:s)=r(a#b)'>'++r(-a#b)'<'++'*':h(b:s)
h e=""
f(a:r)=a:h(fromEnum<$>a:r)

Essayez-le en ligne! Utilise l'approche de xnor . Appelez avec f "somestring".

Laikoni
la source