증분 암호


19

이 작업은 다소 단순하며 세 가지 "연산자"문자를 사용합니다. 당신의 작업은, 사용하여 인코딩하려면 다음 작업을 수행, 문자의 간단한 순서를 주어 <, >, *. 대문자 또는 소문자를 사용하도록 선택할 수 있으며 둘 다 처리 할 필요는 없습니다.


암호 설명

암호는 간단합니다. 증가 및 감소 조작을 사용 *하여 "제출"기능 을 사용하여 문자 1에서 끝 문자로 이동 합니다. "증가"의 연산자는 " >감소"입니다 <.

단어를 사용하는 예 adbc:

  • 단어의 첫 글자로 시작하여 그 글자를 출력하십시오. a
  • 다음으로, (brainfuck ><같이)를 사용하여 현재 문자를 다음 문자로 "탐색"하십시오. 편지에 1을 a>올리는 것 입니다. 문자를 낮추기 때문에 결과가 나타납니다. 줄 바꿈은 항상 마지막 작업 수를 초래하는 방향을 선택해야합니다.aba<z
  • 올바른을 최소한 조합 출력 후 <>출력 a를 *우리가 다음 문자에 도달 한 것을 나타 내기 위해.

인코딩 단계 adbc는 다음과 같습니다.

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

인코딩 단계 aza는 다음과 같습니다.

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

더 많은 예 :

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

규칙

  • 우리는 디코딩하지 않고 인코딩 하고 있으므로 엉망으로 만들지 마십시오.
  • 메시지에 문자 [A-Z]또는 [a-z], 선택한 내용 이 포함되어 있다고 가정 할 수 있습니다 .
  • 문자 / 숫자 / 예약되지 않은 문자를 사용하여 *(EG $) 를 표시 할 수 있습니다 .
  • 끝이 있어야합니다 *. 반복시 암시 적이 지 않습니다.
  • 빈 문자열을 가정하지 않아도되지만 단일 문자가 가능합니다.
  • 다음 글자와 같은 거리에있는 경우 방향을 선택할 수 있습니다.
  • 이것은 , 가장 낮은 바이트 수의 승리입니다.

다른 사람들이 이런 식으로 배우는 데 도움이되는 답변을 설명하십시오.


분명히하기 위해 마지막 테스트 사례는 abcdefghijklmnopqrstuvwxyz자체 입력이 아닌가?
Nick Clifford

1
@NickClifford 예.
Magic Octopus Urn

나는 zl사용해야 한다고 생각 합니다 >.
xnor

4
예제를 확인해 주시겠습니까? alphabet내 의견에 a>>>>>>>>>>>*>>>>*<<<<<<<<*<<<<<<<*>*>>>*<<<<<<<<<<<*zl있어야합니다 z>>>>>>>>>>>>*및 대한 banana두 번째 솔루션이 존재해야한다b<*<<<<<<<<<<<<<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*>>>>>>>>>>>>>*
요 르그 Hülsermann을

@xnor 맞습니다 zm. 의 수동 오타였습니다 . @jorg 좋은 어획량은 모두 수동으로 수정했습니다.
Magic Octopus Urn

답변:


2

젤리 , 17 바이트

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

대신에 공백 문자 사용 *(공백 또는 줄 바꿈을 , 이상 한 바이트를 저장 ”*).

작동 대문자 전용 또는 소문자 만 입력.

온라인으로 사용해보십시오! 또는 테스트 스위트를 참조하십시오(이 공간은*읽기 편하도록사후 교체됩니다).

어떻게?

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 기계 코드, 70 68 67 바이트

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

작동 방식 :

            |   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

이. 이것은 시원하지 않습니다. 당신도 이걸 정말 빨리 했어요.
Magic Octopus Urn

감사. 그래도 사소한 해결책입니다. 8086
user5434231

10

파이썬 3 , 87 바이트

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

온라인으로 사용해보십시오!

소문자 또는 대문자로 작동합니다.

프로그램은 r입력 문자열의 문자를 반복 할 때 출력 문자열 을 빌드 합니다. 이전 문자를로 저장하고 p증분 작업을 계산 p하여 새 문자 로 가져옵니다 c.

문자 사이의 간격은 ord(c)-ord(p), 그리고 (ord(c)-ord(p)-13)%26-13그것이 간격 (26)을 모듈로한다 [-13..12]. 결과가 음수이면 스텝 다운이 짧고 양수이면 스텝 업이됩니다. 부호 로 >또는 문자열에 <따라 문자열로 변환해야합니다 . abs또는 조건을 사용 하는 대신 음수 일 s*n때 빈 문자열을 제공하는 Python의 문자열 곱셈 을 활용합니다 n. 표현식 '<'*-d+'>'*d에서 잘못 서명 된 부분은 기여하지 않습니다.

초기 상태는 입력을 첫 번째 문자로 나누고 나머지는 Python 3의 압축 풀기로 처리 r,*s=input()합니다. 초기 문자는 초기 "이전"문자뿐만 아니라 문자열 작성을 시작하는 데 사용됩니다.

이 압축 풀기를 수행하기 위해 Python 3으로 전환하도록 제안한 ovs에게 감사합니다.



3

자바 스크립트 (ES6) 118 109 107 바이트

입력 문자열은 대소 문자를 구분하지 않습니다.

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)

작동 원리

Python과 달리 JS 모듈로 연산자는 제수가 아니라 피제수와 같은 부호를 갖는 숫자를 반환합니다. 또한 JS repeat()메서드는 빈 문자열을 반환하지 않고 음수가 주어지면 오류를 발생시킵니다 ( *어쨌든 단순보다 훨씬 깁니다 ).

이것들은이 도전에 대해 다소 불리한 행동입니다. 따라서 우리는 수학 트릭에 의존하기보다는 정확한 사례를 더 잘 식별 할 수 있습니다. (그러한 트릭이 존재하지 않는다는 것을 의미하지는 않지만 찾지 못했습니다.)

아래는 4 가지 가능한 경우를 설명하는 표입니다 d. 현재 문자와 이전 문자 사이의 부호있는 거리는 다음과 같습니다.

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

테스트 사례


2

PHP, 127 바이트

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;

테스트 케이스

PHP, 137 바이트

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;

테스트 케이스


2

자바 스크립트 (ES6) 111 103 바이트

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

원래 n계산하는 동안 @Arnauld의 설정 트릭을 조정하기 전에 111 바이트가 걸리는 버전입니다. 대신 p사용 s하는 또 다른 트릭 이 n있지만 늦어 지므로 귀찮게하지 않을 것입니다.


2

하스켈 (lambdabot) 161 153 바이트

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

온라인으로 사용해보십시오!


설명:

-- 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 바이트

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

Excel VBA 즉시 실행 창에서 실행하십시오.

설명:

String 함수를 사용하여 ">"또는 "<"n을 n 번 반복하는 간단한 for 루프. 여기서 n은 i와 i + 1 문자열의 ASCII 차이입니다.


2

자바 7, 232 바이트

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

사소한 해결책입니다. Ungolfed 및 댓글 :

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 바이트

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

자세한 라이브

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
}

멋진 솔루션. 다음은 이해하기 쉽지만 1 바이트 더 깁니다.#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, 그러나 이것은 코드 골프이므로 항상 바이트 수를 줄이는 것을 목표로합니다. 어쨌든 내 코드 작동 방식에 대한 자세한 설명을 추가했습니다.
Khaled.K

2

자바 스크립트 (ES6) 140 128 129 111 113 바이트

다른 JS 솔루션으로 다른 길을 갔지만 제대로 작동하지 않았습니다. 여기까지 내가 가진 것이 있습니다.

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>

  • Luke 가 문자열을 파괴하는 것에 대한 제안으로 12 바이트를 절약했습니다 .
  • 챌린지의 오판을 수정하는 1 바이트를 추가하여 암시적인 최종 인쇄 문자를 허용한다고 생각했습니다.
  • Luke의 광범위한 재 작성 덕분에 18 바이트를 더 절약했습니다.
  • 숫자가 유효한 인쇄 문자가 아닌 것처럼 2 바이트를 추가했습니다.

원본, 131 바이트


1
([x,...s])=>x+s.map(...)12 바이트를 절약합니다. 끝에 인쇄 문자를 추가해야합니다. 숫자 `1`+1대신 2 바이트 만 사용하는 것이 좋습니다 `*`.
Luke

고마워, 루크; 그런 문자열 입력을 재구성 할 수 없다는 것을 잊었습니다. 어젯밤 도전을 잘못 읽었을 것입니다. 마지막 인쇄 문자 암시 . 불행히도, 단순히 그것을 join입력하면 단일 문자 입력에 대해 잘못된 출력이 발생합니다. 그러나 map메소드 내에서 인쇄 문자를 이동하는 데는 1 바이트 만 소요됩니다.
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``111 바이트
Luke

다시 한번 감사합니다, @Luke. 수정하기 전에 위의 답변을 본인의 답변으로 게시 하시겠습니까? 나는 그것이 나의 것 (거의 그것과 Arnauld의 하이브리드)과 충분히 다르다고 생각합니다.
Shaggy

아냐, 편집 할 수있어 reduce 솔루션을 115 바이트였습니다.
Luke

2

C ++, 210 190 바이트

골프에서 나의 첫번째 시도!

#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는 <,> 또는 * 중 어느 것을 인쇄 할 것인지 저장합니다. 먼저 배열의 첫 번째 요소를 인쇄 한 다음 배열의 첫 번째 요소부터 마지막 ​​요소까지 루프를 실행합니다. J 가까이 * (A)에 의한 경우를 비교하여 J 후 이전 및 저장 요소 <또는> 세트 K에 <,>는 각각 다음 J는 P와 동일하게 될 때까지 K 다음이 루프를 실행하여 출력한다. 그런 다음 두 번째 루프 인쇄가 끝날 때마다 *.


2
사이트에 오신 것을 환영합니다! 내가 올바르게 기억하면로 *p!=0바꿀 수 있습니다 *p. 나는 공간 char *a도 불필요하다고 확신합니다 . 당신은 또한에 필요 #include <iostream>하고 using namespace std;(내 생각하지만 그것은 단지 추가로 저렴 수 있습니다std:: 이 완전한 답하도록).
밀 마법사

2
사이트에 오신 것을 환영합니다! 난 당신이 포함 할 필요가 있다고 생각 std::하거나 using namespace std;당신은 아마도 필요합니다 #include <iostream>당신의 바이트 수에.
DJMcMayhem

+1, 그러나 앞서 언급 한 두 가지 사항을 수정하십시오. PPCG에 오신 것을 환영합니다. 기회가 생기면 TIO Nexus ( tio.run/nexus ) 주변의 일부 언어를 확인하십시오 ! 어쩌면 Dennis에게 자신을 소개 할 수도 있습니다. 그는 여기에 떠있는 주요 친구입니다.
Magic Octopus Urn

제안과 실수를 지적 해 주셔서 감사합니다. 코드를 곧 업데이트하겠습니다.
0x81915

1

05AB1E , 17 바이트

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

온라인으로 사용해보십시오!

설명

용도 >, <<space>표시하기 위해 증가 , 감소 , 제출

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

3 시간 😉하여이 하나를 잃었다.
매직 문어 Urn

1

하스켈 , 167 (168) 126 바이트

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)

이제 xnor의 산술 솔루션을 사용합니다. 인코딩 할 문자열 이 e str어디에 있는지 와 함께 호출하십시오 str :: String.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.