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 $s
dan 1.120 digit lainnya masuk $t
. Saya mulai dengan program yang bukan quine, tetapi hanya mencetak tugas untuk $s
dan $t
untuk 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 =~ /$_/g
adalah 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"};eval
dari 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 print
ke print "\$s = '$s';\n\$t = '$t';\n\$_=q{$_};eval"
.
Akhirnya, saya mengubah program saya dengan mengubah tugas pertama $t
menjadi 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)
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
oct
ke oct'0b'.$_
biaya 7.
- Ubah
/../g
ke /.{6}/g
biaya 2.
- Ubah
"%02o"
ke "% 06b" `biaya 0.
- Ubah
160
ke 480
biaya 0.
- Ubah
0..7
untuk 0,1
menyimpan 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 #$t
komentar ke akhir file. Ini menghapus baris baru yang mengakhiri komentar, dan literal \n
di quine.
Perubahan ini menyimpan total 329 karakter, dan mengurangi skor saya dari 1428 menjadi 1099.