Cifra incrementale


19

Questa attività è piuttosto semplice e utilizza tre caratteri "operatore" distinti. Il vostro compito è, data una semplice sequenza di lettere, eseguire le seguenti operazioni per codificare utilizzando <, >, *. Puoi scegliere di utilizzare lettere maiuscole o minuscole, non è necessario gestirle entrambe.


Spiegazione del cifrario

Il codice è semplice, stai usando le operazioni di incremento e decremento per passare dalla lettera 1 alla lettera finale, *essendo la tua funzione "submit". L'operatore per "incremento" sarà >e "decremento" sarà <.

Un esempio usando la parola adbc:

  • Inizia con la prima lettera della parola, genera quella lettera. a
  • Quindi, utilizzare >e <(come brainfuck) per "navigare" dalla lettera corrente a quella successiva. a>comporterebbe un "aumento" adi 1 alla lettera b. a<comporterebbe zperché stai abbassando la lettera (si avvolge, devi sempre scegliere la direzione risultante nel MINIMO numero di operazioni).
  • Dopo aver emesso la corretta combinazione minimizzata di <e >output a *per indicare che abbiamo raggiunto la lettera successiva.

I passaggi per codificare adbcsarebbero:

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

Esempi

I passaggi per codificare azasarebbero:

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

Altri esempi:

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

Regole

  • Stiamo codificando non decodificando, quindi non rovinare tutto.
  • Puoi presumere che il messaggio conterrà lettere [A-Z]o [a-z], a tua scelta.
  • È possibile utilizzare qualsiasi carattere non lettera / numerico / riservato per indicare * (EG $).
  • Devi avere il finale * , non è implicito nelle ripetizioni.
  • Non puoi assumere stringhe vuote, ma è possibile un singolo carattere.
  • Se è equidistante in entrambi i modi dalla lettera successiva, puoi scegliere una direzione.
  • Questo è , vince il conteggio di byte più basso.

Spiega la tua risposta, aiuta gli altri a imparare in questo modo.


Giusto per essere chiari, l'ultimo caso di test rappresenta abcdefghijklmnopqrstuvwxyze non è il suo input?
Nick Clifford,

1
@NickClifford sì.
Magic Octopus Urn,

Penso che zldovrei usare >.
xnor

4
Potresti per favore controllare gli esempi? alphabetè secondo me a>>>>>>>>>>>*>>>>*<<<<<<<<*<<<<<<<*>*>>>*<<<<<<<<<<<*e zldovrebbe essere z>>>>>>>>>>>>*e per bananadovrebbe esistere una seconda soluzioneb<*<<<<<<<<<<<<<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*>>>>>>>>>>>>>*
Jörg Hülsermann

@xnor correct, era un refuso manuale da zm. @jorg buone catture, risolto tutti, è stato uno sforzo manuale.
Magic Octopus Urn,

Risposte:


2

Gelatina , 17 byte

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

Utilizza un carattere spazio al posto di *(uno spazio , o una nuova riga , salva un byte ”*).

Funziona con o maiuscolo solo o ingresso minuscolo sola.

Provalo online! o vedere una suite di test (in cui tali spazi sono post-sostituiti*per facilità di lettura).

Come?

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

11

8086 codice macchina, 70 68 67 byte

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

Come funziona:

            |   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

Questo. Questo va ben oltre. Lo hai fatto anche DAVVERO rapidamente, dang.
Magic Octopus Urn,

Grazie. È praticamente la soluzione banale però.
Sembra

10

Python 3 , 87 byte

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

Provalo online!

Funziona con lettere minuscole o maiuscole.

Il programma crea la stringa di output rmentre scorre i caratteri nella stringa di input. Memorizza il carattere precedente come pe calcola l'operazione di incremento per passare dal pnuovo carattere c.

L'intervallo tra i caratteri è ord(c)-ord(p)e lo (ord(c)-ord(p)-13)%26-13porta modulo 26 all'intervallo [-13..12]. Un risultato negativo significa che è più breve scendere e un risultato positivo significa intensificare. Questo deve essere convertito in una stringa di >o in <base al segno. Invece di usare abso un condizionale, sfruttiamo la moltiplicazione di stringhe di Python che s*ndà la stringa vuota quando nè negativa. Nell'espressione'<'*-d+'>'*d , la parte con firma errata non contribuisce.

Lo stato iniziale viene gestito dividendo l'input nel suo primo carattere e il resto con il disimballaggio di Python 3 r,*s=input(). Il carattere iniziale viene utilizzato per iniziare a creare la stringa, nonché il carattere "precedente" iniziale.

Grazie a ovs per aver suggerito di passare a Python 3 per fare questo disimballaggio.



3

JavaScript (ES6), 118 109 107 byte

La stringa di input non fa distinzione tra maiuscole e minuscole.

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)

Come funziona

A differenza di Python, l'operatore modulo JS restituisce un numero con lo stesso segno del dividendo anziché del divisore. Inoltre, il repeat()metodo JS genera un errore quando viene assegnato un numero negativo, anziché restituire una stringa vuota (ed è significativamente più lunga di una semplice *comunque).

Questi sono comportamenti piuttosto sfavorevoli per questa sfida. Quindi, dovremmo identificare meglio in quale caso esatto piuttosto che fare affidamento su trucchi matematici. (Il che non significa che tali trucchi non esistano, ma piuttosto che non sono riuscito a trovarli.)

Di seguito è riportata una tabella che descrive i 4 casi possibili, in cui dè indicata la distanza tra il carattere corrente e quello precedente:

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

Casi test


2

PHP, 127 byte

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;

Casi test

PHP, 137 byte

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;

Casi test


2

JavaScript (ES6), 111 103 byte

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

Versione originale che impiegava 111 byte prima di adattare il trucco di impostazione di @ Arnauld ndurante l'informatica p, penso che ci sia probabilmente un altro trucco da usare sinvece di nma si sta facendo tardi, quindi non mi preoccuperò .:


2

Haskell (lambdabot), 161 153 byte

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

Provalo online!


Spiegazione:

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

2

EXCEL VBA 130 byte

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

Eseguilo dalla finestra immediata di VBA di Excel.

Spiegazione:

Semplice per il ciclo che con la funzione String per ripetere ">" o "<" n numero di volte in cui n è la differenza ascii tra la stringa i e i + 1.


2

Java 7-, 232 byte

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

Praticamente la soluzione banale. Ungolf e commentato:

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

2

C, 170 byte

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 dettagliato

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
}

Soluzione interessante. Quanto segue è probabilmente più facile da capire, ma 1 byte più lungo:#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, ma questo è un codice-golf, quindi miriamo sempre a ridurre il conteggio dei byte, comunque ho aggiunto una spiegazione dettagliata su come funziona il mio codice.
Khaled.K,

2

JavaScript (ES6), 140 128 129 111 113 byte

Ho percorso una strada diversa rispetto alle altre soluzioni JS ma non ha funzionato troppo bene - ecco cosa ho finora:

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>

  • Salvato 12 byte grazie a un suggerimento di Luke sulla destrutturazione della stringa.
  • Aggiunto 1 byte per correggere una lettura errata della sfida, che pensavo consentisse un carattere di stampa finale implicito.
  • Salvati altri 18 byte grazie a un'ampia riscrittura di Luke.
  • Aggiunti 2 byte in quanto i numeri non sono caratteri di stampa validi.

Originale, 131 byte


1
([x,...s])=>x+s.map(...)salva 12 byte. Si noti che è necessario aggiungere un carattere di stampa anche alla fine. Suggerisco di usare un numero, che costerà solo 2 byte `1`+1anziché `*`.
Luca,

Grazie Luke; Avevo dimenticato di poter destrutturare un input di stringa del genere. Devo aver letto male la sfida ieri sera; Avrei potuto giurare che fosse implicito l'ultimo personaggio di stampa . Sfortunatamente, semplicemente affrontarlo dopo joinavrebbe comportato un output non valido per input a lettera singola. Tuttavia, spostare il carattere di stampa all'interno del mapmetodo costa solo 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``per 111 byte
Luca,

Grazie ancora, @Luke. Prima di modificarlo, preferiresti pubblicare quanto sopra come risposta personale? Sento che differisce sufficientemente dal mio (quasi un ibrido tra esso e quello di Arnauld) perché ciò sia OK.
Shaggy,

No, puoi modificarlo. Ho provato a golf una reducesoluzione, ma si è rivelato essere di 115 byte.
Luca,

2

C ++, 210 190 byte

Il mio primo tentativo di giocare a 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 memorizza quale di <,> o * stampare. All'inizio stampa semplicemente il primo elemento dell'array, quindi esegue un ciclo per un dal primo all'ultimo elemento dell'array. j memorizza l'elemento precedente e quindi confrontando se j più vicino a * a per <o> imposta k su <,> rispettivamente e quindi stampa k quindi esegui questo ciclo fino a quando j diventa uguale a p. Quindi dopo ogni fine della seconda stampa del ciclo *.


2
Benvenuti nel sito! Se ricordo bene *p!=0può essere sostituito con *p. Sono abbastanza sicuro che anche lo spazio non char *asia necessario. Dovrai anche #include <iostream>e using namespace std;(anche se penso che potrebbe essere più economico aggiungere semplicemente std::) per rendere questa una risposta completa.
Mago del grano

2
Benvenuti nel sito! Penso che devi includere std::o using namespace std;probabilmente avrai bisogno anche #include <iostream>del conteggio dei byte.
DJMcMayhem

+1, ma risolvi le due cose di cui sopra, benvenuto in PPCG;). Scopri alcune delle lingue intorno a TIO Nexus ( tio.run/nexus ) quando ne hai la possibilità! Forse presentati a Dennis, è un tipo chiave che fluttua qui intorno.
Magic Octopus Urn,

Grazie a tutti per suggerimenti e sottolineando gli errori. Aggiornerò il codice a breve.
0x81915

1

05AB1E , 17 byte

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

Provalo online!

Spiegazione

Usi >, <e <space>per indicare incremento , decremento , presentare

¬                  # 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

E l'ho perso per 3 ore 😉.
Magic Octopus Urn,

1

Haskell , 167 168 126 byte

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)

Ora usando la soluzione aritmetica di xnor. Chiama con e strdov'è str :: Stringla stringa da codificare.


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.