创建旋转的奎因


26

通过将字符串分成两部分并颠倒其顺序来进行字符串"world! Hello,"的旋转,例如的旋转"Hello, world!"。可以创建可以旋转以形成其他但仍然有效的程序的程序。考虑一下python中的这个示例:

print ")import sys; sys.stdout.write("

可以旋转形成

import sys; sys.stdout.write("print ")

这本身就是有效的python程序。

您面临的挑战是编写一个输出自身旋转的程序,该程序在运行时将输出原始程序。奖励指向周期长度大于2的任何条目!

这是代码高尔夫,准确的得分将是:(代码长度)/(循环长度-1)。

编辑:我们有一个赢家(除非其他人能打出4分)!我仍然非常有兴趣看到其他解决方案,无论它们是否在竞争。


2
真好!您已将(周期长度为1)的权重排除在廉价级联之外。

3
尝试在Befunge中进行原旋转。
机械蜗牛

使用鸡肉和鸡蛋也是这方面的一个好方法。
meawoppl 2014年

Answers:


21

APL(158个字符,得分= 4)

'''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 

我在这里使用Dyalog APL。通过将表达式的末尾和字符串的末尾(之前''')相加(0后跟一个空格),可以将循环数增加一。循环长度为(# 0's) + 1,表达式的长度为150 + 4*(cycle length))。假设我们永远永远添加零,则分数为Limit[(150 + 4*n)/(n - 1), n -> Infinity] = 4,其中n为周期长度。

这是一个循环长度为6的示例:

      '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 
 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0

      0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0
 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0

      0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0
 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0

      0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0
 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0

      0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0
 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1

      0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1
'''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 0 0 0 0

192个字符,得分= 2

'''{2≠⍴⍺:¯3⌽(2×1+⍴⍺)⍴(1+⍴⍺)⍴⍺ ⋄ a←⊃2⌷⍺ ⋄ ⍵=0:¯2⌽(2×1+⍴a)⍴(1+⍴a)⍴a⋄(-4+⌊10⍟⊃⍺)⌽(2×1+⍴a)⍴(1+⍴a)⍴a}01'''{2≠⍴⍺:¯3⌽(2×1+⍴⍺)⍴(1+⍴⍺)⍴⍺⋄a←⊃2⌷⍺⋄⍵=0:¯2⌽(2×1+⍴a)⍴(1+⍴a)⍴a⋄(-4+⌊10⍟⊃⍺)⌽(2×1+⍴a)⍴(1+⍴a)⍴a}01

根据实现的不同,一个失败点可能是字符串前缀的整数太大。但是,从理论上讲,我们可以通过添加两个字符来添加一个循环- 1在字符串的末尾(在之前''')和1在整行的末尾添加一个字符。

200个字符,得分= 1

'''{a←{2=⍴⍵:⊃2⌷⍵⋄⍵}⍺⋄(⍺{⍵=9:⍬⋄⍕1+{2=⍴⍵:10×⊃⍵⋄0}⍺}⍵),(¯2⌽(2×1+⍴a)⍴(1+⍴a)⍴a),⍺{⍵=9:(⍕9),⍕⊃⍺⋄⍕⌊⍵÷10}⍵}'''{a←{2=⍴⍵:⊃2⌷⍵⋄⍵}⍺⋄(⍺{⍵=9:⍬⋄⍕1+{2=⍴⍵:10×⊃⍵⋄0}⍺}⍵),(¯2⌽(2×1+⍴a)⍴(1+⍴a)⍴a),⍺{⍵=9:(⍕9),⍕⊃⍺⋄⍕⌊⍵÷10}⍵}91

我的APL实现默认情况下没有无限精度的整数,因此当整数太大时,该整数将转换为浮点数,从而导致输出错误。因此,这是最挑剔的,但是从理论上讲(无论是手工操作还是使用其他APL解释器),它的得分都应该为1。只需1在表达式的末尾添加a ,就可以得到另一个循环。

概述(带有较短的奎因)

我将概述第一个版本,因为我认为这可能是最容易理解的版本。但是,在处理该版本之前,我们将考虑APL中的一个简单方法:

1⌽22⍴11⍴'''1⌽22⍴11⍴'''

我发现理解某些APL表达式的最好方法之一是查看整个运算符/函数级联的输出。APL中的所有运算符和函数都是右关联的,并且具有相同的优先级,因此从右到左是这样的:

  • '''1⌽22⍴11⍴''':这只是一个字符串文字(字符列表)。''是APL转义单引号的方式。输出:'1⌽22⍴11⍴'
  • 11⍴'''1⌽22⍴11⍴''':这里,我们将()整形为length的字符串11。由于字符串的长度小于11,因此5⍴'abc'将对其进行重复(即会产生'abcab')。输出:'1⌽22⍴11⍴''。因此,我们现在在末尾有两个引号-我们到了!
  • 22⍴11⍴'''1⌽22⍴11⍴''':同样,我们现在将之前的输出重塑为length 22。输出:'1⌽22⍴11⍴'''1⌽22⍴11⍴''。我们快到了-我们只需要将第一个单引号移到末尾。
  • 1⌽22⍴11⍴'''1⌽22⍴11⍴''':在这里,我们将字符列表旋转()1。这会将字符串的第一个字符移到末尾。再举一个例子,2⌽'abcdef'return 'cdefab'。输出:1⌽22⍴11⍴'''1⌽22⍴11⍴'''

旋转奎

那个短的奎因是我们旋转奎因的主要基础。现在,考虑到这一点,让我们看一下我们的方法:

'''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 

{ ... }定义一个未命名的函数,我们将在该函数中进行工作。请注意,APL中的函数带有一个右参数(由表示)和一个可选的左参数(由(think infix)表示)。我们想同时向我们的Quine字符串和一些东西提供这个功能,以帮助我们创建任意数量的循环。为了使自己(以及任何想要添加循环的人)更轻松,我们将quine字符串作为左参数。因此,正确的参数是放置循环列表的位置。由空格分隔的2个或更多项目创建一个列表,因此在此示例中,我们有2个元素的列表,其中包含a 1和a 0

我们可以看到该函数看起来与以前的方法相似。我们以前有相同的...⌽...⍴...⍴...表格。很好-我们至少了解得这么多!让我们更深入地研究椭圆,从最后一个开始⊃,/(~^/¨⍺=0)/⍺

  • 如您在上面的示例中看到的那样,我们在字符串的右边添加0前缀,并在每次迭代时添加一个;但是我们现在不在乎那些。我们只想要字符串!
  • 首先,请考虑括号中的内容。(顺便说一下,他们像大多数其他语言一样分组。)
    • ⍺=0返回一个列表,在这种情况下,列表的形状与相同,如果其中的每个元素均等于,则将其中的每个元素替换100否则为。这是递归执行的;因此,如果我们有一个字符列表的列表,则将对各个字符进行0测试,您将获得一个二进制值列表的列表。
    • 因此,如果仅由我们的字符串组成,我们将返回一个0列表。否则,我们的left参数的前缀为0(例如0 0 0 'quinestring'),因此它是一个由0和另一个列表(我们的字符串)组成的列表。然后我们的输出看起来像1 1 1 <sub-list of zeros>
    • ^/¨⍺=0:我们将派生函数应用到的每个()元素^/,该函数/使用逻辑AND(^)函数来减少()。这是为了平整零的子列表,以便我们可以将Quine字符串视为一个二进制值。考虑前面的示例,输出为。¨⍺=01 1 1 0
    • ~:我们不对之前的每个值进行二进制处理(例如,返回0 0 0 1)。
  • (~^/¨⍺=0)/⍺:对于中的每个元素,我们将其复制(/)由左参数中相应元素给出的次数。这样就消除了所有的0,只剩下我们的quine字符串。
  • ⊃,/是一些必要的文书工作,可通过使用串联函数(,)减少结果来确保获得平坦的字符列表。如果输入已经是一个扁平化的列表(即,主函数的左参数仅是字符串),我们将得到一个包含该列表的1元素列表。在另一种情况下,当我们有一个由字符串的子列表组成的列表时,我们又得到了相同的东西(一个带有子列表的列表)。然后,我们解压缩此(),只给我们列表的第一个元素(即字符的子列表)。这似乎没有必要,但是否则我们将尝试重塑1元素列表!

接下来,我们在括号内查看为第一次重塑给出的长度:

  • ⍺,⍵:我们将正确的参数连接到第一个参数
  • ⊃,/⍺,⍵:与以前相同-整理列表。
  • +/0=⊃,/⍺,⍵/使用加法(+)函数通过减少()来累加列表中的零个数。
  • 2×+/0=⊃,/⍺,⍵:将该数字乘以2。
  • z←2×+/0=⊃,/⍺,⍵:将()结果分配给变量z。回顾一下,z现在是在左右参数中找到的零的数量的两倍。
  • 77+z←2×+/0=⊃,/⍺,⍵:然后77,对于quine字符串中的字符,我们添加,忽略后面的空格1。像最初的quine示例一样,我们在字符串的长度上加1以得到另一个单引号。
  • 在此示例中,此重塑的输出为: '{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 ''

紧随其后的重塑的论点很简单,它反映了短提包(2倍于第一次重塑的长度)。现在我们的输出是:

'{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 '''{(((3+z)×^/⍵)-5+2×+/+/¨⍺=0)⌽(2×77+z)⍴(77+z←2×+/0=⊃,/⍺,⍵)⍴⊃,/(~^/¨⍺=0)/⍺}1 0 ''

现在进行最后一步,在这里我们计算旋转输出字符串的程度:

  • 正如您通过查看先前的输出所看到的,我们希望将其旋转回去(负数),以将2个最终报价引到开头。因为我们也希望一个0(和另一个空格)移动到开头,所以我们想将它再旋转3个字符。
  • +/+/¨⍺=0:在参数中加零的数量。第一个(从右侧开始)对+/¨每个元素的计数(即,子列表或仅是整数)+/求和,第二个给我们该结果列表的总和。
  • 5+2×+/+/¨⍺=0:乘以2(也可以旋转空格),然后加5(我们之前得出的结果)。
  • 现在,我们从左边的参数中减去前一个值,-以处理循环结束时的情况:
    • (3+z)×^/⍵:和正确参数中的所有元素一起看我们是否到达了end(1),然后乘以3+z

我们完成了!


哇,太酷了,当我写下原始问题时,没想到会有这样的事情!我一点也不讲APL,您是否有机会概述一下它的工作原理?
Gordon Bailey 2012年

当然!我还有更多版本要发布(理论上分数较低),因此明天的某个时候我将对其进行概述。
Dillon Cower 2012年

非常感谢您提供的非常详尽的文档,此处使用了一些巧妙的技巧。我特别喜欢使用operator(?)。我认为在完全消化之前,我必须再通读几遍!
戈登·贝利2012年

13

GolfScript,10046/9999≈1.0047(渐近得分1)

好的,我将尝试以此击败DC的APL条目

{\''+.,{(;\'.~1'}{'1'9999*@'.~']puts:puts}if}.~

上面的代码不是实际的代码—我觉得发布10kB单线并不是一个好主意。而是,运行上面的代码一次将生成实际的10046个字符的GolfScript程序,该程序按问题中的指定进行迭代时,将自身生成9999旋转,并最终生成自身的旋转。

可以通过更改常数来调整循环(和程序)的长度9999。为了简便起见,我将展示将常量简化为9以下形式的迭代输出的外观:

111111111{\''+.,{(;\'.~1'}{'1'9*@'.~']puts:puts}if}.~
11111111{\''+.,{(;\'.~1'}{'1'9*@'.~']puts:puts}if}.~1
1111111{\''+.,{(;\'.~1'}{'1'9*@'.~']puts:puts}if}.~11
111111{\''+.,{(;\'.~1'}{'1'9*@'.~']puts:puts}if}.~111
11111{\''+.,{(;\'.~1'}{'1'9*@'.~']puts:puts}if}.~1111
1111{\''+.,{(;\'.~1'}{'1'9*@'.~']puts:puts}if}.~11111
111{\''+.,{(;\'.~1'}{'1'9*@'.~']puts:puts}if}.~111111
11{\''+.,{(;\'.~1'}{'1'9*@'.~']puts:puts}if}.~1111111
1{\''+.,{(;\'.~1'}{'1'9*@'.~']puts:puts}if}.~11111111
{\''+.,{(;\'.~1'}{'1'9*@'.~']puts:puts}if}.~111111111
111111111{\''+.,{(;\'.~1'}{'1'9*@'.~']puts:puts}if}.~
11111111{\''+.,{(;\'.~1'}{'1'9*@'.~']puts:puts}if}.~1
1111111{\''+.,{(;\'.~1'}{'1'9*@'.~']puts:puts}if}.~11
111111{\''+.,{(;\'.~1'}{'1'9*@'.~']puts:puts}if}.~111
etc.

随着常数9999的增加,程序长度和循环长度的比率(减一)趋向于一。我很确定,这个解决方案不会被打败,至少不是渐近的。;-)

它是如何工作的?

GolfScript是一种非常容易写的quines语言,因为基本上任何数字文字都可以充当quine:例如,GolfScript程序12345输出(您猜对了)12345。同样,串联多个奎纳通常会产生一个奎尼。因此,我可以使用一个简单的数字,如11111...111我的循环奎因的重复部分。

但是,要使奎纳真正循环,我们需要携带并执行不平凡的“有效载荷”。我能想到的最简单的GolfScript奎因可以做到这一点:

{PAYLOAD'.~'}.~

因此,我的计划是使用重复的数字常量为类似这样的Quine加上前缀,并使用有效载荷将数字减去一位并将其移至程序末尾。如果程序检测到存在在其前面没有数值常量(在这种情况下在堆栈上在它下面的值将是一个空字符串,假设有没有输入),它将代替在前面前面加上一个固定长度的数字常数本身。

但是,还有一个额外的折痕-当“环绕”时,有效载荷还必须抑制其自身之后的数字输出。通常,当GolfScript程序结束时,堆栈上的所有值都会自动打印出来,这在这里是一个问题。

但是,有一种避免这种情况的(AFAIK)未记录方式:解释器实际上调用预定义函数puts进行打印,因此将该函数重新定义为no-op会抑制自动输出。当然,这也意味着我们必须首先调用puts自身以打印打印的堆栈部分。

最终代码看起来很凌乱(即使对于GolfScript也是如此),但至少它可以工作。我怀疑可能还没有想到一些聪明的方法可以从有效负载上减少一些字符,但是对于这个版本,我主要只是关注渐近得分。


似乎没有时对我有用puts{}:puts,尽管我可以看到有一个争论,{print}:puts理由是输出中的换行符表示它严格意义上不是循环的。
彼得·泰勒

@Peter:]puts{}:puts需要从{STUFF}.~111111111到的换行111111111{STUFF}.~,否则1程序末尾的s 数量会不断增加。(不过,这{}似乎是不必要的;显然,GolfScript解释器允许从空堆栈中进行赋值。)
Ilmari Karonen12年

非常好,尽管看起来DC还发布了一个渐近得分为1的解决方案,所以我们可能会平分秋色。
戈登·贝利2012年

-3

HTML,负无穷大(几乎)

-2

AA

-10

AAAAAAAAAA

依此类推...如果有人说它在作弊,我们可以争论一下,但是我发现了一个问题:)

因此,我想每个人都知道代码可以做到,它没有循环,所以最长的循环是0,考虑程序长度为n,score为n / (0 - 1)or -n,我可以编写具有n大正整数的程序,但是它没有用,因为每个人都可以理解。


7
抱歉,您的周期长度是1,而不是0。所以您的得分是n / 0,这既不是负数也不是小数值。
Paul Thomann 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.