Szyfr przyrostowy


19

To zadanie jest dość proste i wykorzystuje trzy różne znaki „operatora”. Twoim zadaniem jest, biorąc pod uwagę prostą sekwencję liter, należy wykonać następujące czynności, aby zakodować za pomocą <, >, *. Możesz wybrać użycie wielkich lub małych liter, nie musisz obsługiwać obu.


Wyjaśnienie szyfru

Szyfr jest prosty, używasz operacji inkrementacji i dekrementacji, aby przechodzić od litery 1 do litery końcowej, *będąc funkcją „wysyłania”. Operatorem „inkrementacji” będzie >i „decrement” będzie <.

Przykład z użyciem słowa adbc:

  • Zacznij od pierwszej litery słowa, wypisz tę literę. a
  • Następnie użyj >i <(jak pieprzenie mózgu), aby „nawigować” bieżącą literę do następnej. a>spowodowałoby „podniesienie” ao 1 do litery b. a<spowodowałoby zto, że obniżasz literę (jest ona zawijana, zawsze musisz wybrać kierunek, w wyniku czego NAJMNIEJ liczba operacji).
  • Po wypisaniu poprawnej zminimalizowanej kombinacji <i wypisanie >a *oznacza, że ​​osiągnęliśmy następną literę.

Kroki do zakodowania adbcto:

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

Przykłady

Kroki do zakodowania azato:

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

Więcej przykładów:

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

Zasady

  • Jesteśmy kodowania nie dekodowania, więc nie bałagan że up.
  • Możesz założyć, że wiadomość będzie zawierać litery [A-Z]lub [a-z]twój wybór.
  • Możesz użyć dowolnego nieliterowego / numerycznego / zarezerwowanego znaku do oznaczenia *(EG $).
  • Musisz mieć zakończenie *, nie ma to miejsca na powtórzenia.
  • Możesz założyć, że nie ma pustych łańcuchów, ale możliwy jest pojedynczy znak.
  • Jeśli jest w jednakowej odległości do następnej litery, możesz wybrać kierunek.
  • To jest , wygrana o najniższej liczbie bajtów.

Proszę wyjaśnić swoją odpowiedź, pomaga to innym w nauce w ten sposób.


Żeby było jasne, ostatni przypadek testowy reprezentuje abcdefghijklmnopqrstuvwxyzi nie jest własnym wkładem?
Nick Clifford

1
@NickClifford tak.
Magic Octopus Urn

Myślę, że zlpowinienem użyć >.
xnor

4
Czy możesz sprawdzić przykłady? alphabetjest moim zdaniem a>>>>>>>>>>>*>>>>*<<<<<<<<*<<<<<<<*>*>>>*<<<<<<<<<<<*i zlpowinien być z>>>>>>>>>>>>*i bananapowinien istnieć drugie rozwiązanieb<*<<<<<<<<<<<<<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*>>>>>>>>>>>>>*
Jörg Hülsermann

@ xnor poprawne, to literówka ręczna z zm. @ jorg dobre połowy, naprawione wszystkie, były wysiłkiem ręcznym.
Magic Octopus Urn

Odpowiedzi:


2

Galaretka , 17 bajtów

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

Używa spacji zamiast *(spacja lub nowa linia , zapisuje jeden bajt ”*).

Działa z każdym wielkie wyłącznie lub małymi literami tylko.

Wypróbuj online! lub zobacz zestaw testowy (gdzie te miejsca są zastępowane przez*dla ułatwienia czytania).

W jaki sposób?

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

Kod maszynowy 8086, 70 68 67 bajtów

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

Jak to działa:

            |   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

To. To jest poza spokojem. Zrobiłeś to NAPRAWDĘ szybko, cholera.
Magic Octopus Urn

Dzięki. Jest to jednak dość trywialne rozwiązanie. Po prostu bywa dość krótki w 8086.
użytkownik5434231

10

Python 3 , 87 bajtów

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

Wypróbuj online!

Działa z małymi lub dużymi literami.

Program buduje ciąg wyjściowy rpodczas iteracji znaków w ciągu wejściowym. Przechowuje poprzedni znak jako pi oblicza operację zwiększania, aby przejść od pnowej postaci c.

Odstęp między znakami wynosi ord(c)-ord(p)i wynosi (ord(c)-ord(p)-13)%26-13modulo 26 do przedziału [-13..12]. Wynik ujemny oznacza, że ​​krócej jest go obniżyć, a wynik dodatni oznacza, że ​​trzeba go zwiększyć. To musi być przekonwertowane na ciąg >lub w <zależności od znaku. Zamiast używać abswarunkowego lub warunkowego, korzystamy z mnożenia ciągów Pythona, s*ndając pusty ciąg, gdy njest ujemny. W wyrażeniu '<'*-d+'>'*dźle podpisana część nie ma znaczenia.

Stan początkowy jest obsługiwany przez podzielenie danych wejściowych na pierwszy znak, a resztę za pomocą rozpakowywania Pythona 3 r,*s=input(). Początkowy znak służy do rozpoczęcia budowy łańcucha, a także początkowego „poprzedniego” znaku.

Podziękowania dla ovs za zasugerowanie przejścia na Python 3 w celu rozpakowania.



3

JavaScript (ES6), 118 109 107 bajtów

Łańcuch wejściowy nie rozróżnia wielkości liter.

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)

Jak to działa

W przeciwieństwie do Pythona, operator modulo JS zwraca liczbę mającą ten sam znak co dywidenda, a nie dzielnik. Ponadto repeat()metoda JS generuje błąd, gdy otrzymuje liczbę ujemną, zamiast zwracania pustego ciągu (i tak jest znacznie dłuższy niż zwykły *).

Są to raczej niekorzystne zachowania dla tego wyzwania. Lepiej więc zidentyfikujmy konkretny przypadek, zamiast polegać na matematycznych sztuczkach. (Co nie znaczy, że takie sztuczki nie istnieją, ale raczej, że ich nie znalazłem.)

Poniżej znajduje się tabela opisująca 4 możliwe przypadki, gdzie djest podpisana odległość między obecną postacią a poprzednią:

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

Przypadki testowe


2

PHP, 127 bajtów

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;

Przypadki testowe

PHP, 137 bajtów

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;

Przypadki testowe


2

JavaScript (ES6), 111 103 bajtów

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

Oryginalna wersja, która zajęła 111 bajtów, zanim dostosowałem sztuczkę @ Arnaulda do ustawiania npodczas obliczeń p, myślę, że prawdopodobnie jest to inna sztuczka szamiast, nale robi się późno, więc nie będę się tym przejmować:


2

Haskell (lambdabot), 161 153 bajtów

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

Wypróbuj online!


Wyjaśnienie:

-- 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 bajtów

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

Uruchom go z okna Excel VBA Natychmiastowe.

Wyjaśnienie:

Prosta pętla, która z funkcją String może powtarzać „>” lub „<” n liczbę razy, gdzie n jest różnicą ascii między ciągiem znaków i i + 1.


2

Java 7-, 232 bajty

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

Prawie trywialne rozwiązanie. Nie golfił i skomentował:

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 bajtów

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

Szczegółowe na żywo

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
}

Fajne rozwiązanie. Następujące jest prawdopodobnie łatwiejsze do zrozumienia, ale o 1 bajt dłużej:#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, ale jest to gra w golfa kodu, więc zawsze staramy się zmniejszyć liczbę bajtów, w każdym razie dodałem szczegółowe wyjaśnienie dotyczące działania mojego kodu.
Khaled.K

2

JavaScript (ES6), 140 128 129 111 113 113 bajtów

Poszedłem inną drogą do innych rozwiązań JS, ale nie wyszło to zbyt dobrze - oto co mam do tej pory:

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>

  • Zaoszczędzono 12 bajtów dzięki sugestii Łukasza dotyczącej zniszczenia łańcucha.
  • Dodano 1 bajt naprawiający błędne odczytanie wyzwania, co, jak sądzę, pozwoliło na domniemany druk końcowy.
  • Oszczędność kolejnych 18 bajtów dzięki obszernej przeróbce napisanej przez Łukasza.
  • Dodano 2 bajty, ponieważ wydaje się, że liczby nie są prawidłowymi drukowanymi znakami.

Oryginał, 131 bajtów


1
([x,...s])=>x+s.map(...)oszczędza 12 bajtów. Pamiętaj, że powinieneś również dołączyć znak na końcu. Sugeruję użycie liczby, która `1`+1zamiast kosztuje tylko 2 bajty `*`.
Łukasz

Dzięki, Luke; Zapomniałem, że mogę zniszczyć taki ciąg znaków. Musiałem wczoraj źle odczytać wyzwanie; Mógłbym przysiąc, że ostatni znak do druku był niejawny. Niestety, po prostu sczepienie go po tym joinskutkowałoby niepoprawnym wyjściem dla pojedynczych liter. Jednak przeniesienie znaku do wydruku w ramach tej mapmetody kosztuje tylko 1 bajt.
Kudłaty

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``za 111 bajtów
Łukasz

Jeszcze raz dziękuję @Luke. Czy przed opublikowaniem go wolisz opublikować powyższą odpowiedź jako własną odpowiedź? Wydaje mi się, że wystarczająco różni się od mojej (prawie hybrydy tej i Arnaulda), aby było w porządku.
Kudłaty

Nie, możesz to edytować. Próbowałem grać w golfa reduce, ale okazało się, że to 115 bajtów.
Łukasz

2

C ++, 210 190 bajtów

Moja pierwsza próba gry w golfa!

#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 przechowuje, które z <,> lub * do wydrukowania. Najpierw po prostu drukuje pierwszy element tablicy, a następnie uruchamia pętlę od pierwszego do ostatniego elementu tablicy. j przechowuje poprzedni element, a następnie porównując, czy j bliżej * a przez <lub> ustaw odpowiednio k na <,>, a następnie wypisz k, a następnie uruchom tę pętlę, aż j stanie się równe p. Następnie po każdym zakończeniu drugiego wydruku w pętli *.


2
Witamy na stronie! Jeśli dobrze pamiętam, *p!=0można go zastąpić *p. Jestem pewien, że przestrzeń w tym miejscu char *ajest również niepotrzebna. Potrzebny będzie również do #include <iostream>i using namespace std;(chociaż myślę, że to może być tańsze tylko dodać std::), aby ta pełna odpowiedź.
Kreator pszenicy,

2
Witamy na stronie! Myślę, że musisz dołączyć std::lub using namespace std;Prawdopodobnie będziesz również potrzebować #include <iostream>w swojej liczbie bajtów.
DJMcMayhem

+1, ale napraw dwie wyżej wymienione rzeczy, witamy w PPCG;). Zapoznaj się z niektórymi językami wokół TIO Nexus ( tio.run/nexus ), kiedy będziesz mieć szansę! Może przedstaw się Dennisowi, on jest kluczowym facetem unoszącym się tutaj.
Magic Octopus Urn

Dziękujemy wszystkim za sugestie i wskazanie błędów. Wkrótce zaktualizuję kod.
0x81915

1

05AB1E , 17 bajtów

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

Wypróbuj online!

Wyjaśnienie

Zastosowania >, <oraz <space>do określenia przyrostu , ubytku , przedkłada

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

I straciłem to o 3 godziny 😉.
Magic Octopus Urn

1

Haskell , 167 168 126 bajtów

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)

Teraz za pomocą rozwiązania arytmetycznego xnor. Wywołaj z e strgdzie str :: Stringjest ciąg znaków do zakodowania.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.