自行排列以编码字符串的程序(五变量)


16

编写一个打印以下80个字符的行的程序:

来自codegolf.stackexchange.com的该程序本身可以对字符串进行编码。

然后接受一行输入,然后打印其源代码以及可能重新排序的代码点(未添加,也未删除)。执行该代码时,除了打印的行将是最新的输入行之外,其他操作也必须发生。

Perl样式的正则表达式^[A-Za-z0-9. ]{80}$将匹配任何输入行。您不能做任何其他假设。

提交的分数是其源代码中的代码点数减去94。越低越好。

该代码不得执行任何无法接受的操作(例如,读取文件)。特别是,任何分数为负的提交都必须以某种方式作弊,例如93!小于64 80

2014年4月21日添加:程序的整个源代码必须采用计数点数的字符编码格式。例如,不能在UTF-8尾随字节范围(80..BF)中使用80个连续字节,并且不能将每个字节计为一个U + FFFD REPLACEMENT CHARACTER(或更糟糕的是,根本不是一个代码点)。

此外,如果编码允许以多种方式对代码点(例如 SCSU)进行编码,则您的程序以及直接或间接生成的所有程序都必须仅使用其中一种(或者至少在整个代码中必须等同地对待所有程序) )。


重新阅读您的问题后,我不确定我的答案是否确实符合您的想法。将新字符串管道传递到程序是否正常,还是必须启动交互式提示?
丹尼斯2014年

@丹尼斯:这不是为什么你的答案不可接受的原因。而是打印“来自...的程序” 之前读取输入。
2014年

那就是我的意思,我只是表达不好。在开始执行脚本之前,GolfScript解释器会读取通过管道传递给它的所有内容。避免这种情况的唯一方法是启动提示,这使得无法进行管道传输。
丹尼斯

嗨,我正在JavaScript中尝试此操作。在不阅读<script>标记之间的文本的情况下似乎不可能制作出奎因吗?置换源代码的目的是什么?您说“可能重新排序”;这是否意味着仅在必要时进行置换?
bacchusbeale,2014年

Answers:


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 < 94回到6。

假设我们有代码块“ E”和“ D”,它们如上所述对字符串进行编码和解码。

现在,我们需要对那些符合问题要求的代码块进行包装:

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

这将执行以下操作:

  • {…}.~定义一个块,将其复制并执行第二个副本。第一个副本将保留在堆栈中。

  • \.$ 将编码的字符串与该块交换,并创建编码后的字符串和带排序字符的副本。

  • [{}/]:&; 从上面将字符串转换为数组,将其保存在“&”中并丢弃。

  • D puts 解码编码的字符串并打印结果。

  • '"#{`head -1`}"'~通过head -1在Shell中执行读取一行输入。

  • 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@.$[{}/]:&\以保存两个字符。

  • 定义{;65base}:b保存一个字符的功能。

  • 删除所有空格,除了结尾的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个置换的二进制数字)。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"};evalPerl奎纳的形式。这一个分配一个字符串q{...}$_,然后调用eval,所以我可以有我的字符串编码,并运行它。我的计划成为当我换我倒数第三行的奎因$_=q{};eval,并改变我最后printprint "\$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) 

基于x轴的图形,在y轴上的排列位数

尽管以8为底数是局部最小值,但以2、3和4为基数的最佳底数是960排列数字。对于标准高尔夫,基数2最好,因为Perl的基数为2。

用960个二进制数字替换1280个八进制数字可节省320个字符。

将代码从八进制切换到二进制需要8个字符:

  • 更改octoct'0b'.$_成本7。
  • 更改/../g/.{6}/g成本2。
  • 更改"%02o"为“%06b”`的费用为0。
  • 更改160480费用0。
  • 更改0..70,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。


1
使用二进制而不是八进制数字将仅需要960个可置换字符。
丹尼斯

@丹尼斯感谢您的提示!我切换到二进制文件(节省312个字符)。在这里,我打了另外17个角色。
kernigh 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.