VIC暗号エンコーダーを書く


18

VIC暗号はこれまでに考案された最も複雑な鉛筆と紙暗号の一つです。ソビエトのスパイReinoHäyhänen(コード名「VICTOR」)が1950年代に使用した主な原理は、難読化によるセキュリティです。多くの難読化の。

あなたの仕事は、メッセージを受け取り、VIC暗号を使用してエンコードするプログラムまたは関数を作成することです。私はまたしているここVIC暗号デコーダチャレンジを掲載します。次の指示のいずれかが不明な場合は、コメントでそれらについて尋ねることをtoしないでください。指示はこのサイトから適応されます

VIC暗号のエンコード

準備

5つの入力が必要です。

  • 平文メッセージ
  • あなたの言語で最も一般的な文字を含む短いキーワードまたはフレーズ
  • 引用や歌の行などのキーフレーズ(20文字以上)
  • 日付(または6桁以上の別の数値)
  • パーソナルエージェント番号

実際には、これらの最後の4つは、送信者と受信者のエージェント番号がエンコードで使用されるかどうかを含め、送信者と受信者によって事前に合意される必要があります。

私のメッセージ例は次のとおりです。 We are discovered. Take what you can. Burn everything else. Move to Safehouse Foxtrot 3.

英語でエンコードします(ただし、好みの言語とアルファベットを使用できます)A, E, I, N, O, R, S, T。英語のアルファベットで最も一般的な文字はです。キーワードを使用しますSENATORI

私のキーフレーズは、リチャード・ファインマンの引用です:「最初の原則は、あなたは自分をだましてはいけないということです—そして、あなたはだますのが最も簡単な人です。」

日付として、2016年7月31日(形式3172016)を使用します。これは、この説明を書いた日です。

私が自分用に選んだ個人番号は9です。

手順の概要

  1. 次の手順で使用する中間キーを導出します。
  2. 跨ぐチェッカーボードを作成して適用します。
  3. 最初の転置テーブルを構築して適用します。
  4. 2番目の(中断された)転置テーブルを作成して適用します。
  5. メッセージインジケータグループを挿入して、メッセージを完成させます。

サブメカニズム

問題の本質を説明する前に、2つの事柄を説明します。チェーンの追加と順次化のプロセスです。

ラグ付きフィボナッチジェネレーターとも呼ばれるチェーン加算は、開始桁シーケンスを取得し、最初の2桁を運ぶことなく加算し(それらを一緒に加算しmod 10)、結果を末尾に追加します。例えば:

79081
7 + 9 = 6

790816
9 + 0 = 9

7908169
0 + 8 = 8

79081698
8 + 1 = 9

790816989
1 + 6 = 7

7908169897
... and so on

順序付けとは、基本的に文字または数字のシーケンスを取得し、それらをアルファベット順/数字順にラベル付けすることです。重複は左から右にラベル付けされます。例えば:

E X A M P L E
    0           # A
1   0       2   # Es
1   0     3 2   # L
1   0 4   3 2   # M
1   0 4 5 3 2   # P
1 6 0 4 5 3 2   # X

3  3  0  5  8  4  2  0  4  7  5  4  8  1
      0              1                     # 0s
      0              1                 2   # 1
      0           3  1                 2   # 2
4  5  0           3  1                 2   # 3s
4  5  0        6  3  1  7        8     2   # 4s
4  5  0  9     6  3  1  7    10  8     2   # 5s
4  5  0  9     6  3  1  7 11 10  8     2   # 7
4  5  0  9 12  6  3  1  7 11 10  8 13  2   # 8s

ここではゼロインデックスを使用しますが、好きなようにインデックスを作成します。

1.中間キー

キーフレーズの最初の20文字を10個の2つのグループに分割し、それぞれ個別にシーケンシャル化S1S2ます。

    THEFIRSTPR
S1: 8201357946

    INCIPLEIST
S2: 2603751489

ランダムな5桁のメッセージ識別子を選択しますM(これは、必要に応じて入力の1つにすることができます)。

M = 47921

からmod 10のキー日付の最初の5桁を、借用せずに減算(減算)します。3172016M

M      47921
date - 31720
     = 16201

10桁になるまで結果をチェーンで追加します。

1620178218

これらの数字をS1に追加して、またはを運ばずmod 10に取得しGます

     1620178218
S1 + 8201357946
G  = 9821425154

上記S2で、シーケンス0123456789を記述します。シーケンス0123456789の各桁を見つけGて、の直下の桁に置き換えS2ます。結果はTです。

   0123456789
S2 2603751489

G  9821425154
T  9806705657

チェーンの追加を使用してT、60桁に拡張します。

9806705657

becomes

980670565778637511245490262369939288595822106344304316978734

これらの最後の50桁は、それぞれ10桁の5行でUブロックを形成します。

T  9806705657
U  7863751124
   5490262369
   9392885958
   2210634430
   4316978734

最後の二つの非同等の数字Uブロックを個別に2つの転位の幅を与えるために、エージェントの個人番号に追加、されているpq

9 + 3 = 12(p、最初の転置幅)9 + 4 = 13(q、2番目の転置幅)

SequentializeはTの列をオフにコピーするには、この配列を使用してU、数字の新しい行に、上から下へ、ブロックV

T     9806705657
seqT  9804612537

U     7863751124
      5490262369
      9392885958
      2210634430
      4316978734

V     69911 56837 12548 26533 30206 13947 72869 49804 84323 75924

最初Sequentialize p最初の転置のためのキーを取得するために数字をK1、および以下のq第二のためのキーの数字をK2

First 12  6  9  9  1  1  5  6  8  3  7  1  2
K1        6 10 11  0  1  5  7  9  4  8  2  3

Next 13   5  4  8  2  6  5  3  3  3  0  2  0  6
K2        8  7 12  2 10  9  4  5  6  0  3  1 11

最後に、Uブロックの最後の行を順番に並べCて、またがるチェッカーボードの列ヘッダーを取得します。

U5  4316978734
C   3105968724

2.チェッカーボードにまたがる

最初に、チェッカーボードの例を示し、それをそのように作成する際の原則を説明します。

  3 1 0 5 9 6 8 7 2 4
  S E N A T O R I
2 B D G J L P U W Y .
4 C F H K M Q V X Z #

文字の最初の行は短いキーワードSENATORIです。キーワードには重複のない任意の文字列を使用できますが、チェッカーボードの一番上の行を定義するため、賢明に選択してください。キーワードの上はCで、他の行は選択した任意の順序での残りのアルファベットです。私の場合、チェッカーボードにラテンアルファベットの残り、句読点.、および数字を区別するためのマークを入れました#。基本的に、チェッカーボードは派手な代替暗号です。たとえば、「E」はに置き換えられ1、「W」はに置き換えられ27ます。

このチェッカーボードでプレーンテキストメッセージをエンコードしたら、最初に、ランダムな位置で分割し、すべて大文字にすることで、メッセージの始まりを目立たなくする必要があります。他の最初の始まりを示すために、2つの完全なストップを使用します..

We are discovered. Take what you can. Burn everything else. Move to Safehouse Foxtrot 3.

になる

HING ELSE. MOVE TO SAFEHOUSE FOXTROT#3#.. WE ARE
DISCOVERED. TAKE WHAT YOU CAN. BURN EVERYT

チェッカーボードでエンコードして、以下を提供します。

407020 1293124 496481 96 354114062831 416479869443442424 271 581 
2173436481812124 95451 274059 22628 435024 232880 14818229

メッセージの長さが5で割り切れない場合、メッセージを埋めるためにいくつかのヌル文字を追加します。メッセージの長さは109桁なので、「4」という1つのヌルを追加します。

40702 01293 12449 64819 63541 14062 83141 64798 69443 44242 42715
81217 34364 81812 12495 45127 40592 26284 35024 23288 01481 82294

注:私のメッセージ例には数字が含まれていないので、ここで言うように#3#、ここでエンコードされ44344ます。

3.最初の転置

書き替えて転置表を作成する K1(中間キーセクションから)、続いてキーの下に同じ長さの行で前のステップからのエンコードされたメッセージをます。

K1   6 10 11  0  1  5  7  9  4  8  2  3

     4  0  7  0  2  0  1  2  9  3  1  2
     4  4  9  6  4  8  1  9  6  3  5  4
     1  1  4  0  6  2  8  3  1  4  1  6
     4  7  9  8  6  9  4  4  3  4  4  2
     4  2  4  2  7  1  5  8  1  2  1  7
     3  4  3  6  4  8  1  8  1  2  1  2
     4  9  5  4  5  1  2  7  4  0  5  9
     2  2  6  2  8  4  3  5  0  2  4  2
     3  2  8  8  0  1  4  8  1  8  2  2
     9  4

番号順に列を取得すると、次のようになります。

060826428  246674580  151411542  246272922  961311401  082918141
4414434239 118451234  334422028  293488758  0417249224 794943568

4. 2番目の転置

最初の転置は比較的簡単でした。ただし、これは混乱した転位です。中断パターンは、テーブルの幅とキーによって決まります。この例では、110桁と13列で構成されています。つまり、8つの行と6つの残り物があります。最初の行の入力を開始しますが、列0で停止し、次のように続行します。

K2   8  7 12  2 10  9  4  5  6  0  3  1 11

     0  6  0  8  2  6  4  2  8              stop at 0
     2  4  6  6  7  4  5  8  0  1           continue in a triangle pattern
     5  1  4  1  1  5  4  2  2  4  6
     2  7  2  9  2  2  9  6  1  3  1  1
     4  0  1  0  8  2  9  1  8  1  4  1  4  until the end
     4  1  4  4  3  4  2  3  9  1  1        restart and stop at 1
     8  4  5  1  2  3  4  3  3  4  4  2
     2  0  2  8  2  9  3  4  8  8  7  5  8
     0  4  1                                restart and stop at 2

次に、最後のいくつかのスペースに残りの数字を入力します。

K2   8  7 12  2 10  9  4  5  6  0  3  1 11

     0  6  0  8  2  6  4  2  8  7  2  4  9
     2  4  6  6  7  4  5  8  0  1  2  2  4
     5  1  4  1  1  5  4  2  2  4  6  7  9
     2  7  2  9  2  2  9  6  1  3  1  1  4
     4  0  1  0  8  2  9  1  8  1  4  1  4
     4  1  4  4  3  4  2  3  9  1  1  9  4
     8  4  5  1  2  3  4  3  3  4  4  2  3
     2  0  2  8  2  9  3  4  8  8  7  5  8
     0  4  1  5  6  8

ここで、最初の転置の場合とまったく同じ方法で列を読み取ります。

71431148  42711925  861904185 22614147  45499243  28261334  80218938
641701404 025244820 645224398 271283226 94944438  064214521

そして、すべてを5桁のグループに分割します。

71431 14842 71192 58619 04185 22614 14745 49924 32826 13348 02189
38641 70140 40252 44820 64522 43982 71283 22694 94443 80642 14521

5.メッセージを完成させる

最後のステップは47921、メッセージ自体にランダムなメッセージ識別子を挿入することです。基準日の最後の数字は、6グループが最後からどれだけ離れているかを示しています。

71431 14842 71192 58619 04185 22614 14745 49924 32826 13348 02189 38641
70140 40252 44820 64522 43982 47921 71283 22694 94443 80642 14521

このチャレンジの注意事項

  • メッセージ、文字キーワード、キーフレーズ、日付、個人番号の5つ以上の入力が与えられます。2つの追加の入力を含めることができます:ランダムメッセージ識別子と、メッセージを埋め込むために必要なnull、または関数が独自にいくつかの乱数を生成します。
  • すべての入力が有効で、正しい桁数と文字数(5桁のメッセージ識別子、キーフレーズ用に少なくとも20桁など)が有効であると想定できます。ご使用のバージョンで許可されているものを除き、文字列(メッセージとキーワード)ですべての句読点とスペースが既に削除されており、番号は既にシャープ記号で区切られていると想定できます。
  • 最初のキーワードには重複した文字を含めないでください。コードでは、重複した文字を使用しないと想定できます。
  • エンコードに使用する言語は、その言語が既存であり、アルファベットが既存である限り、重要ではなく、回答で使用する言語を指定します。
  • 跨ぐチェッカーボードにどのアルファベットを使用しても、チェッカーボードを埋めるためにシンボルを追加または削除できます。これらの記号の使用目的を指定します(句読点、別の「メッセージ開始」記号、一般的な単語の記号など)。番号記号を完全に放棄し、番号を綴るか、チェッカーボードに各桁を含めることができます。番号記号が他の何かのためにあったスロットを使用します。回答で使用したチェッカーボードを指定してください。
  • 出力は、スペースで区切られた5桁のグループの文字列、5桁の整数のリスト、または同様のものである必要があります。
  • 0123456789私の例では、ゼロインデックスを使用しました。使用した1234567890ものを指定する限り、回答で1-indexingおよび、または他のシステムを使用できます。

ここでIdeone上の実装例では

これは長い投稿であり、ほとんどを手書きで書いたので、この投稿に紛らわしい部分がある場合や、カウントと転置のエラーがある場合はお知らせください。幸運と良いゴルフ!


1
adding the first two digits without adding運ぶという意味ですか?
isaacg

@isaacgはい、できました。編集済み。
シャーロック

あなたは何を意味するかについて明確でしたwithout borrowingwithout carrying?modの加算と減算10、つまり(6+7) mod 10 = 3and を意味します(6-8) mod 10 = 8か?
R.ガプス

@ R.Kapええ、それを明確にしましょう。
Sherlock9

私たちは、ください持っているが画定数字に?
R.ガプス

回答:


10

Pythonの31423 1348 1324 1316 1300 1286の 1250 1249 1209 1206 1204バイト

これは間違いなくこれまでで最長のゴルフであり、1文字の変数名が不足することを真剣に心配した唯一のゴルフです。ゴルフの提案を歓迎します。オンラインでお試しください!

大文字のラテンアルファベットと追加の文字.#使用してエンコードし、0インデックスを使用して、0123456789に変換gtます。私のチェッカーボードは、次の例のような形式です。

  2 9 7 4 5 8 3 1 0 6    # C
  S E N A T O R I        # keyword
0 B D G J L P U W Y .    # remaining alphabet arranged in columns
6 C F H K M Q V X Z #    # . and # at the end

編集: -63バイトは、1文字の変数で頻繁に使用される関数の一部を短縮するというTuukkaXの提案のおかげです。a, g, tコンパクト化から-12バイト。

編集:一度だけ使用される中間キーの変数名、つまりを削除して、-24バイトを作成しますa, g, s, S, k, K

編集:統合から-74バイトH(), T() and C()

編集: -1バイトに変更ord(s[i])+ord(s[i+1])することを提案してくれたNick Aに感謝しsum(map(ord,s[i:i+2]))ます。-の2回の+=[a]呼び出しの変更から-2バイト+=a,。-13バイトG()の最小値のインデックスの検索方法の変更からs。-2変化からバイトy=(y+1)%vy=-~y%vk.index()への割り当てから-15バイトK10への割り当てから-4バイトW。inside 1-I(d[-1])への割り当てから-5バイト。書き換えのメインループから-3バイト。-2バイトの再編成。XVC()T()

I=int;L=list;E=len;R=range;B=str;J=''.join;W=10
def H(s,e):
 for i in R(e-E(s)):s+=chr(48+sum(map(ord,s[i:i+2]))%32%W)
 return s
def Q(s):
 r=[0]*E(s);s=L(s)
 for z in R(E(s)):b=s.index(min(s));r[b]=z;s[b]="~"
 return r
def T(x,k,d=0):
 u=E(x);v=E(k);g=R(v);K=k.index;n=u//v+1;w=[];e=r=y=0;i=K(y);c=[]
 if d:
  while r<n:
   if r>n-1:i=min(i,(u%v or v))
   w+=L(x[e:e+i]),;e+=i;i+=1;r+=1
   if i>v:y=-~y%v;i=K(y)
  r=y=0;i=v-K(y)
  while r<n:
   w[r]+=L(x[e:e+i]);e+=i;i-=1;r+=1
   if i<1:y+=1;i+=v-K(y);r+=1
  w[-1]+=['']*(v-E(w[-1]))
  for j in g:c+=J(z[j]for z in w),
 else:c=[x[i::v]for i in g]
 s=[0]*v
 for f in g:s[k[f]]=c[f]
 return J(s)
def C(m,s,w,n):
 t={".":s[-2:],"#":s[-1]*2};j=z=0
 for x in R(26):
  v=chr(x+65)
  if v in w:t[v]=s[w.index(v)]
  else:t[v]=s[z-2]+s[j];j+=z;z=-~z%2
 r=J(i.isdigit()and i or t[i]for i in m)
 return r+n[:-E(r)%5]
def V(m,w,P,d,A,M,n):X=1-I(d[-1]);t=J(B(Q(P[W:20])[I(J(B((I(H(J(B((I(M[i])-I(d[i]))%W)for i in R(5)),W)[i])+I(Q(P[:W])[i]))%W)for i in R(W))[i])])for i in R(W));u=H(t,60)[W:];p=A+I(u[-2]);v=T(u,Q(t));z=T(T(C(m,J(B(i)for i in Q(u[40:])),w,n),Q(v[:p])),Q(v[p:p+A+I(u[-1])]),1);e=[z[5*i:5*-~i]for i in R(-(-E(z)//5))];return' '.join(e[:X]+[M]+e[X:])

アンゴルフ:

def chain_add(seq, end):
    for i in range(end - len(seq)):
        seq += chr(48+sum(map(ord,seq[i:i+2]))%32%10)
    return seq

def sequent(seq):
    res = [0]*len(seq)
    seq = list(seq)
    for z in range(len(seq)):
        b = seq.index(min(seq))
        res[b] = z
        seq[b] = "~"
    return res

def transpose(text, keys, disrupt=False):
    if disrupt:
        num_rows = len(text) // len(keys) + 1
        len_last = len(text) % len(keys)
        if len_last == 0:
            len_last = len(keys)
        d_rows = []
        text_index = 0
        current_row = 0
        stop_key = 0
        stop_index = keys.index(stop_key)
        while current_row < num_rows:
            if current_row > num_rows-1:
                stop_index = min(stop_index, len_last)
            d_rows += [list(text[text_index:text_index+stop_index])]
            text_index += stop_index
            stop_index += 1
            if stop_index>len(keys):
                stop_key = (stop_key+1) % len(keys)
                stop_index = keys.index(stop_key)
            current_row += 1
        current_row = 0
        stop_key = 0
        stop_len = len(keys) - keys.index(stop_key)
        while current_row < num_rows:
            d_rows[current_row] += list(text[text_index:text_index+stop_len])
            text_index += stop_len
            stop_len -= 1
            if stop_len < 1:
                stop_key += 1
                stop_len = len(keys) - keys.index(stop_key)
                current_row += 1
            current_row += 1
        d_rows[-1] += ['']*(len(keys)-len(d_rows[-1]))
        columns = []
        for j in range(len(keys)):
            columns += [''.join(i[j]for i in d_rows)]
    else:
        columns = ['']*len(keys)
        for t in range(len(text)):
            columns[t%len(keys)] += text[t]
    res = [0]*len(keys)
    for index in range(len(keys)):
        res[keys[index]] = columns[index]
    return''.join(res)

def checkerboard(message, seq, word, null):
    trans = {".":seq[-2:], "#":seq[-1]*2};res='';j=z=0
    for x in range(26):
        v = chr(x + 65)
        if v in word:
            trans[v] = seq[word.index(v)]
        else:
            trans[v] = seq[z-2] + seq[j]
            j += z
            z = (z+1) % 2
    for i in message:
        if i.isdigit():
            res += i
        else:
            res += trans[i]
    return res + null[:-len(res)%5]

def vic_cipher(message, keyword, phrase, date, agent, m_id, null):
    s1 = sequent(phrase[:10])
    s2 = sequent(phrase[10:20])
    a = ''.join(str((int(m_id[i])-int(date[i]))%10) for i in range(5))
    g = ''.join(str((int(a[i])+int(s1[i]))%10) for i in range(10))
    t = ''.join(str(s2[int(g[i])]) for i in range(10))
    u = chain_add(t,60)[10:]
    p = agent+int(u[-2])
    q = agent+int(u[-1])
    seqT = sequent(t)
    v = transpose(u,seqT)
    k1 = sequent(v[:p])
    k2 = sequent(v[p:p+q])
    c = ''.join(str(i)for i in sequent(u[40:]))
    x = checkerboard(message,c,keyword,null)
    y = transpose(x,k1)
    z = transpose(y,k2,1)
    e = [z[5*i:5*(i+1)] for i in range(-(-len(z)//5))]
    X = 1-int(date[-1])
    return ' '.join(e[:X] + [m_id] + e[X:])

2
Python 3では、Unicode文字を変数として使用できます(FYI)。
ポール

に変更ord(seq[i])+ord(seq[i+1])すると、sum(map(ord,seq[i:i+2]))1つのキャラクターが保存されます。

3

C、2880 2769 2766 2762 2743 2741 2739 2699 2458バイト

#include<stdio.h>
#define m(x)malloc(x)
#define Y(x)strlen(x)
typedef int i;typedef char*c;c _(c A,i B,i D){if(D>=B){return A;}c C=m(Y(A)+2);sprintf(C,"%s%c",A,48+(A[D]+A[D+1]-96)%10);return _(C,B,D+1);}c l(c A){i J=Y(A);c P=m(J+2);for(i m=0;m<J;m++){P[m]=32;}for(i v=0;v<J;v++){char G;i R;for(i u=0;u<J;u++){R=u<1|A[u]<G?u:R;G=u<1|A[u]<G?A[u]:G;}P[R]=48+v;c V=m(J);for(i t=0;t<J;t++){V[t]=t!=R?A[t]:97;}A=V;}return P;}c S(c C,c N,c I,char U){srand(time(NULL));i M=Y(I);i O=Y(N);i R=rand()%M;c Q=m(M+1);for(i u=R;u<M;u++){Q[u-R]=I[u];}Q[M-R]=46;for(i H=0;H<R;H++){Q[H+M-R+1]=I[H];}c g=m(28);c V=m(28);strcat(V,C);sprintf(g,"%s%s",N,"BCDFGHJKLMPQUVWXYZ.#");i B=Y(N);for(i q=B;q<10;q++){for(i x=0;x<10;x++){char J[2]={C[q],C[x]};V[B]=48+atoi(J);B++;}}c w=m(M*2+4);for(i J=0;J<=M;J++){i K=0;for(i X=0;X<28;X++){if(Q[J]==g[X]){char F[3];sprintf(F,"%d",V[X]-48);strcat(w,F);K=1;}}if(K<1){w[Y(w)]=Q[J];}}i f=Y(w);if(f%5>0){c P=m(5-f%5);for(i E=0;E<5-f%5;E++){P[E]=U;}strcat(w,P);}return w;}c a(c I,c U){i M=Y(I),K=Y(U);c T=m(M);i F=0;for(i b=0;b<K;b++){for(i y=0;y<K;y++){if(U[y]==48+b){for(i u=y;u<M;u+=K){T[F]=I[u];F++;}}}}return T;}c da(c I,c K){i e=Y(I),k=Y(K);c T=m(e);for(i y=0;y<e;y++){T[y]=32;}i F,P;F=P=0;for(i u=0;u<k;u++){for(i v=0;v<k;v++){T[F]=I[P];P++;F++;if(K[v+1]-48==u){for(i C=1;C<k-v;C++){F+=k-v-C;for(i E=0;E<=v+C;E++){if(F<e&P<e){T[F]=I[P];}F++;P++;}}break;}}if(F>e){break;}}i U=0;for(i g=0;g<e;g++){U=T[g]-48<10&-1<T[g]-48?U+1:U;}for(i j=U;j<e;j++){for(i x=0;x<e;x++){if(T[x]==32){T[x]=I[j];break;}}}return a(T,K);}En(c n,c m,c k,i d,c v,c s,char u){c S1,S2;S1=m(10);S2=m(10);for(i i=0;i<20;i++){if(i<10){S1[i]=k[i];}else{S2[i-10]=k[i];}}S1=l(S1);S2=l(S2);c M=m(5);for(i i=4;i>-1;i--){M[i]=48+(s[i]-v[i])%10;}c G=_(M,5,0);for(i y=0;y<10;y++){G[y]=48+(S1[y]+G[y]-96)%10;}c N="0123456789";c T=m(10);for(i q=0;q<10;q++){for(i t=0;t<10;t++){if(N[t]==G[q]){T[q]=S2[t];}}}c Z=_(T,50,0);c U=m(50);for(i h=0;h<50;h++){U[h]=Z[h+10];}i p,q;for(i b=49;b>10;b++){if(U[b]!=U[b-1]){q=d+U[b]-48;p=d+U[b-1]-48;break;}}c V=m(50);i Ct=0;for(i j=0;j<10;j++){for(i o=0;o<10;o++){if(l(T)[o]==48+j){for(i x=o;x<o+41;x+=10){V[Ct]=U[x];Ct+=1;}}}}c K1=m(p);c K2=m(q);for(i D=0;D<p+q;D++){if(D<p){K1[D]=V[D];}else{K2[D-p]=V[D];}}K1=l(K1);K2=l(K2);c C=m(10);for(i b=40;b<50;b++){C[b-40]=U[b];}C=l(C);c t=da(a(S(C,m,n,u),K1),K2);i O=0;for(i B=0;B<Y(t)/5+1;B++){if(B==Y(t)/5-v[Y(v)-1]+49){printf("%s ",s);}else{for(i J=O;J<O+5;J++){printf("%c",t[J]);}printf(" ");O+=5;}}}

やばい これは、私がまでゴルフをしたことがある最長のプログラムです。これは、実際にグローバルスコープの1文字の変数名を使い果たした最初のケ​​ースでもあるため、数文字の2文字の変数名を使用する必要がありました(明らかに変数を再宣言できないという事実は役に立ちません)。したがって、ゴルフのヒントは大歓迎です。

非ゴルフ

ゴルフバージョンとは異なり、警告なしでコンパイルします。ゴルフバージョンに加えられたわずかな変更は、このゴルフバージョンには反映されません。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

char*Chain_Add(char*String,int End,int Start){
  if(Start>=End){return String;}
  char*C=malloc(strlen(String)+2);
  sprintf(C,"%s%c",String,'0'+(((String[Start]-'0')+(String[Start+1]-'0'))%10));
  return Chain_Add(C,End,Start+1);
}

char*Sequent(char*String){
  int J=strlen(String);
  char*P=malloc(J+2);
  for(int m=0;m<J;m++){
    P[m]=' ';
  }
  for(int v=0;v<J;v++){
    char G;
    int R;
    for(int u=0;u<J;u++){
      R=(u<1||String[u]<G)?u:R;
      G=(u<1||String[u]<G)?String[u]:G;
    }
    P[R]='0'+v;
    char*V=malloc(J);
    for(int t=0;t<J;t++){
      if(t!=R){
    V[t]=String[t];
      }
      else{
    V[t]='a';
      }
    }
    String=V;
  }
  return P;
}

char*Straddling_Checkerboard(char*C,char*Key,char*Message,char null){
  srand(time(NULL));
  int Msg_Len=strlen(Message);
  int Key_Len=strlen(Key);
  int R=rand()%Msg_Len;
  char*Q=malloc(Msg_Len+1);
  for(int u=R;u<Msg_Len;u++){
    Q[u-R]=Message[u];
  }
  Q[Msg_Len-R]='.';
  for(int H=0;H<R;H++){
    Q[H+Msg_Len-R+1]=Message[H];
  }
  char*Alphabet=malloc(26);
  for(int W=0;W<26;W++){
    Alphabet[W]='A'+W;
  }
  int q=0;
  char*e=malloc(Key_Len);
  for(int z=0;z<Key_Len;z++){
    if(strchr(e,Key[z])!=NULL){
      q++;
    }
    else{
      e[z-q]=Key[z];
    }
  }
  int r=0;
  for(int h=0;h<26;h++){
    if(strchr(e,Alphabet[h-r])!=NULL){
      for(int X=h-r;X<26;X++){
    Alphabet[X]=Alphabet[X+1];
      }
      r++;
    }
  }
  char*Checkerboard=malloc(28);
  for(int i=0;i<26;i++){
    if(i<strlen(e)){
      Checkerboard[i]=e[i];
    }
    else{
      Checkerboard[i]=Alphabet[i-strlen(e)];
    }
  }
  Checkerboard[26]='.';
  Checkerboard[27]='#';
  char*Values=malloc(28);
  strcat(Values,C);
  int B=strlen(e);
  for(int q=B;q<10;q++){
    for(int x=0;x<10;x++){
      char J[2]={C[q],C[x]};
      Values[B]='0'+atoi(J);
      B++;
    }
  }
  char*Encoded=malloc(Msg_Len*2+4);
  for(int J=0;J<=Msg_Len;J++){
    int K=0;
    for(int X=0;X<28;X++){
      if(Q[J]==Checkerboard[X]){
    char F[3];
    sprintf(F,"%d",Values[X]-'0');
    strcat(Encoded,F);
    //printf("F = %s while Q[J] = %c and Checkerboard[X] = %c and Encoded = %s\n",F,Q[J],Checkerboard[X],Encoded);
    K=1;
      } 
    }
    if(K<1){
      Encoded[strlen(Encoded)]=Q[J];
    }
  }
  int Encded_Len=strlen(Encoded);
  if(Encded_Len%5>0){
    char*P=malloc(5-Encded_Len%5);
    for(int E=0;E<5-Encded_Len%5;E++){
      P[E]=null;
    }
  strcat(Encoded,P);
  }
  return Encoded;
}

char*Transpose(char*Message,char*K1){
  int Msg_Len=strlen(Message),K1_Len=strlen(K1);
  char*T=malloc(Msg_Len);
  int F=0;
  for(int i=0;i<K1_Len;i++){
    for(int y=0;y<K1_Len;y++){
      if(K1[y]=='0'+i){
    for(int u=y;u<Msg_Len;u+=K1_Len){
      T[F]=Message[u];
      F++;
    }
      }
    }
  }
  return T;
}

char*Disrupted_Transpose(char*Message,char*K2){
  int Msg_Len=strlen(Message),K2_Len=strlen(K2);
  char*T=malloc(Msg_Len);
  for(int y=0;y<Msg_Len;y++){
    T[y]=' ';
  }
  int F=0;
  int P=0;
  for(int u=0;u<K2_Len;u++){
    for(int v=0;v<K2_Len;v++){
      T[F]=Message[P];
      P++;F++;
      if(K2[v+1]-'0'==u){
        for(int C=1;C<K2_Len-v;C++){
      F+=K2_Len-v-C;
      for(int E=0;E<=v+C;E++){
        if(F<Msg_Len&P<Msg_Len){
          T[F]=Message[P];
        }
        F++;P++;
      }
    }
    break;
      }
    }
    if(F>Msg_Len){
      break;
    }
  }
  int U=0;
  for(int g=0;g<Msg_Len;g++){
    U=(T[g]-'0'<10&-1<T[g]-'0')?U+1:U;
  }
  for(int j=U;j<Msg_Len;j++){
    for(int x=0;x<Msg_Len;x++){
      if(T[x]==' '){
    T[x]=Message[j];
    break;
      }
    }
  }
  return Transpose(T,K2);
}

void VIC_Encoder(char*Message,char*Phrase,char*Key,int a_id,char*date,char*m_id,char null){
  char*S1=malloc(10);
  char*S2=malloc(10);
  for(int i=0;i<20;i++){
    if(i<10){
      S1[i]=Key[i];
    }
    else{
      S2[i-10]=Key[i];
    }
  }
  S1=Sequent(S1);
  S2=Sequent(S2);
  char*M=malloc(5);
  for(int i=4;i>-1;i--){
    M[i]='0'+(((m_id[i]-'0')-(date[i]-'0'))%10);
  }
  char*G=Chain_Add(M,5,0);
  for(int y=0;y<10;y++){
    G[y]='0'+(((S1[y]-'0')+(G[y]-'0'))%10);
  }
  char*N="0123456789";
  char*T=malloc(10);
  for(int q=0;q<10;q++){
    for(int t=0;t<10;t++){
      if(N[t]==G[q]){
    T[q]=S2[t];
      }
    }
  }
  char*Z=Chain_Add(T,50,0);
  char*U=malloc(50);
  for(int h=0;h<50;h++){
    U[h]=Z[h+10];
  }
  int p,q;
  for(int b=49;b>10;b++){
    if(U[b]!=U[b-1]){
      q=a_id+(U[b]-'0');
      p=a_id+(U[b-1]-'0');
      break;
    }
  }
  char*seqT=Sequent(T);
  char*V=malloc(50);
  int Count=0;
  for(int j=0;j<10;j++){
    for(int o=0;o<10;o++){
      if(seqT[o]=='0'+j){
    for(int x=o;x<o+41;x+=10){
      V[Count]=U[x];
      Count+=1;
    }
      }
    }
  }
  char*K1=malloc(p);
  char*K2=malloc(q);
  for(int D=0;D<p+q;D++){
    if(D<p){
      K1[D]=V[D];
    }
    else{
      K2[D-p]=V[D];
    }
  }
  K1=Sequent(K1);
  K2=Sequent(K2);
  char*C=malloc(10);
  for(int b=40;b<50;b++){
    C[b-40]=U[b];
  }
  C=Sequent(C);
  char*Transposed_2=Disrupted_Transpose(Transpose(Straddling_Checkerboard(C,Phrase,Message,null),K1),K2);
  int O=0;
  for(int B=0;B<strlen(Transposed_2)/5+1;B++){
    if(B==strlen(Transposed_2)/5-date[strlen(date)-1]+'1'){
      printf("%s ",m_id);
    }
    else{
      for(int J=O;J<O+5;J++){
    printf("%c",Transposed_2[J]);
      }
      printf(" ");
      O+=5;
    }
  }
}

ノート

  • これは、次のようなチェッカーボードを使用してメッセージをエンコードします。

      3 4 5 6 2 3 4 5 6 7
      S E N A T O R I     
    6 B C D F G H J K L M 
    7 P Q U V W X Y Z . #
    
  • これは、該当するすべての文字列が大文字で指定されていることを前提としています。メッセージにはすべての句読点も含める必要がありますを除くと、#sで区切られたすべての数字が必要です。一方、キーフレーズでは、すべての句読点を削除する必要があります

  • 結果のエンコードされたメッセージは、スペースで区切られた5桁のグループのストリングとしてSTDOUTに出力されます。

  • 入力メッセージは英語でなければなりません。

  • 使用した関数のいくつかを組み合わせたはずですが、その後、2文字の変数名を使用することに頼らなければならず、最終的なプログラムは、いくつかの関数よりも長くなります。

  • これは現在、キーワード(少なくとも英語)が常に同じ文字セットを含むことを想定していないため、重複を削除したり、チェッカーボードを操作したりすることで埋め合わせます。この機能は明らかにOPでは不要です。だから、私は現在、余分な、不要なバイトを取り込んでいます。ゴルフバージョン用に更新されました。


2

JavaScript(ES6)、946 938 953バイト

V=(c,d,f,g,j,k,m)=>{S=a=>a.split``,J=a=>a.join``,A=(a,b)=>{for(i=0;a[L="length"]<b;a+=(a[i++]- -a[i])%h);return a},Q=b=>(a=S(b).sort(),S(b).map(b=>a[i=a[X="indexOf"](b)]=i)),u=A(t=J(S(A(J(S(k).map((a,b)=>Math.abs(a-g[b]))),h=10)).map((a,b)=>Q(f[C="slice"](h,20))[(Q(f[C](0,h))[b]- -a)%h])),60)[C](h),T=((a,b,c)=>{if(r=Array(l=b[L]).fill(""),c){for(e=a[L]/l,i=0,w=[],u=R=b[X](x=0);i<e;)w[i++]=a[P](0,R++),u?u=0:R>l||(R=b[X](u=++x));for(i=0;i<e;)w[i]=J(w[i].concat(a[P](0,l-w[i++][L])));a=J(w)}for(i in a)r[+b[i%l]]+=a[i];return r}),v=J(T(u,Q(t))),q=J(Q(u[C](-h))),t="ABCDEFGHIJKLMNOPQRSTUVWXYZ#".match(new RegExp("[^"+d+"]","g")),t[P="splice"](9,0,"."),M=[];for(i in t)M[t[i]]=q[8^i/h]+(M[d[i]]=q[i%h]);for(n=c[L],b=J((c[C](n-=new Date%n)+"."+c[C](0,n)).split(/ |/).map(a=>M[a]||a)),b+=m.repeat(5-b[L]%5),i=f=q=49;f==q;)f=+u[i-1]+j,q=+u[i++]+j;return t=J(T(S(J(T(b,Q(v[C](0,f))))),Q(v.substr(f,q)),1)).match(/.{5}/g),g=-g[C](-1),g++&&t[P](g||t[L],0,k),t}

週末にこれに対するJSエントリがまだなかったので、ここに(最後の1分)の試みを示します。これを実装してゴルフをするのは楽しかったのと同じくらいクレイジーでした!

デモスニペット

編集:-8バイト

関数の周りに余分な括弧があることに気づいた S,J,A,Q

編集:+15バイト

message idが最終メッセージに配置される方法のロジックを更新しました(現在は1インデックスが付けられ、0は出力に含まれません)。

非ゴルフ

chainAdd = (s,l)=>{for(i=0;s.length<l;s+=(s[i++]- -s[i])%10);return s;}

sequentialize = (s)=> {
    a=s.split('').sort();
    return s.split('').map(c=>(i=a.indexOf(c),a[i]='',i));  
}

transpose = (s,k,disruptive)=>{
    var result=Array(k.length).fill('')
    if(disruptive){
        rows=[]
        k_index=0;
        rowLength=k.indexOf(k_index);
        triangling=!rowLength;

        expectedRows = s.length/k.length
        for(row=0;row<expectedRows;row++){
            rows[row]=s.splice(0,rowLength++)
            if(triangling){     
                if(rowLength>k.length){
                    triangling=false;
                    rowLength=k.indexOf(++k_index)              
                }
            }
            else{               
                triangling=true;
            }
        }

        for(row=0;row<expectedRows;row++){
            rows[row]= rows[row].concat(s.splice(0,k.length-rows[row].length)).join('')
        }
        s=rows.join('')
    }
    for(i in s)
        result[+k[i%k.length]]+=s[i];   
    return result;
}

checkerboard =(message,seq, keyword, nulls)=>{  
    t='ABCDEFGHIJKLMNOPQRSTUVWXYZ#'.match(new RegExp('[^'+keyword+']','g'));
    t.splice(9,0,'.')

    map=[]
    for(i in t)
        map[t[i]]=(seq[8^(i/10)])+(map[keyword[i]]=seq[i%10])

    r = new Date%message.length;
    rotateMessage=message.substr(message.length-r)+'.'+message.substr(0,message.length-r)

    result =rotateMessage.split(/ |/).map(x=>map[x]||x).join('');
    result+=nulls.repeat(5-result.length%5)

    return result;
}

vic = (message, keyword, phrase, date, agent, m_id, nulls)=>{
    s1=sequentialize(phrase.substr(0,10))//.join('')
    s2=sequentialize(phrase.substr(10,10))//.join('')

    r = m_id.split('').map((x,i)=>Math.abs(x-date[i])).join('')
    g = chainAdd(r,10).split('').map((x,i)=>(s1[i]- -x)%10);

    t = g.map(i=>s2[+i]).join('');
    u=chainAdd(t,60).substr(10)

    var p,q;
    for(i=49;p==q;i++){
        p=agent + +u[i-1];
        q=agent + +u[i];
    }
    seqT = sequentialize(t);
    v=transpose(u,seqT).join('');

    k1 = sequentialize(v.substr(0,p));
    k2 = sequentialize(v.substr(p,q));
    c  = sequentialize(u.substr(-10)).join('')

    CB =checkerboard(message,c, keyword, nulls);
    t1=transpose(CB,k1).join('')
    t2=transpose(t1.split(''),k2,1).join('').match(/.{5}/g);
    (d=-date.substr(-1))&&t2.splice((d+1)||t2.length,0,m_id);
    return t2;
}

ノート

  • これは、次のようなチェッカーボードを使用してメッセージをエンコードします。

      3 1 0 5 9 6 8 7 2 4
      S E N A T O R I
    2 B C D F G H J K L .
    4 M P Q U V W X Y Z #
    
  • すべての文字列は大文字で指定されます。メッセージは英数字のラテン文字(プラス.#)であり、すべての句読点(ピリオドを除く)を削除する必要があります。すべての番号はすでに#s でマークされているはずです。キーフレーズでは、すべての句読点/スペースを削除する必要があります。

  • 結果のメッセージは、5桁の文字列の配列として返されます。

機能強化

  • バイトを節約するために「すべての言語」を悪用する方法があるように感じます。もっと時間があれば、これを再考して、言語がハワイ語のような12文字しかないものだと仮定します。

  • ゴルフの提案はいつでも歓迎します。


これが機能することを確認できるように、スニペットを追加してください。もしそうなら、私はあなたに報奨金を授与することができます。
R.カップ

@ R.Kap確かに、デモスニペットを追加しました
SLuck49

うーん...デモでは、message identifierあるように思わ7代わりの端から離れました6。また、あなたの非ゴルフバージョンでは、同じIdことが終わりではなく始まり6から離れているようです。
R.ガプス

@ R.Kapええ、私が最初にそれを投稿したときにバグがありました(変更されていないはずです)。そうでない場合のでgolfedとして、私は0インデックスされたと仮定 1あなたが言うところの手段は非常に終わるmessage identifierに行くべき0?変更することができますが、知っておく必要があります。
SLuck49

私は上だと思います出力から省略されなければなりません。0message identifier
R. Kap

1

Clojure、1197 1212バイト

疲れた。

更新:必要なメッセージのランダムな分割場所を追加しました。ungolfedバージョンは、アルゴリズムを簡単に検証できるように、指定された例と同じ場所を使用します。

(defn enc[I K E D Y M](let[P split-at A concat Z zipmap R partition W mapcat % count X repeat O vector / map x(fn[C](apply / O C))G range t 10 r(G t)m(fn[i](mod i t))F(fn[[n & N]](/ last(iterate(fn[[[b & N]a]][(A N[(m(+ a b))])b])[N n])))Q(fn[S](for[i(G(% S))a[(nth S i)]](apply +(%(filter #{a}(take i S)))(for[b S :when(pos?(compare a b))]1))))[S J](/ Q(P t(take 20 E)))T(/(Z r J)(/ m(/ + S(F(/ - M D)))))U(take 50(drop t(F T)))l(last U)p(+ Y(last(remove #{l}U)))V(W(Z(Q T)(x(R t U)))r)[k j](/ Q(P p(take(+ p Y l)V)))B(into(Z(/ char(G 48 58))(G))(/(fn[i c][c(+(*(quot i 10)20)(nth(Q(reverse(take t(reverse U))))(m i)))])(G)(A(str K",,")(remove(set K)(/ char(A(G 65 91)".#"))))))?(% k)T(vec(filter some?(W(Z k(x(R ?(A(flatten(R 5(A(W str(/ B(let[[b e](P(rand-int(count I))I)](apply str(A e".. "b)))))(X 4(B\,)))))(X(dec ?)nil)))))(G ?))))w (% j)NR(+(quot(% T)w)1)L(flatten(for[k r](for[i(G(.indexOf j k)(inc w))](G i))))C(for[[r c](/ O(rest(reductions + -1(/(fn[i](get{0 1}i 0))L)))L):when(< r NR)][r c])H(R 5(filter some?(W(Z j(x(R w (A(vals(into(sorted-map)(/ O(A C(for[i(G NR)j(G w)c[[i j]]:when(not((set C)c))]c))T)))(X(dec w)nil)))))(G w))))](/(fn[p](apply str p))(let[[b e](P(-(% H)(D 6)-1)H)](A b[M]e)))))

サンプル入力とテストケース:

(def mymsg (clojure.string/upper-case "We are discovered. Take what you can. Burn everything else. Move to Safehouse Foxtrot#3#"))
(def mykey "SENATORI")
(def mypharase (clojure.string/upper-case (apply str (remove #{\space} "The first principle is that you must not fool yourself — and you are the easiest person to fool."))))
(def mydate [3 1 7 2 0 1 6])
(def mynum 9)
(def M [4 7 9 2 1])

;("61231" "12824" "71192" "58609" "92185" "48612" "14927" "22944" "34046" "13348" "04159" "38645" "70546" "20254" "22026" "64584" "21904" "47921" "90253" "42694" "42221" "56644" "14541")
(enc mymsg mykey mypharase mydate mynum M)

ゴルフをしていない:

(defn enc[mymsg mykey mypharase mydate mynum M]
  (let[t       10
       r       (range t)
       m       (fn[i](mod i t))
       lagfib  (fn[[n & N]](map last(iterate(fn[[[b & N]a]][(concat N[(m(+ a b))])b])[N n])))
       toseq   (fn[S](for[i(range(count S))a[(nth S i)]](apply +(count(filter #{a}(take i S)))(for[b S :when(pos?(compare a b))]1))))
       [S1 S2] (map toseq(split-at t(take 20 mypharase)))
       M2      (take t(lagfib(map - M mydate)))
       G       (map m(map + S1 M2))
       Gmap    (zipmap r S2)
       T       (map Gmap G)
       U       (take 50(drop t(lagfib T)))
       L2      (last U)
       L1      (last(remove #{L2}U))
       p       (+ mynum L1)
       q       (+ mynum L2)
       seqT    (toseq T)
       V       (mapcat(zipmap seqT(apply map vector(partition t U)))r)
       [K1 K2] (map toseq(split-at p(take(+ p q)V)))
       C       (toseq(reverse(take t(reverse U))))
       B       (into(zipmap(map char(range 48 58))(range))(map(fn[i c][c(+(*(quot i 10)20)(nth C(m i)))])(range)(concat(str mykey",,")(remove(set mykey)(map char(concat(range 65 91)".#"))))))
      ;B       (into(zipmap(map char(range 48 58))(range))(map(fn[i c][c(+(nth C(quot i 3))(*(mod i 3)20))])(range)(flatten(apply map vector(partition 10(apply concat mykey",,"(apply map vector (partition 2(remove(set mykey)(map char(concat(range 65 91)".#")))))))))))
       N1      (count K1)
       mymsg   (flatten(partition 5(concat(mapcat str(map B(let[[b e](split-at 49 mymsg)](apply str(concat e".. "b)))))(repeat 4(B\,)))))
       T1      (vec(filter some?(mapcat(zipmap K1(apply map vector(partition N1(concat mymsg(repeat(dec N1)nil)))))(range N1))))
       N2      (count K2)
       NR      (+(quot(count T1)N2)1)
       cols    (flatten(for[k r](for[i(range(.indexOf K2 k)(+(count K2)1))](range i))))
       rows    (rest(reductions + -1(map(fn[i](get{0 1}i 0))cols)))
       coords  (for[[r c](map vector rows cols):when(< r NR)][r c])
       coords  (concat coords(for[i(range NR)j(range N2)c[[i j]]:when(not((set coords)c))]c))
       T2      (partition 5(filter some?(mapcat(zipmap K2(apply map vector(partition N2(concat(vals(into(sorted-map)(map vector coords T1)))(repeat(dec N2)nil)))))(range N2))))]
    (map(fn[p](apply str p))(let[[b e](split-at(-(count T2)(mydate 6)-1)T2)](concat b[M]e)))))

Bタスク定義と同じチェッカーボード上の代替実装があります。ただし、サブミッションでは、未使用のアルファベットが最初に2行目を埋め、次に列ごとに埋めるのではなく3行目を埋める別の文字列を使用します。


Clojureソリューションの作成を検討しましたが、質問を読んでいるときに頭が爆発しました。書くのにどれくらいかかりましたか?
発癌性

横にあるYoutubeを見ながら3時間か。これは非常に簡単に始まりましたが、2番目の「中断された転置」を実装しなければならなかったとき、私はあきらめようとしました。これcoordsは2回生成され、最初に三角形を生成してから、欠落していた座標を埋めます。1つの元素とNの長さに分割する-また、「多重Nの長さにパディング」は、Nを連結するよりも、よりエレガントな解決策があるかもしれない
NikoNyrh

ああ、ハードコードされたスプリットポイントを変更するのを忘れた (split-at 49 mymsg) 49、49のようなものになるはずな(rand-int(count mymsg))ので、正解は1200バイトを少し超えるでしょう。zzz
ニコニール

くそー。おそらくcの答えよりもまだ少ないでしょう。
発癌性
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.