増分暗号


19

このタスクはかなり単純で、3つの異なる「演算子」文字を使用します。あなたの仕事は、使用してそれをエンコードするには、次のタスクを実行し、文字のシンプルなシーケンスを与えられています<>*。大文字または小文字を使用することもできますが、両方を処理する必要はありません。


暗号の説明

暗号は簡単です。インクリメントおよびデクリメント操作を使用し*て、「送信」機能として、文字1から末尾の文字まで移動します。「増分」の演算子はになり>、「減分」はになります<

単語を使用した例adbc

  • 単語の最初の文字から始めて、その文字を出力します。 a
  • 次に、>and <(brainfuckなど)を使用して、現在の文字を次の文字に「ナビゲート」します。a>その結果a、手紙が1だけ「上がる」ことになりbます。あなたは手紙を下げるので、a<結果になりzます(折り返します、あなたは常に操作の数が最も少なくなる方向を選択する必要があります)。
  • 正しいminimalizedの組み合わせ出力した後<>出力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はそれ自身の入力ではなく、それ自体の入力ですか?
ニッククリフォード

1
@NickCliffordはい。
魔法のタコUr

zl使用すべきだと思います>
XNOR

4
例を確認していただけますか?alphabet私の意見であるa>>>>>>>>>>>*>>>>*<<<<<<<<*<<<<<<<*>*>>>*<<<<<<<<<<<*zlあるべきz>>>>>>>>>>>>*とするためには、banana第2の解決策は存在している必要がありますb<*<<<<<<<<<<<<<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*>>>>>>>>>>>>>*
イェルクHülsermann

@xnor正しい、からの手動入力ミスでしたzm。@jorgの良いキャッチは、それらすべてを修正し、手作業でした。
魔法のタコUr

回答:


2

ゼリー、17 バイト

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

の代わりにスペース文字を使用します*(スペース、または改行、、は1バイト節約します”*)。

作品のいずれか大文字のみまたは小文字のみの入力。

オンラインでお試しください!またはテストスイート*読みやすくするためにこれらのスペースが置き換えられた場所)を参照してください。

どうやって?

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

この。これはクールを超えています。あなたもこれを本当に迅速にやった。
魔法のタコUr

ありがとう。しかし、それはほとんど些細な解決策です。8086ではたまたま非常に短いです。
user54342

10

Python 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または条件を使用するのではなく、Pythonの文字列乗算s*nを利用して、n負の場合に空の文字列を提供します。式'<'*-d+'>'*dでは、間違って署名された部分は寄与しません。

初期状態は、入力を最初の文字に分割し、残りをPython 3のunpackingで分割することで処理されr,*s=input()ます。最初の文字は、文字列と最初の「前の」文字の構築を開始するために使用されます。

この展開を行うためにPython 3に切り替えることを提案してくれたovsに感謝します。



3

JavaScriptの(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

JavaScript(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

Haskell(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イミディエイトウィンドウから実行します。

説明:

文字列関数を使用して「>」または「<」をn回繰り返す単純なforループ。ここで、nはiとi + 1の文字列のASCII差です。


2

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

かなり簡単なソリューションです。非ゴルフとコメント:

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

JavaScriptの(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バイトしかかかりません`*`
ルーク

ありがとう、ルーク。そのような文字列入力を非構造化できることを忘れていました。私は昨夜の挑戦を読み違えたに違いない。私は、最後の活字暗黙的であると言ったと断言できました。残念なことに、join1文字入力の場合、無効になった後に単に追加するだけです。ただし、mapメソッド内で印刷文字を移動するには、1バイトしかかかりません。
シャギー

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に感謝します。編集する前に、上記を自分の回答として投稿してください。私はそれが私のもの(それとアーナウルドのほぼハイブリッド)とは十分に異なると感じています。
シャギー

いや、あなたはそれを編集することができます。私はreduce解決策をゴルフしようとしましたが、それは115バイトであることが判明しました。
ルーク

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は前の要素を保存し、<または>によってjが* aに近いかどうかを比較することにより、それぞれkを<、>に設定し、kを出力して、jがpに等しくなるまでこのループを実行します。その後、2番目のループprint *が終了するたびに。


2
サイトへようこそ!正しく思い出せばに*p!=0置き換えることができます*p。スペースchar *aも不要であると確信しています。また、これを完全な答えにするために、(追加する方が安いかもしれませんが)とする必要が#include <iostream>あります。using namespace std;std::
小麦ウィザード

2
サイトへようこそ!含める必要があると思います。std::または、バイトカウントにusing namespace std;もおそらく必要#include <iostream>です。
DJMcMayhem

+1、ただし前述の2つのことを修正してください。PPCGへようこそ;)。機会があれば、TIO Nexus(tio.run/nexus)周辺のいくつかの言語をチェックしてください!デニスを紹介してください。彼はこの辺りに浮かんでいる重要な人物です。
魔法のタコUr

提案と間違いの指摘に感謝します。コードを間もなく更新します。
0x81915

1

05AB1E、17バイト

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

オンラインでお試しください!

説明

およびを使用して>incrementdecrementsubmitを示します<<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時間で失いました😉。
魔法のタコUr

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 strwhereで呼び出しstr :: Stringます。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.