文字列をエンコードするために自分自身を並べ替えるプログラム(クインバリアント)


16

次の80文字の行を印刷するプログラムを作成します。

codegolf.stackexchange.comのこのプログラムは、文字列をエンコードするためにそれ自体を置換します。

その後、1行の入力を受け入れ、そのコードポイントを並べ替えてソースコードを出力します(追加も削除もされません)。そのコードが実行されるとき、印刷された行が入力の最新の行であることを除いて、同じことが起こる必要があります。

Perlスタイルの正規表現^[A-Za-z0-9. ]{80}$は、任意の入力行に一致します。追加の仮定を行うことはできません。

提出のスコアは、ソースコードのコードポイントの数から94を引いたものです。低いほど良い。

コードはQUINE(に受け入れられない何もないしなければならない例えば、ファイルの読み取りを)。特に、負のスコアを持つ投稿は、なんとか93として不正行為でなければなりません!64 80未満です。

2014-04-21を追加しました。プログラムのソースコード全体が、コードポイントをカウントする文字エンコーディングで整形式でなければなりません。たとえば、UTF-8の末尾のバイト範囲(80..BF)で80個の連続したバイトを使用し、それぞれを単一のU + FFFD REPLACEMENT CHARACTERとしてカウントすることはできません(さらに悪いことに、コードポイントではないため)。

また、エンコードは複数のコードポイント(コード化する方法を許可する場合など SCSUを、)、あなたのプログラムだけでなく、それが直接的または間接的に発生し、すべてのプログラムをのみ、そのうちの1つ(または少なくともすべてを使用しなければならないコード全体同等に扱われなければなりません)。


あなたの質問を読み直した後、私の答えがあなたが念頭に置いていたものと正確に一致するかどうかはわかりません。新しい文字列をプログラムにパイピングしても問題ありませんか、または対話式プロンプトを起動する必要がありますか?
デニス

@Dennis:それがあなたの答えが受け入れられない理由ではありません。むしろ、「This program from [...]」を印刷するに入力を読み取ります。
プリーズスタンド

それが私が意図したことです、私はそれをうまく表現しませんでした。GolfScriptインタープリターは、スクリプトの実行を開始する前にパイプされたすべてのものを読み取ります。これを回避する唯一の方法は、プロンプトを起動することであり、これはパイピングを不可能にします。
デニス

こんにちは、JavaScriptでこれを試しています。<script>タグの間にあるテキストを読まずにクインを作成することは不可能に思えますか?ソースコードを並べ替える目的は何ですか?あなたは「おそらく再注文された」と言います。これは必要な場合にのみ並べ替えを意味しますか?
バッカスビール

回答:


5

GolfScript、231 162 131

'1àâ4ÿaVo5GùpZBtiXOürsóNîMmWåKHc09JdñúêyzíECäYïhDU ãáIFõ6é8òRìjTv23ønuðLwxfSkôbëAelqý.çèPQ
öûg7'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~

使い方

文字列をエンコードするために並べ替えられる94の異なる文字を選択することから始めます。任意の94文字を使用できますが、ゴルフの目的で以下を選択します。

\n .0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
àáâãäåçèéêëìíîïðñòóôõöøùúûüýÿ

これらの文字の配列を「&」と呼びましょう。

入力行には常に81文字(LFを含む)が含まれます。これらの文字はすべて、「&」の最初の65文字に含まれています。これが、上位128バイトの文字を選択する唯一の理由です。

文字列の各文字を“&”のインデックスで置き換えるため、LFは0になり、スペースは1になります。

取得した81個の数字は、単一の基数65の数字と見なされます。この番号を「N」と呼びましょう。

ここで、「&」の可能なすべての順列を列挙し、上記の番号に対応する順列を取得します。これは、次の方法で実現されます。

  1. 設定c = 1A = []ます。
  2. に追加N % cAます。
  3. 設定N = N / cc = c + 1ます。
  4. の場合c < 95、2に戻ります。
  5. 設定i = 0s = ""ます。
  6. 文字を取得し、&[A[i]]「s」に追加して「&」から削除します。
  7. 設定しi = i + 1ます。
  8. i < 946に戻る場合。

上記で説明したように、文字列をエンコードおよびデコードするコードブロック「E」および「D」があるとします。

次に、質問の要件に準拠するコードブロックのラッパーが必要です。

'encoded string'{\.$[{}/]:&; D puts '"#{`head -1`}"'~ E "'".@+\+\'.~'}.~

これは次のことを行います。

  • {…}.~ブロックを定義して複製し、2番目のコピーを実行します。最初のコピーはスタックに残ります。

  • \.$ エンコードされた文字列をブロックと交換し、ソートされた文字でエンコードされた文字列のコピーを作成します。

  • [{}/]:&; 文字列を上から配列に変換し、「&」に保存して破棄します。

  • D puts エンコードされた文字列をデコードし、結果を出力します。

  • '"#{`head -1`}"'~head -1シェルで実行することにより、入力の1行を読み取ります。

  • E "'".@+\+ 文字列をエンコードし、単一引用符を付加して追加します。

  • \'.~'エンコードされた文字列とブロックを交換し、文字列を追加します'.~'

  • ブロックが実行された後、GolfScriptはスタックの内容(エンコードされた文字列、ブロック'.~')を出力して終了します。

「E」は次のように定義できます。

{&?}%        # Replace each character by its index in “&”.
);           # Remove the last integer from the array, since it corresponds to the LF.
65base       # Convert the array to an integer “N” by considering it a base 65 number.
[            #
  94,        # For each integer “c” in 0 … 93:
  {          #
    )        # Increment “c”.
    1$1$%    # Push “N % c”.
    @@/      # Rotate “N % c” below “N” and “c” and divide the first by the latter.
  }/;        # Discard “N”.
]            # Collect the results of “N % c” in an array “A”.
-1%          # Reverse “A”.
&\           # Push “&” and swap it with “A”.
[            #
  {          # For each “j” in “A”:
    1$=.[]+  # Push “&[j] [&[j]]”.
    @^       # Rotate “&” on top of “[&[j]]” and take their symmetric difference.
  }/         #
]            # Collect the charcters into an array.

「D」は次のように定義できます。

0&           # Push 0 (initial value of the accumulator “A”) and “&”.
@            # Rotate the encoded string on top of “&”.
{            # For each character “c” of the encoded string:
    @2$,*    # Rotate “A” on top of the stack and multiply it by the length of “&”.
    2$2$?+   # Get the index of “c” in “&” and add it to “A”.
    @@^      # Rotate “A” below “&” and “c” and take their symmetric difference.
}/;          # Discard “&”.
65base       # Convert “A” into the array of its digits in base 65.
{&=}%        # Replace each digit by the corresponding character in “&”.
''+          # Convert the resulting array into a string.

最終的なゴルフ:

  • 置換\.$[{}/]:&;0&@0@.$[{}/]:&\て2文字を保存します。

  • {;65base}:b1つの文字を保存する関数を定義します。

  • 文字列の末尾のLFとLFを除くすべての空白を削除します。

$ # Create GolfScript file using base64 to avoid encoding issues.
$ base64 > permute.gs -d <<< JzHg4jT/YVZvNUf5cFpCdGlYT/xyc/NO7k1tV+VLSGMwOUpk8frqeXrtRUPkWe9oRFUg4+FJRvU26TjyUuxqVHYyM/hudfBMd3hmU2v0YutBZWxx/S7n6FBRCvb7ZzcnezBALiRbe30vXTomXHtAMiQsKjIkMiQ/K0BAXn0vezs2NWJhc2V9OmJ+eyY9fSUnJytwdXRzJyIje2BoZWFkIC0xYH0iJ357Jj99JSliWzk0LHspMSQxJCVAQC99LztdLTElJlxbezEkPS5AXn0vXSInIi5AK1wrXCcufid9Ln4K
$
$ # Set locale to en_US (or any other where one character is one byte).
$ LANG=en_US
$
$ # Go back and forth between two different strings.
$ # Second and sixth line are user input, not output from the script.
$
$ golfscript permute.gs | tee >(tail -n+2 > tmp.gs) && golfscript tmp.gs && rm tmp.gs
This program from codegolf.stackexchange.com permutes itself to encode a string.
Permuting source code code points to encode a string is a certain quine variant.
'18äJoS3sgV9qdçëxm0ÿKMNe5íPî.Htn2ciâIuøbRZéð4AwB7áìUüöôWõèûfñåLàóDrhQlO6
pTaýzòkùYCyFêïãG júEvX'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~
Permuting source code code points to encode a string is a certain quine variant.
This program from codegolf.stackexchange.com permutes itself to encode a string.
'1àâ4ÿaVo5GùpZBtiXOürsóNîMmWåKHc09JdñúêyzíECäYïhDU ãáIFõ6é8òRìjTv23ønuðLwxfSkôbëAelqý.çèPQ
öûg7'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~
$
$ # Sort all characters from the original source code and hash them.
$ fold -1 permute.gs | sort | md5sum
b5d978c81df5354fcda8662cf89a9784  -
$
$ # Sort all characters from the second output (modified source code) and hash them.
$ golfscript permute.gs | tail -n+2 | fold -1 | sort | md5sum
Permuting source code code points to encode a string is a certain quine variant.
b5d978c81df5354fcda8662cf89a9784  -
$
$ # The hashes match, so the characters of the modified source code are a permutation
$ # of the character of the original one.

224マイナス94は130です
。– mbomb007

詳しく説明してもらえますか?
デニス

1

Perl、1428 1099

これには1193個のASCII文字(960個の置換された2進数を含む)があります。1193-94 = 1099

$s='010011100001100010101100111111101001101011101000100000101011011010100110111111011111101011101000100110111111011100101000011101011110100000101000100101011111111110101100101101011010011100100100011110110001011100100001011010100111100000011110111110011100101000100110111111101001011110101011100110101110101101011110101100111111100010101101101100011110100101011111111111101101101000111111011110100111011100101000011101011110111111011010111111101100101101101011100010100111100000111110';$_=q{$i=join'',A..Z,a..z,0..9,'. ';print map({substr$i,oct'0b'.$_,1}$s=~/.{6}/g),$/;chop($s=<>);$s=join'',map{sprintf"%06b",index$i,$_}$s=~/./g;$t=join'',map{$_ x(480-(()=$s=~/$_/g))}0,1;print"\$s='$s';\$_=q{$_};eval#$t"};eval#000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

私の最初のデザイン

デニスからバイナリに切り替えるよう提案される前に、私のプログラムは8進数を並べ替えました。

私の最初の設計では、文字ごとに2桁の160文字の8進数で各文字列をエンコードします。このエンコードには、100 8 = 64個の異なる文字があります。8進法には8つの異なる数字があります。プログラムには各桁のコピーが160個必要であるため、8×160 = 1280桁を並べ替えます。

私は160桁を保持$sし、他の1120桁を保持し$tます。私はQUINEないプログラムを起動し、だけに割り当てを印刷し$sそして$t次の実行のために。これだよ:

$s = '2341425477515350405332467737535046773450353640504537765455323444366134413247403676345046775136534656553654774255543645377755507736473450353677327754555342474076';
$t = '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777';

# $i = character map of 64 characters, such that:
#  substr($i, $_, 1) is the character at index $_
#  index($i, $_) is the index of character $_
$i = join '', 'A'..'Z', 'a'..'z', '0'..'9', '. ';

# Decode $s from octal, print.
#  1. ($s =~ /../g) splits $s into a list of pairs of octal digits.
#  2. map() takes each $_ from this list.
#  3. oct() converts $_ from an octal string to a number.
#  4. substr() on $i converts number to character.
#  5. print() outputs the characters from map() and a final "\n".
print map({ substr $i, oct, 1 } $s =~ /../g), "\n";

# Read new $s, encode to octal.
#  1. ($s = <>) reads a line.
#  2. chop($s) removes the last character of $s, the "\n".
#  3. ($s =~ /./g) splits $s into characters.
#  4. map() encodes each character $_ as a pair of octal digits.
#  5. join() concatenates the pairs from map().
chop($s = <>);
$s = join '', map { sprintf "%02o", index $i, $_ } $s =~ /./g;

# Make new $t.
#  1. map() takes each $_ from 0 to 7.
#  2. $_ x (160 - (() = $s =~ /$_/g)) makes a string where $_ repeats
#     160 times, minus the number of times that $_ appears in $s.
#  3. join() concatentates the strings from map().
$t = join '', map { $_ x (160 - (() = $s =~ /$_/g)) } 0..7;

# Print the new assignments for $s and $t.  This is not yet a quine,
# because it does not print the rest of the program.
print "\$s = '$s';\n\$t = '$t';\n";

(() = $s =~ /$_/g))変数の空のリストへの割り当てです。PerlMonksコンテキストチュートリアルからこのトリックを取り上げます。一致演算子のリストコンテキストを強制します=~。スカラーコンテキストでは、一致はtrueまたはfalseになり$i++ while ($s =~ /$_/g)、一致をカウントするようなループが必要になります。リストコンテキストで$s =~ /$_/gは、一致のリストです。このリストを減算のスカラーコンテキストに入れるので、Perlはリスト要素をカウントします。

を作るために、Rosetta CodeのPerl quines$_=q{print"\$_=q{$_};eval"};evalからフォームを取ります。これは文字列q{...}を割り当ててから$_を呼び出すevalので、文字列にコードを入れて実行することもできます。私のプログラムは、私が最後の行に私の第三のラップQUINEなり$_=q{};eval、そして私が最後に変更printしますprint "\$s = '$s';\n\$t = '$t';\n\$_=q{$_};eval"

最後に、最初の割り当てを$tコメントに変更し、余分な文字を削除して、プログラムをゴルフします。

これには1522個のASCII文字が含まれます(置換された1280の8進数を含む)。
1522-94 = 1428

$s='2341425477515350405332467737535046773450353640504537765455323444366134413247403676345046775136534656553654774255543645377755507736473450353677327754555342474076';#0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
$_=q{$i=join'','A'..'Z','a'..'z','0'..'9','. ';print map({substr$i,oct,1}$s=~/../g),"\n";chop($s=<>);$s=join'',map{sprintf"%02o",index$i,$_}$s=~/./g;$t=join'',map{$_ x(160-(()=$s=~/$_/g))}0..7;print"\$s='$s';#$t\n\$_=q{$_};eval"};eval

バイナリへの切り替え

コメントでは、デニスは、960個の置換された2進数が1280の8進数よりも少ないことに気付きました。そこで、各ベースの置換された数字の数を2〜16でグラフ化しました。

Maxima 5.29.1 http://maxima.sourceforge.net
using Lisp ECL 13.5.1
...
(%i36) n : floor(x);
(%o36)                             floor(x)
...
(%i41) plot2d(n * ceiling(log(64) / log(n)) * 80, [x, 2, 16],
              [xlabel, "base"], [ylabel, "number of permuted digits"]);
(%o41) 

x軸に基数、y軸に置換された桁数を持つグラフ

8を基数とするのはローカルミニマムですが、2と3および4の基数は960桁の最適な基数につながります。コードゴルフの場合、Perlにはベース2の変換があるため、ベース2が最適です。

1280の8進数を960の2進数に置き換えると、320文字節約されます。

コードを8進数から2進数に切り替えるには、8文字かかります。

  • 変更octoct'0b'.$_コスト7。
  • 変更/../g/.{6}/gコスト2。
  • "%02o"「%06b」 `コスト0への変更。
  • コスト0に変更160480ます。
  • 変更0..7には0,11が保存されます。

Perlゴルフのヒントを学びました。彼らは14文字を保存します:

  • に変更'A'..'Z','a'..'z','0'..'9'A..Z,a..z,0..9、裸の単語と裸の数字を使用して、12文字を節約します。
  • 2文字"\n"$/保存するように変更します。

#$tコメントをファイルの最後に移動して、3文字を保存します。これにより、コメントを終了する改行と\n、クインのリテラルが削除されます。

これらの変更により、合計329文字が節約され、スコアが1428から1099に減少します。


1
8進数の代わりに2進数を使用するには、960文字の「可変」文字のみが必要です。
デニス

@Dennisヒントをありがとう!バイナリに切り替えました(312文字を節約)。ここにいる間に、私はさらに17人のキャラクターをゴルフで打ち切りました。
カーニグ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.