Perl,1428 1099
它具有1193个ASCII字符(包括960个置换的二进制数字)。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
我的第一个设计
在我接受Dennis的建议以切换到二进制之前,我的程序将八进制数字进行了排列。
我的第一个设计将每个字符串编码为160个八进制数字,每个字符2个数字。此编码具有100 8 = 64个不同的字符。八进制系统有8个不同的数字。该程序的每个数字必须具有160个副本,因此它排列为8×160 = 1280个数字。
我保留160位数字,$s
其余1120位数字$t
。我先从一个程序,是不是奎因,但只打印作业,以$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的上下文教程中学到了这个技巧。它强制匹配操作符上的列表上下文=~
。在标量上下文中,匹配项是对还是错,我需要一个循环$i++ while ($s =~ /$_/g)
来计算匹配项。在列表上下文中,$s =~ /$_/g
是匹配项列表。我将此列表放在减法的标量上下文中,因此Perl计算列表元素。
要制作一个奎纳,我采用Rosetta Code$_=q{print"\$_=q{$_};eval"};eval
的Perl奎纳的形式。这一个分配一个字符串q{...}
来$_
,然后调用eval
,所以我可以有我的字符串编码,并运行它。我的计划成为当我换我倒数第三行的奎因$_=q{
和};eval
,并改变我最后print
来print "\$s = '$s';\n\$t = '$t';\n\$_=q{$_};eval"
。
最后,通过将第一个作业更改$t
为注释,并删除多余的字符,我对程序进行了调整。
它具有1522个ASCII字符(包括1280个排列的八进制数字)。
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
切换到二进制
在评论中,Dennis注意到960个置换的二进制数字将少于1280个八进制数字。因此,我绘制了每个基数从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)
尽管以8为底数是局部最小值,但以2、3和4为基数的最佳底数是960排列数字。对于标准高尔夫,基数2最好,因为Perl的基数为2。
用960个二进制数字替换1280个八进制数字可节省320个字符。
将代码从八进制切换到二进制需要8个字符:
- 更改
oct
到oct'0b'.$_
成本7。
- 更改
/../g
到/.{6}/g
成本2。
- 更改
"%02o"
为“%06b”`的费用为0。
- 更改
160
为480
费用0。
- 更改
0..7
为0,1
保存1。
我学到了一些Perl高尔夫技巧。他们保存14个字符:
- 更改
'A'..'Z','a'..'z','0'..'9'
为A..Z,a..z,0..9
,使用裸词和裸数字保存12个字符。
- 更改
"\n"
为$/
保存2个字符。
我通过将#$t
注释移到文件末尾来保存3个字符。这将删除以注释结尾的换行符和文本\n
框中的文字。
这些更改总共节省了329个字符,并将我的分数从1428降低到1099。