Cifrado incremental

19

Esta tarea es bastante simple y utiliza tres caracteres distintos de "operador". Su tarea es, dada una simple secuencia de letras, realice la siguiente tarea para codificarla utilizando <, >, *. Puede elegir usar letras mayúsculas o minúsculas, no tiene que manejar ambas.


Explicación de cifrado

El cifrado es simple, está utilizando operaciones de incremento y decremento para recorrer de la letra 1 a la letra final, *siendo su función de "envío". El operador para "incremento" será >y "decremento" será <.

Un ejemplo usando la palabra adbc:

  • Comience con la primera letra de la palabra, envíe esa letra. a
  • Luego, use >y <(como brainfuck) para "navegar" la letra actual a la siguiente. a>daría como resultado 'elevar' apor 1 al pie de la letra b. a<resultaría zporque está bajando la letra (se ajusta, siempre debe elegir la dirección que resulte en la MENOS cantidad de operaciones).
  • Después de generar la combinación minimalista correcta de <y >generar a *para indicar que hemos llegado a la siguiente letra.

Los pasos para codificar adbcserían:

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

Ejemplos

Los pasos para codificar azaserían:

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

Más ejemplos:

"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>*>*>*>*>*<<<<<<*"

Reglas

  • Estamos codificando, no decodificando, así que no lo estropees.
  • Puede suponer que el mensaje contendrá letras [A-Z]o [a-z], a su elección.
  • Puede usar cualquier carácter que no sea letra / numérico / reservado para denotar *(EG $).
  • Debe tener el final *, no está implícito en las repeticiones.
  • Puede suponer que no hay cadenas vacías, pero es posible un solo carácter.
  • Si es equidistante en ambos sentidos a la siguiente letra, puede elegir una dirección.
  • Este es el , el menor recuento de bytes gana.

Por favor explique su respuesta, ayuda a otros a aprender de esta manera.

Urna de pulpo mágico
fuente
Para ser claros, ¿el último caso de prueba representa abcdefghijklmnopqrstuvwxyzy no es su propia entrada?
Nick Clifford
1
@NickClifford sí.
Magic Octopus Urn
Creo que zldebería usar >.
xnor
44
¿Podrías consultar los ejemplos? alphabetestá en mi opinión a>>>>>>>>>>>*>>>>*<<<<<<<<*<<<<<<<*>*>>>*<<<<<<<<<<<*y zldebería ser z>>>>>>>>>>>>*y para bananasi existe una segunda soluciónb<*<<<<<<<<<<<<<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*>>>>>>>>>>>>>*
Jörg Hülsermann
@xnor correcto, fue un error tipográfico manual de zm. @jorg buenas capturas, las arregló todas, fue un esfuerzo manual.
Urna de pulpo mágico

Respuestas:

2

Jalea , 17 bytes

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

Utiliza un carácter de espacio en lugar de *(un espacio , o una nueva línea , guarda un byte ”*).

Funciona con cualquiera mayúsculas sólo o entrada en minúsculas solamente.

Pruébalo en línea! o vea un conjunto de pruebas (donde esos espacios se reemplazan posteriormente*para facilitar la lectura).

¿Cómo?

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
fuente
11

Código de máquina 8086, 70 68 67 bytes

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

Cómo funciona:

            |   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
usuario5434231
fuente
Esta. Esto es más que genial. Hiciste esto REALMENTE rápido también, maldita sea.
Urna mágica del pulpo
Gracias. Sin embargo, es prácticamente la solución trivial. Simplemente es bastante corto en 8086.
user5434231
10

Python 3 , 87 bytes

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

Pruébalo en línea!

Funciona con minúsculas o mayúsculas.

El programa construye la cadena de salida a rmedida que itera sobre los caracteres en la cadena de entrada. Almacena el carácter anterior como p, y calcula la operación de incremento para llegar pal nuevo carácter c.

El intervalo entre los caracteres es ord(c)-ord(p), y lo (ord(c)-ord(p)-13)%26-13lleva el módulo 26 al intervalo [-13..12]. Un resultado negativo significa que es más corto dar un paso atrás, y un resultado positivo significa dar un paso adelante. Esto debe convertirse en una cadena de >o en <función del signo. En lugar de usar abso un condicional, aprovechamos la multiplicación de cadenas de Python que s*nda la cadena vacía cuando nes negativa. En la expresión '<'*-d+'>'*d, la parte mal firmada no contribuye.

El estado inicial se maneja dividiendo la entrada en su primer carácter y el resto con el desempaquetado de Python 3 r,*s=input(). El carácter inicial se usa para comenzar a construir la cadena, así como el carácter "anterior" inicial.

Gracias a Ovs por sugerir cambiar a Python 3 para hacer este desempaquetado.

xnor
fuente
6

Python 3 , 110 93 bytes

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)

Pruébalo en línea!

ovs
fuente
Ooo ... Funciona tanto en mayúsculas como en minúsculas, agradable (pero creo que puede reducir los bytes asumiendo uno u otro).
Magic Octopus Urn
¿Explicación por favor?
Camarada SparklePony
3

JavaScript (ES6), 118 109 107 bytes

La cadena de entrada no distingue entre mayúsculas y minúsculas.

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)

Cómo funciona

A diferencia de Python, el operador de módulo JS devuelve un número que tiene el mismo signo que el dividendo en lugar del divisor. Además, el repeat()método JS arroja un error cuando se le da un número negativo, en lugar de devolver una cadena vacía (y de *todos modos es significativamente más larga que una simple ).

Estos son comportamientos bastante desfavorables para este desafío. Por lo tanto, sería mejor identificar en qué caso exacto estamos en lugar de depender de trucos matemáticos. (Lo que no significa que tales trucos no existan, sino que no pude encontrarlos).

A continuación hay una tabla que describe los 4 casos posibles, donde destá la distancia firmada entre el personaje actual y el anterior:

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

Casos de prueba

Arnauld
fuente
2

PHP, 127 bytes

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;

Casos de prueba

PHP, 137 bytes

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;

Casos de prueba

Jörg Hülsermann
fuente
2

JavaScript (ES6), 111 103 bytes

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

Originalmente, la versión que tomó 111 bytes antes de adaptar el truco de configuración de @ Arnauld nmientras computaba p, creo que probablemente haya otro truco usando en slugar de, npero se está haciendo tarde, así que no me molestaré .:

Neil
fuente
2

Haskell (lambdabot), 161 153 bytes

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])++"*"

Pruébalo en línea!


Explicación:

-- 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
          )
Alondra
fuente
2

EXCEL VBA 130 bytes

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

Ejecútelo desde la ventana de Excel VBA Inmediato.

Explicación:

Simple for loop que con la función String para repetir el ">" o "<" n número de veces donde n es la diferencia entre la cadena de caracteres i e i + 1.

Rohan
fuente
2

Java 7-, 232 bytes

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

Más o menos la solución trivial. Ungolfed y comentó:

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);
    }
}
Hiperneutrino
fuente
2

C, 170 bytes

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

Detallado en vivo

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
fuente
Solución genial El siguiente es probablemente más fácil de entender, pero ya 1 byte:#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, pero este es un código de golf, por lo que siempre buscamos reducir el conteo de bytes, de todos modos he agregado una explicación detallada sobre cómo funciona mi código.
Khaled.K
2

JavaScript (ES6), 140 128 129 111 113 bytes

Seguí una ruta diferente a las otras soluciones JS, pero no funcionó demasiado bien: esto es lo que tengo hasta ahora:

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>

  • Guardado 12 bytes gracias a una sugerencia de Luke sobre la desestructuración de la cadena.
  • Se agregó 1 byte para corregir una lectura errónea del desafío, que pensé que permitía un carácter de impresión final implícito.
  • Ahorró otros 18 bytes gracias a una extensa reescritura de Luke.
  • Se agregaron 2 bytes, ya que parece que los números no son caracteres de impresión válidos.

Original, 131 bytes

Lanudo
fuente
1
([x,...s])=>x+s.map(...)ahorra 12 bytes. Tenga en cuenta que también debe agregar un carácter de impresión al final. Sugiero usar un número, que solo costará 2 bytes en `1`+1lugar de `*`.
Lucas
Gracias Luke; Había olvidado que podía desestructurar una entrada de cadena como esa. Debo haber leído mal el desafío anoche; Podría haber jurado que decía que el último carácter impreso estaba implícito. Desafortunadamente, simplemente agregarlo después de joinhaber resultado en una salida no válida para entradas de una sola letra. Sin embargo, mover el carácter de impresión dentro del mapmétodo solo cuesta 1 byte.
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``para 111 bytes
Lucas
Gracias de nuevo, @Luke. Antes de editarlo, ¿preferiría publicar lo anterior como su propia respuesta? Siento que difiere lo suficiente del mío (casi un híbrido de él y el de Arnauld) para que eso esté bien.
Shaggy
No, puedes editarlo. Intenté jugar una reducesolución, pero resultó ser 115 bytes.
Lucas
2

C ++, 210 190 bytes

Mi primer intento en el 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 almacena cuál de <,> o * para imprimir. En primer lugar, simplemente imprime el primer elemento de la matriz y luego ejecuta un bucle desde el primero hasta el último elemento de la matriz. j almacena el elemento anterior y luego al comparar si j más cerca de * a mediante <o> establezca k en <,> respectivamente y luego imprima k y luego ejecute este ciclo hasta que j sea igual a p. Luego, después de cada final de la segunda impresión de bucle *.

0x81915
fuente
2
Bienvenido al sitio! Si recuerdo correctamente *p!=0puede ser reemplazado con *p. Estoy bastante seguro de que el espacio char *atambién es innecesario. También necesitarás #include <iostream>yusing namespace std; (aunque creo que podría ser más barato simplemente agregar std::) para que esta sea una respuesta completa.
Wheat Wizard
2
Bienvenido al sitio! Creo que debe incluir std::o using namespace std;probablemente también necesitará #include <iostream>en su recuento de bytes.
DJMcMayhem
+1, pero arregle las dos cosas antes mencionadas, bienvenido a PPCG;). ¡Vea algunos de los idiomas alrededor del TIO Nexus ( tio.run/nexus ) cuando tenga la oportunidad! Tal vez preséntese a Dennis, es un tipo clave que flota por aquí.
Urna de pulpo mágico
Gracias a todos por las sugerencias y señalar los errores. Actualizaré el código en breve.
0x81915
1

05AB1E , 17 bytes

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

Pruébalo en línea!

Explicación

Usos >, <y <space>para denotar incremento , decremento , enviar

¬                  # 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
fuente
Y perdí este por 3 horas 😉.
Urna de pulpo mágico
1

Haskell , 167 168 126 bytes

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)

Ahora usando la solución aritmética de xnor. Llame con e strdonde str :: Stringestá la cadena a codificar.

Julian Wolf
fuente