Perl, 1428 1099
Điều này có 1193 ký tự ASCII (bao gồm 960 chữ số nhị phân được hoán vị). 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
Thiết kế đầu tiên của tôi
Trước khi tôi nhận được đề nghị từ Dennis để chuyển sang nhị phân, chương trình của tôi đã hoán vị các chữ số bát phân.
Thiết kế đầu tiên của tôi mã hóa mỗi chuỗi bằng 160 chữ số bát phân, với 2 chữ số cho mỗi ký tự. Mã hóa này có 100 8 = 64 ký tự khác nhau. Hệ thống bát phân có 8 chữ số khác nhau. Chương trình phải có 160 bản sao của mỗi chữ số, vì vậy nó cho phép 8 × 160 = 1280 chữ số.
Tôi giữ 160 chữ số $s
và 1120 chữ số khác $t
. Tôi bắt đầu với một chương trình không phải là một quine, mà chỉ in các bài tập đến $s
và $t
cho lần chạy tiếp theo. Đây là nó:
$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))
là một sự gán cho một danh sách trống của các biến. Tôi thực hiện thủ thuật này từ hướng dẫn ngữ cảnh tại PerlMonks . Nó buộc liệt kê bối cảnh trên toán tử khớp =~
. Trong bối cảnh vô hướng, trận đấu sẽ đúng hoặc sai và tôi sẽ cần một vòng lặp $i++ while ($s =~ /$_/g)
để đếm các trận đấu. Trong bối cảnh danh sách, $s =~ /$_/g
là một danh sách các trận đấu. Tôi đặt danh sách này trong ngữ cảnh vô hướng của phép trừ, vì vậy Perl đếm các phần tử danh sách.
Để tạo ra một quine, tôi lấy mẫu $_=q{print"\$_=q{$_};eval"};eval
từ các quines Perl tại Rosetta Code . Điều này một chuyển nhượng một chuỗi q{...}
đến $_
và sau đó gọi eval
, vì vậy tôi có thể có mã của tôi trong một chuỗi và cũng chạy nó. Chương trình của tôi sẽ trở thành một Quine khi tôi quấn thứ ba của tôi để dòng cuối cùng trong $_=q{
và };eval
và thay đổi của tôi cuối cùng print
để print "\$s = '$s';\n\$t = '$t';\n\$_=q{$_};eval"
.
Cuối cùng, tôi đánh golf chương trình của mình bằng cách thay đổi nhiệm vụ đầu tiên $t
thành nhận xét và bằng cách xóa các ký tự phụ.
Điều này có 1522 ký tự ASCII (bao gồm 1280 chữ số bát phân được hoán vị).
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
Việc chuyển sang nhị phân
Trong các bình luận, Dennis nhận thấy rằng 960 chữ số nhị phân được hoán vị sẽ nhỏ hơn 1280 chữ số bát phân. Vì vậy, tôi đã vẽ đồ thị số chữ số hoán vị cho mỗi cơ sở từ 2 đến 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)
Mặc dù cơ sở 8 là mức tối thiểu cục bộ, cơ sở 2 và 3 và 4 cho cơ sở tốt nhất, ở mức 960 chữ số được hoán vị. Đối với mã golf, cơ sở 2 là tốt nhất vì Perl có chuyển đổi cho cơ sở 2.
Thay thế 1280 chữ số bát phân bằng 960 chữ số nhị phân tiết kiệm 320 ký tự.
Chuyển đổi mã từ bát phân sang nhị phân có giá 8 ký tự:
- Thay đổi
oct
thành oct'0b'.$_
chi phí 7.
- Thay đổi
/../g
thành /.{6}/g
chi phí 2.
- Thay đổi
"%02o"
thành "% 06b" `chi phí 0.
- Thay đổi
160
thành 480
chi phí 0.
- Thay đổi
0..7
để 0,1
tiết kiệm 1.
Tôi đã học được một số mẹo chơi gôn Perl . Họ lưu 14 ký tự:
- Thay đổi
'A'..'Z','a'..'z','0'..'9'
thành A..Z,a..z,0..9
, sử dụng barewords và số trần, lưu 12 ký tự.
- Thay đổi
"\n"
để $/
lưu 2 ký tự.
Tôi lưu 3 ký tự bằng cách di chuyển #$t
bình luận đến cuối tập tin. Điều này loại bỏ dòng mới kết thúc bình luận, và một nghĩa đen \n
trong quine.
Những thay đổi này lưu tổng cộng 329 ký tự và giảm điểm của tôi từ 1428 xuống còn 1099.