Program yang memungkinkan dirinya untuk menyandikan string (quine-varian)

16

Tulis program yang mencetak baris 80 karakter berikut:

Program ini dari codegolf.stackexchange.com memungkinkan dirinya untuk menyandikan string.

kemudian menerima satu baris input, lalu mencetak kode sumbernya dengan titik kode yang mungkin disusun ulang (tidak ada yang ditambahkan dan tidak ada yang dihapus). Ketika kode itu dieksekusi, hal yang sama harus terjadi, kecuali baris yang dicetak akan menjadi jalur input terbaru.

Regex-style Perl ^[A-Za-z0-9. ]{80}$akan cocok dengan semua input. Anda tidak dapat membuat asumsi tambahan.

Skor pengajuan adalah jumlah poin kode dalam kode sumbernya kurang dari 94 . Lebih rendah lebih baik.

Kode tidak boleh melakukan apa pun yang tidak dapat diterima dalam quine ( mis . Pembacaan file). Khususnya, setiap pengajuan dengan skor negatif harus curang entah bagaimana, seperti 93! kurang dari 64 80 .

Ditambahkan 2014-04-21: Seluruh kode sumber program Anda harus terbentuk dengan baik dalam pengkodean karakter tempat Anda menghitung poin kode. Misalnya, Anda tidak dapat menggunakan 80 byte berturut-turut dalam rentang byte trailing UTF-8 (80..BF) dan menghitung masing-masing sebagai satu KARAKTER PENGGANTIAN U + FFFD (atau lebih buruk, karena bukan titik kode sama sekali).

Selain itu, jika penyandian memungkinkan beberapa cara untuk menyandikan titik kode ( misalnya SCSU ), program Anda, serta semua program yang dihasilkan secara langsung atau tidak langsung, hanya boleh menggunakan salah satunya (atau setidaknya semua harus diperlakukan secara setara di seluruh kode) ).

Tolong berdiri
sumber
Setelah membaca ulang pertanyaan Anda, saya tidak yakin apakah jawaban saya tepat seperti yang Anda pikirkan. Apakah mem-piping string baru ke program OK atau harus meluncurkan prompt interaktif?
Dennis
@ Dennis: Bukan itu sebabnya jawaban Anda tidak bisa diterima. Sebaliknya, ia membaca input sebelum mencetak "Program ini dari [...]".
PleaseStand
Itulah yang saya maksud, saya hanya tidak mengungkapkannya dengan baik. Interpreter GolfScript membaca semua yang disalurkan sebelum mulai menjalankan skrip. Satu-satunya cara untuk menghindari ini adalah meluncurkan prompt, yang membuat perpipaan tidak mungkin.
Dennis
Hai, saya mencoba ini dalam JavaScript. Tampaknya tidak mungkin membuat quine tanpa membaca teks di antara tag <script>? Apa tujuan dari permutasi kode sumber? Anda mengatakan 'mungkin memesan ulang'; apakah ini berarti permutasi hanya jika perlu?
bacchusbeale

Jawaban:

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$=.@^}/]"'".@+\+\'.~'}.~

Bagaimana itu bekerja

Kami mulai dengan memilih 94 karakter berbeda yang akan diizinkan untuk menyandikan string. 94 karakter apa pun akan berfungsi, tetapi kami memilih yang berikut untuk tujuan bermain golf:

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

Sebut saja larik karakter ini "&".

Baris input akan selalu berisi 81 karakter (termasuk LF). Semua karakter tersebut hadir dalam 65 karakter pertama "&". Ini adalah satu-satunya alasan untuk memilih karakter dalam 128 byte atas.

Kami mengganti setiap karakter string dengan indeksnya di "&", jadi LF menjadi 0, spasi menjadi 1, dll.

Kami menganggap 81 nomor yang diperoleh sebagai digit dari satu nomor basis 65. Sebut saja nomor ini "N".

Sekarang, kami menghitung semua kemungkinan permutasi "&" dan mengambil permutasi yang sesuai dengan nomor dari atas. Ini dicapai dengan cara berikut:

  1. Atur c = 1dan A = [].
  2. Berlaku N % cuntuk A.
  3. Atur N = N / cdan c = c + 1.
  4. Jika c < 95, kembali ke 2.
  5. Atur i = 0dan s = "".
  6. Ambil charcter &[A[i]], tambahkan ke "s" dan hapus dari "&".
  7. Setel i = i + 1.
  8. Jika i < 94kembali ke 6.

Misalkan kita memiliki blok kode "E" dan "D" yang menyandikan dan mendekode string seperti dijelaskan di atas.

Sekarang, kita membutuhkan pembungkus untuk blok kode yang memenuhi persyaratan pertanyaan:

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

Ini melakukan hal berikut:

  • {…}.~mendefinisikan sebuah blok, menggandakannya dan mengeksekusi salinan kedua. Salinan pertama akan tetap di tumpukan.

  • \.$ menukar string yang disandikan dengan blok dan membuat salinan dari string yang disandikan, dengan karakter yang diurutkan.

  • [{}/]:&; mengubah string dari atas menjadi sebuah array, menyimpannya di "&" dan membuangnya.

  • D puts mendekodekan string yang disandikan dan mencetak hasilnya.

  • '"#{`head -1`}"'~membaca satu baris input dengan mengeksekusi head -1di shell.

  • E "'".@+\+ mengkodekan string dan menambahkan dan menambahkan satu kutipan.

  • \'.~'menukar string yang disandikan dan blok dan menambahkan string '.~'.

  • Setelah blok telah dieksekusi, GolfScript mencetak isi stack (string yang dikodekan, blok, '.~') dan keluar.

"E" dapat didefinisikan sebagai berikut:

{&?}%        # 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" dapat didefinisikan sebagai berikut:

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.

Golf terakhir:

  • Ganti \.$[{}/]:&;0&@dengan 0@.$[{}/]:&\untuk menyimpan dua karakter.

  • Tentukan fungsi {;65base}:buntuk menyimpan satu karakter.

  • Hapus semua spasi putih kecuali LF tertinggal dan LF dalam string.

Contoh

$ # 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.
Dennis
sumber
224 minus 94 adalah 130.
mbomb007
Bisakah Anda menguraikan?
Dennis
1

Perl, 1428 1099

Ini memiliki 1193 karakter ASCII (termasuk 960 digit biner yang diijinkan). 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

Desain pertama saya

Sebelum saya mengambil saran dari Dennis untuk beralih ke biner, program saya mengijinkan digit oktal.

Desain pertama saya mengkodekan setiap string dalam 160 digit oktal, dengan 2 digit per karakter. Pengkodean ini memiliki 100 8 = 64 karakter yang berbeda. Sistem oktal memiliki 8 digit berbeda. Program harus memiliki 160 salinan dari setiap digit, sehingga memungkinkan 8 × 160 = 1280 digit.

Saya menyimpan 160 digit $sdan 1.120 digit lainnya masuk $t. Saya mulai dengan program yang bukan quine, tetapi hanya mencetak tugas untuk $sdan $tuntuk menjalankan selanjutnya. Ini dia:

$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))adalah penugasan ke daftar variabel yang kosong. Saya mengambil trik ini dari tutorial konteks di PerlMonks . Ini memaksa konteks daftar pada operator pertandingan =~. Dalam konteks skalar, kecocokan akan benar atau salah, dan saya akan memerlukan loop ingin $i++ while ($s =~ /$_/g)menghitung kecocokan. Dalam konteks daftar, $s =~ /$_/gadalah daftar kecocokan. Saya menempatkan daftar ini dalam konteks skalar pengurangan, jadi Perl menghitung elemen daftar.

Untuk membuat quine, saya mengambil formulir $_=q{print"\$_=q{$_};eval"};evaldari quines Perl di Rosetta Code . Yang ini memberikan sebuah string q{...}ke $_dan kemudian memanggil eval, jadi saya dapat memiliki kode saya dalam sebuah string dan juga menjalankannya. Program saya menjadi quine ketika saya membungkus baris ketiga ke terakhir di $_=q{dan };eval, dan mengubah yang terakhir printke print "\$s = '$s';\n\$t = '$t';\n\$_=q{$_};eval".

Akhirnya, saya mengubah program saya dengan mengubah tugas pertama $tmenjadi komentar, dan dengan menghapus karakter tambahan.

Ini memiliki 1522 karakter ASCII (termasuk 1280 digit oktal yang diijinkan).
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

Beralih ke biner

Dalam komentar, Dennis memperhatikan bahwa 960 digit biner yang diijinkan akan kurang dari 1280 digit oktal. Jadi saya membuat grafik jumlah digit yang diijinkan untuk setiap basis dari 2 hingga 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) 

grafik dengan basis pada sumbu x, jumlah digit permutasi pada sumbu y

Meskipun basis 8 adalah minimum lokal, basis 2 dan 3 dan 4 mengikat untuk basis terbaik, pada 960 digit yang diijinkan. Untuk golf kode, base 2 adalah yang terbaik karena Perl memiliki konversi untuk base 2.

Mengganti 1280 digit oktal dengan 960 digit biner menghemat 320 karakter.

Mengubah kode dari oktal ke biner menghabiskan 8 karakter:

  • Ubah octke oct'0b'.$_biaya 7.
  • Ubah /../gke /.{6}/gbiaya 2.
  • Ubah "%02o"ke "% 06b" `biaya 0.
  • Ubah 160ke 480biaya 0.
  • Ubah 0..7untuk 0,1menyimpan 1.

Saya belajar beberapa tips golf Perl . Mereka menyimpan 14 karakter:

  • Ubah 'A'..'Z','a'..'z','0'..'9'ke A..Z,a..z,0..9, menggunakan kata kunci dan angka telanjang, menyimpan 12 karakter.
  • Ubah "\n"untuk $/menyimpan 2 karakter.

Saya menyimpan 3 karakter dengan memindahkan #$tkomentar ke akhir file. Ini menghapus baris baru yang mengakhiri komentar, dan literal \ndi quine.

Perubahan ini menyimpan total 329 karakter, dan mengurangi skor saya dari 1428 menjadi 1099.

kernigh
sumber
1
Menggunakan biner alih-alih digit oktal akan membutuhkan "hanya" 960 karakter yang dapat diijinkan.
Dennis
@ Dennis Terima kasih atas tipnya! Saya beralih ke biner (menyimpan 312 karakter). Sementara di sini, saya bermain golf 17 karakter lagi.
kernigh