防辐射奎因


39

正如您应该(希望)知道的那样,防辐射的奎因是一种奎因,您可以从其中删除任何一个字符,但仍打印其原始的,预先修改的源。事实是,使用其中大多数,您只能删除一个字符。否则一切都会崩溃。这就是它的来历;您的目标是构建一个可以进行尽可能多的字符去除的防辐射的奎因。符合规则的任何语言都可以。

规则

  • 该程序必须至少一个字符长
  • 使用的语言必须是完整的(因此HQ9 +等语言不符合条件)
  • 适用于普通拉皮的所有其他规则也适用于此。
  • 用最少的溶液program_length^(2/n),其中的任何一组的准确n的字符,同时仍打印原始源代码胜被移除。

1
我正在尝试提出一个解决方案Subleq。我认为这对这种挑战将是理想的!


鉴于此名称与防辐射的藜麦不同,也许可以更改名称?也许,“辐射证明奎因”?
Cyoce

@Cyoce我唯一可以说的区别是,这项挑战是针对任意数量的去除,而大多数(如果不是全部)其他经过辐射硬化处理的奎因只能去除一个。
塔克拉

Ruby解决方案来自著名的“ mame”。github.com/mame/radiation-hardened-quine
mbomb007'2013/

Answers:


57

Perl 1116 1124个字节,n = 3,得分= 1124 ^(2/3)或大约108.1

更新:我现在已经验证了通过蛮力可以在n = 3下工作(花了几天);使用如此复杂的程序,很难手动检查抗辐射性(我在以前的版本中犯了一个错误,这就是字节数增加的原因)。结束更新

我建议将stderr重定向到您看不到的地方。即使您没有从程序中删除字符,该程序也会产生大量有关可疑语法的警告。

程序可能会缩短。进行这项工作相当痛苦,很容易错过可能的微观优化。我的主要目标是尽可能多地删除可删除的字符(因为这是程序中真正具有挑战性的部分),并且将抢七游戏视为目标明确但我不愿意提出的东西进行优化的荒谬工作(基于很容易意外破坏抗辐射性)。

该程序

注意:_四个出现的每一个之前都有一个立即数控制字符(ASCII 31)-+。我认为它没有正确地复制并粘贴到StackOverflow上,因此您必须在运行程序之前重新添加它。

eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;

说明

显然,该程序是由四个相同的较小程序串联在一起组成的。基本思想是,程序的每个副本都将验证其是否损坏得太严重而无法运行;如果已经存在,它将什么都不做(除了可能喷出警告),然后运行下一个副本;如果尚未删除(即没有删除,或者删除的字符对程序的操作没有影响),它将执行其琐碎的事情(打印出完整程序的源代码;这是正确的做法, (每个部分都包含整个源代码的编码),然后退出(防止其他任何未损坏的副本再次打印源代码,从而避免由于打印太多文本而破坏了键盘)。

每个部分依次由两部分组成,这两部分在功能上实际上是独立的。一个外部包装和一些内部代码。因此,我们可以将它们分开考虑。

外包装纸

基本上,外部包装是eval<+eval<+eval< ... >####>####...>###(加上一堆分号和换行符,其目的应该很明显;这是为了确保程序的各部分将保持分离,而不管是否删除了某些分号或换行符。 )。这看似相当简单,但是在许多方面都很微妙,这也是我选择Perl应对这一挑战的原因。

首先,让我们看一下包装程序在程序的未损坏副本中的功能。eval解析为一个内置函数,该函数带有一个参数。因为会发生争执,所以+这里是一元论+(现在,Perl高尔夫球手将非常熟悉;他们经常出人意料地有用)。我们仍然期望有一个参数(我们刚刚看到一个一元运算符),因此<接下来出现的解释为该<>运算符的开始(它不带前缀或后缀参数,因此可以在操作数位置使用)。

<>是一个很奇怪的运算符。它的通常用途是读取文件句柄,然后将文件句柄名称放在尖括号内。或者,如果该表达式作为文件句柄名称无效,它会进行遍历(基本上,UNIX Shell使用相同的过程将用户输入的文本转换为一系列命令行参数;实际上使用了许多旧版本的Perl外壳程序,但如今Perl在内部处理glob)。因此,预期的用途<*.c>与相似,通常会返回类似的列表("foo.c", "bar.c")。在标量上下文中(例如eval),它只会返回第一次运行时找到的第一个条目(相当于第一个参数),并且会在假设的未来运行中返回从未发生的其他条目。

现在,shell通常会处理命令行参数。如果您提供不-r带任何参数的类似内容,它将被原样传递给程序,而不管是否存在具有该名称的文件。Perl的行为方式相同,因此只要确保在<和匹配之间没有shell或Perl专用的字符>,我们就可以像字符串文字的真正尴尬形式一样有效地使用它。更好的是,Perl的类似报价操作符的解析器有一种强迫性的倾向,即使在像这样没有意义的情况下也要匹配括号,因此我们可以<>安全地嵌套(这是实现该程序所需的发现)。所有这些嵌套的主要缺点<>是逃避了<>几乎是不可能的;每一个似乎都有两层不可<>转义的内容,因此要在这三层中都避开某些东西,必须在其前面加上63个反斜杠。我决定,尽管代码大小只是此问题的第二要考虑因素,但几乎肯定不值得为此付出代价,因此,我只决定编写程序的其余部分而不使用令人讨厌的字符。

那么,如果包装器的某些部分被删除会怎样?

  • 单词中的删除eval会使其变成无,即无意义的字符串。Perl不喜欢这些,但会像对待引号一样对待它们。因此eal<+eval<+...被解释为"eal" < +eval<+...。这对程序的操作没有影响,因为它基本上只是从高度嵌套的evals中获取结果(无论如何我们都不会使用),将其转换为整数,然后对其进行一些无意义的比较。(这种情况会引起很多警告垃圾邮件,因为在正常情况下,这样做显然是没有用的;我们只是使用它来吸收删除内容。)这会更改所需的闭合尖括号的数量(因为打开尖括号)现在被解释为比较运算符),但末尾的注释链可确保字符串无论嵌套多少次都可以安全结束。(这里有#比完全需要的更多的符号;我写它的目的是使程序更具可压缩性,使我可以使用更少的数据来存储该信息。)
  • 如果a <被删除,则代码现在解析为eval(eval<...>)。外部的次要对象eval没有任何作用,因为我们正在评估的程序不会返回任何具有任何实际效果的程序(如果它们完全正常返回,则通常为空字符串或裸字;更常见的是,它们通过异常,导致eval返回空字符串,或用于exit避免返回)。
  • 如果将a +删除,则如果相邻代码完整无缺,则不会立即生效;一元+对程序没有影响。(原始+s存在的原因是为了帮助修复损坏;它们增加了<被解释为一元<>而不是关系运算符的情况的数量,这意味着您需要进行更多删除才能生成无效程序。)

包装程序可能会被足够多的删除损坏,但是您需要进行一系列删除才能生成无法解析的内容。使用四个删除,您可以执行以下操作:

eal<evl<eval+<...

在Perl中,关系运算符<是非关联的,因此会出现语法错误(与相同1<2<3)。这样,编写的程序的上限为n = 3。添加更多一元+s似乎是增加它的一种有前途的方法,但是那样一来,包装器的内部也可能会损坏,因此验证该程序的新版本可能非常困难。

包装程序如此重要的原因是,eval在Perl中捕获了异常,例如(例如)您在尝试编译语法错误时获得的异常。因为这eval是字符串文字,所以字符串的编译会在运行时发生,如果文字无法编译,则会捕获所产生的异常。这将导致eval返回一个空字符串并设置错误指示符$@,但我们从不进行任何检查(除非偶尔在程序的一些突变版本中执行返回的空字符串)。至关重要的是,这意味着如果里面的代码应该发生什么包装器,导致语法错误,然后包装器将仅使代码不执行任何操作(并且程序将继续执行以尝试查找自身的未损坏副本)。因此,内部代码不必像包装程序那样具有防辐射性。我们所关心的就是,如果损坏,它的作用将与程序的未损坏版本相同,否则它将崩溃(允许eval捕获异常并继续)或正常退出而不打印任何内容。

包装纸内

包装器中的代码基本上是这样的(再次,有一个Control- _Stack Exchange不会在之前显示-+):

eval+(q(...)=~y=A-Z=-+;-AZz-~=r)

这段代码完全用安全字符编写,其目的是添加新的标点符号字母表,从而可以通过音译和评估字符串文字来编写真实的程序(我们不能使用'"作为引号标记,但是q(…… )也是在Perl中形成字符串的有效方法)。(无法打印字符的原因是,我们需要在程序中将某些字符音译为空格字符而没有文字空格字符;因此我们形成一个以ASCII 31开头的范围,并将空格作为范围的第二个元素。)显然,如果我们通过音译产生一些字符,我们必须牺牲字符以将它们音译中,但是大写字母不是很有用,与没有标点符号的访问相比,不使用大写字母的书写要容易得多。

这是由于glob导致的标点符号字母(上一行显示编码,下一行显示其编码的字符):

BCDEFGHIJKLMNOPQRSTUVWXYZ
 !“ ##%&'()* +; <=>?@ AZz {|}〜 

最值得注意的是,我们有一些标点符号,这些标点符号不是全球安全的,但可用于编写Perl程序以及空格字符。我还保存了两个大写字母,即文字AZ(不编码为自身,而是编码为TU,因为A需要作为上下限的端点);这使我们可以使用新的编码字符集来编写音译指令本身(尽管大写字母没什么用,但在指定对大写字母的更改时很有用)。我们没有的最著名的字符是[\],但是不需要(当我在输出中需要换行时,我使用来自say而不需要写\n; chr 10也会有用,但更详细)。

像往常一样,我们需要担心如果包装器内部在字符串文字之外损坏,会发生什么情况。损坏eval将阻止任何运行;我们很好。如果引号损坏,则字符串的内部不是有效的Perl,因此包装程序将捕获它(字符串上的大量减法表示即使您可以使其成为有效的Perl,也不会执行任何操作,因此是可以接受的结果)。如果音译不是语法错误,则损坏音译会破坏所评估的字符串,通常会导致成为语法错误;我不是100%肯定没有这种情况发生,但是我目前正在蛮力地进行确认,如果有的话,应该很容易就可以解决。

编码程序

在字符串文字的内部,反转我使用的编码,并添加空格以使其更具可读性,我们得到了这一点(再次,假设在之前-+编码为的控制下划线A):

$o=q<
  length$o  ==181 || zzzz((()));
  do {
    chop ($t = "eval+<"x4);
    $r = '=-+;-AZz-~=';
    $s = '$o=q<' . $o . '>;eval$o';
    eval '$s=~y' . $r . 'A-Z=';
    say "$t(q($s)=~y=A-Z${r}r)" . "####>"x6;
    say ";" for 1..4
  } for 1..4;
  exit>;
eval $o

习惯了奎因的人会认识到这种一般结构。最关键的部分是在开始时,我们验证$ o没有损坏;如果角色已被删除,它的长度将不匹配181,所以我们跑zzzz((())),如果它是一个,而不是一个语法错误,由于无法比拟的支架,将是一个运行时错误,即使你删除,因为没有任何三个字符,zzzzzzzzz,并且z是一个函数,除了删除(((并引起明显的语法错误外,没有其他方法可以阻止它解析为一个函数。支票本身也不受损害。的||,可能会损坏|,但将导致zzzz((()))呼叫无条件运行; 损坏的变量或常量将导致不匹配,因为您正在比较0180179178为平等的数字某个子集181; 删除其中一个=将导致解析失败,而两个=将不可避免地导致LHS评估为整数0或空字符串,两者均为假。

更新:此检查在程序的早期版本中略有错误,因此我必须对其进行编辑以解决此问题。解码后,以前的版本如下所示:

length$o==179||zzzz((()))

并且可以删除前三个标点符号来获得此功能:

lengtho179||zzz((()))

lengtho179,作为一个裸词,是真实的,因此破坏了检查。我通过添加额外的两个B字符(对空格字符进行编码)来解决此问题,这意味着最新版的quine可以做到这一点:

length$o  ==181||zzzz((()))

现在,不可能=$不产生语法错误的情况下隐藏符号和符号。(我必须添加两个空格而不是一个空格,因为长度为1800在源代码中添加文字字符,在这种情况下可能会滥用该字符以将零与裸字进行整数比较,这会成功。)结束更新

一旦长度检查通过,我们就知道该副本是完好无损的,至少在删除字符方面如此,因此,从那里直接复制就可以了(由于解码表损坏而导致的标点符号替换不会被此检查捕获) ,但我已经通过蛮力进行了验证,解码表中的三个删除都不会破坏该方法;大概是其中的大多数会导致语法错误)。我们$o在已经是可变的,所以我们需要做的是硬编码的外包装纸(有一些小程度的压缩,我没有跳过了问题的第一部分完全)。一种技巧是我们将大部分编码表存储在$r; 我们可以直接打印它以便生成内部包装的编码表部分,也eval可以在它周围连接一些代码,然后以相反的方式运行解码过程(使我们能够弄清楚$ o 的编码版本是什么) ,目前只有解码版本可用)。

最后,如果我们是一个完整的副本,因此可以输出整个原始程序,则我们进行调用exit以防止其他副本也尝试将程序打印出来。

验证脚本

不是很漂亮,但因为有人问而将其发布。我以各种设置运行了几次(通常进行更改$min$max检查感兴趣的各个领域);这不是一个完全自动化的过程。由于其他地方的CPU负载过重,它倾向于停止运行。发生这种情况时,我只是更改$min$x未完全检查的第一个值,然后继续运行脚本(从而确保最终检查范围内的所有程序)。我只检查了程序的第一个副本中的删除,因为很明显其他副本中的删除不能做更多的事情。

use 5.010;
use IPC::Run qw/run/;
undef $/;
my $program = <>;
my $min = 1;
my $max = (length $program) / 4 - 3;
for my $x ($min .. $max) {
    for my $y ($x .. $max) {
        for my $z ($y .. $max) {
            print "$x, $y, $z\n";
            my $p = $program;
            substr $p, $x, 1, "";
            substr $p, $y, 1, "";
            substr $p, $z, 1, "";
            alarm 4;
            run [$^X, '-M5.010'], '<', \$p, '>', \my $out, '2>', \my $err;
            if ($out ne $program) {
                print "Failed deleting at $x, $y, $z\n";
                print "Output: {{{\n$out}}}\n";
                exit;
            }
        }
    }
}

say "All OK!";

3
OP有点模棱两可;但我认为分数将是(1116 * 1116)/ 3。
格雷格·马丁

@GregMartin:(1116 * 1116)/ 3是415152,因此在这种情况下,该条目仍然会获胜。但是,我认为OP并不意味着这样做,因为它几乎没有动力去处理多个字符的删除。如果只需要用它来处理一个字符,则该捆的长度可以小于一半。如果我们这样解释的话,这将使我在得分上获得有效的÷4,这将超过我从n = 3获得的÷3,因此,意味着有趣程度较低的n = 1条目实际上得分更高。

2
我使得分更加清晰。无论如何,这绝对是不可思议的。没想到有人会得到N> 1
takra

1
它说明了Perl的一些观点,即编写不带字母的程序比不加标点符号更容易
罗伯特·弗雷泽

35

Befunge- 98,884,n = 14,得分≈2.636

f00f00f00f00f00f00f00f00f00f00f00f00f00f00f0xxxxxxxxxxxxxxx"""""""""""""""fffffffffffffff'''''''''''''''000000000000000\\\\\\\\\\\\\\\'''''''''''''''000000000000000\\\\\\\\\\\\\\\'''''''''''''''fffffffffffffff\\\\\\\\\\\\\\\111111111111111---------------:::::::::::::::!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!000000000000000aaaaaaaaaaaaaaa---------------bbbbbbbbbbbbbbb---------------***************jjjjjjjjjjjjjjj$$$$$$$$$$$$$$$'''''''''''''''+++++++++++++++kkkkkkkkkkkkkkk,,,,,,,,,,,,,,,333333333333333kkkkkkkkkkkkkkk$$$$$$$$$$$$$$$000000000000000{{{{{{{{{{{{{{{'''''''''''''''888888888888888uuuuuuuuuuuuuuu'''''''''''''''!!!!!!!!!!!!!!!111111111111111+++++++++++++++'''''''''''''''xxxxxxxxxxxxxxx###############;;;;;;;;;;;;;;;:::::::::::::::!!!!!!!!!!!!!!!kkkkkkkkkkkkkkk@@@@@@@@@@@@@@@dddddddddddddddkkkkkkkkkkkkkkk:::::::::::::::eeeeeeeeeeeeeeekkkkkkkkkkkkkkk,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;

在线尝试!

这不仅在删除精确的14个字符时起作用,甚至在删除不超过 14个字符的任何数量时也是如此

n = 14看起来似乎是一个非常随意的选择,但是我使用的技术实际上只能用于1到14的辐射强化命令,但不容易超出此范围(可能,但是我不知道如何做)。order-1 quine仅为73个字节(尽管它采用了一些不适用于Large的高尔夫技巧n):

200 20 xx""''ÈÈ..aa22**..33kk$$00{{''!!uu''!!11++''xx##;;::!!kk@@::,,,,;;

说明

在研究此答案时,我发现可以(2,0)使用以下代码段在辐射硬化条件下将指令指针的增量设置为:

20020xx

请参阅该答案以了解其工作原理。我发现这只是用手一点儿摆弄,但这提出了一个问题,即是否存在去除多个字符后仍很健壮的相似模式。因此,我编写了一个简短的Mathematica脚本,以蛮力搜索这些脚本:

n = 14;
m = 4;
Print @ FromDigits @ {
      m + 1, 0, 
      ## & @@ ((m + 1) IntegerDigits[#, 2, n - 4]),
      m + 1, 0
} & /@ Select[
   Range[0, 2^(n - 4) - 1], 
   AllTrue[
     Subsets[{
         m + 1, 0, 
         ## & @@ ((m + 1) IntegerDigits[#, 2, n - 4]),
         m + 1, 0
       }, 
       {n - m, n - 1}
     ] //. {a___, _, m + 1} | {a___, 0, _} :> {a}, 
     MatchQ@{___, m + 1, 0}
  ] &
];

这很快显示出一种模式。要获取可删除最多n字符的相应代码段,您可以使用(m0x){n}m0where mis n+1and xis m0。因此,以下所有内容都可以删除最多两个字符:

30030030
30030330
30330030
30330330

我敢肯定有可能证明这一点,但我只验证n7。当然,只有在我们可以表示n+1为一个数字的情况下,此方法才有效,并且Befunge 98中最大的数字是f15。这就是为什么我的方法仅限于n = 14。如果有人找到可靠地将delta设置为更大的方法n+1,则可能会无限期增加此经过辐射硬化的奎因的阶数。

让我们看一下实际的代码。基本上有两个部分。首先,(15,0)正如我刚才提到的,将增量设置为:

f00f00f00f00f00f00f00f00f00f00f00f00f00f00f0xxxxxxxxxxxxxxx

其余的代码将每个命令重复15次并打印源。如果我们删除重复,它看起来像这样:

"f'0\'0\'f\1-:!!0a-b-*j$'+k,3k$0{'8u'!1+'x#;:!k@dk:ek,;

"是一种标准的2D quinquin技术:它开始字符串模式,将所有字符(除了自身)压入堆栈,然后在环绕后再次结束字符串模式。这有助于我们获得下半场的所有代码点,但它将无法得到我们任何从上半年有用的,因为在整个f00f00...f0位,它只会记录两个字符(可以是f0取决于哪个字符被删除)。但是由于该部分不是由重复15次的字符组成,所以无论如何我们都需要单独打印它。

更方便的是,在未修饰的quine中,字符串的长度在"is 之前-1 (mod 15)。这保证了无论有多少个字符(最多14个),我们如何删除,该数字记录的人物总是有3(一个x和两个f0)。实际上,对于任何辐射阶数最高为14的情况都是如此。

现在,我们开始打印f00f00...f0零件:

f'0\'0\'f\1-:!!0a-b-*j$'+k,

f          Push 15, a loop counter.
'0\'0\'f\  Put "00f" underneath the loop counter.
1-         Decrement the loop counter.
:!!        Copy it, and turn it into a 1 if it's positive.
0a-b-      Push -21.
*          Multiply by 0 if the loop counter is zero, or by 1 otherwise.
j          Jump that many steps. If the value was 0, this is a no-op and
           the loop ends. Otherwise, this brings us back after the f.
$          Pop the loop counter (which is now 0).
'+k,       Print the top of the stack 43 times, which gives us all of
           the "f00f00...f0" and leaves one "0" on top of the stack.

下一个3k$简单地丢弃该0字符以及"从程序开始时按下的三个字符。现在,堆栈中仅包含字符之后的字符"以及原始f00f00...f0字符下方的垃圾内容,具体取决于要删除的字符。

现在,我们只需要反转堆栈的顶部(包含其余字符),然后将每个字符打印15次。

0{     Start a new, empty stack. This pushes two zeros onto the original stack.
'8u    Move the top 56 values from the original stack to the new one, which
       is the 54 characters after the " as well as those two zeros. This is
       implemented as pop-push loop, so it reverses the order of those elements.
'!1+   Push a " by incrementing a !.
'x     Push an x. Now we've got all the characters that are repeated 15 times.
#;     Enter a loop. This is a standard technique for Befunge-98: the ; is
       a bit like a comment character, that ignores everything until the next
       ;, but we jump over the first one with #, so that from now on only
       the code inside will be executed (over and over).
  :!     Copy the top of the stack, and compute logical NOT (1 if 0, 0 otherwise).
  k@     Terminate the program that many times (i.e. when the top of the
         stack is zero).
  dk:    Make 14 copies of the top of the stack.
  ek,    Print 15 characters from the top of the stack.
;

就是这样。:)


16

JavaScript(ES6),927个字节,n = 1,得分= 859329

注意:请勿使用REPL(如浏览器控制台)来运行它。

这是在代码长度成为一个因素之前编写的,因此尚未打入。

这是非常困难的,值得彻底的解释。我将在探索更多挑战之后稍后再写!

etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;
setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

注意:尾随换行符

基本上,第一行经过精心构造,将所有的“拼写错误”重命名setTimeout为有效函数,因此,如果从setTimeouts中的一个字符中删除了一个字符,该代码将不会出错,并且可以正常运行。还要这样编写,以便如果从第一行中删除了任何一个字符,则不会有错误,并且其余代码可以不受影响地运行。

第二和第三块是完全等效的。如果一个运行完毕,它将设置该_变量,以便另一个知道不重复该quine。如果这些块之一出错,则不会影响另一个块,因为它是使用异步调用的setTimeout。该错误将导致_未设置该错误,因此另一个块将成功进行quine。主代码在一个字符串中,在每个块中检查其长度,以确保没有删除。

如果删除了构成模板字符串的反引号之一,则下一行的模板字符串在模板字符串的末尾带有一些注释,可以防止代码出错。如果删除了结束反引号,则模板字符串以注释中的反引号结束。如果删除了起始反引号,则setTimeout被评估为未分配的函数(无操作),并且代码将正常运行,而没有setTimeout。结束的反引号由另一个注释取消。


你说什么 您想尝试一下吗?别说了!

建议使用整页模式。

忽略输入框,此代码段不输入任何内容。

尝试从代码中删除任何一个字符!

不相信吗?普通代码仍然可以工作(但不会奏效...)试试类似的东西console.log(5)

注意:必须对代码段进行一些修改才能禁用REPL功能,因此我仅针对此答案删除了多个输出功能。

etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;
setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`
<!--                               Try the test suite below!                              --><strong id="bytecount" style="display:inline; font-size:32px; font-family:Helvetica"></strong><strong id="bytediff" style="display:inline; margin-left:10px; font-size:32px; font-family:Helvetica; color:lightgray"></strong><br><br><pre style="margin:0">Code:</pre><textarea id="textbox" style="margin-top:5px; margin-bottom:5px"></textarea><br><pre style="margin:0">Input:</pre><textarea id="inputbox" style="margin-top:5px; margin-bottom:5px"></textarea><br><button id="testbtn">Test!</button><button id="resetbtn">Reset</button><br><p><strong id="origheader" style="font-family:Helvetica; display:none">Original Code Output:</strong><p><div id="origoutput" style="margin-left:15px"></div><p><strong id="newheader" style="font-family:Helvetica; display:none">New Code Output:</strong><p><div id="newoutput" style="margin-left:15px"></div><script type="text/javascript" id="golfsnippet">var bytecount=document.getElementById("bytecount");var bytediff=document.getElementById("bytediff");var textbox=document.getElementById("textbox");var inputbox=document.getElementById("inputbox");var testbtn=document.getElementById("testbtn");var resetbtn=document.getElementById("resetbtn");var origheader=document.getElementById("origheader");var newheader=document.getElementById("newheader");var origoutput=document.getElementById("origoutput");var newoutput=document.getElementById("newoutput");textbox.style.width=inputbox.style.width=window.innerWidth-50+"px";var _originalCode=null;function getOriginalCode(){if(_originalCode!=null)return _originalCode;var allScripts=document.getElementsByTagName("script");for(var i=0;i<allScripts.length;i++){var script=allScripts[i];if(script.id!="golfsnippet"){originalCode=script.textContent.trim();return originalCode}}}function getNewCode(){return textbox.value.trim()}function getInput(){try{var inputText=inputbox.value.trim();var input=eval("["+inputText+"]");return input}catch(e){return null}}function setTextbox(s){textbox.value=s;onTextboxChange()}function setOutput(output,s){output.innerHTML=s}function addOutput(output,data){output.innerHTML='<pre style="background-color:'+(data.type=="err"?"lightcoral":"lightgray")+'">'+escape(data.content)+"</pre>"}function getByteCount(s){return(new Blob([s],{encoding:"UTF-8",type:"text/plain;charset=UTF-8"})).size}function onTextboxChange(){var newLength=getByteCount(getNewCode());var oldLength=getByteCount(getOriginalCode());bytecount.innerHTML=newLength+" bytes";var diff=newLength-oldLength;if(diff>0){bytediff.innerHTML="(+"+diff+")";bytediff.style.color="lightcoral"}else if(diff<0){bytediff.innerHTML="("+diff+")";bytediff.style.color="lightgreen"}else{bytediff.innerHTML="("+diff+")";bytediff.style.color="lightgray"}}function onTestBtn(evt){origheader.style.display="inline";newheader.style.display="inline";setOutput(newoutput,"");setOutput(origoutput,"");var input=getInput();if(input===null){addOutput(origoutput,{type:"err",content:"Input is malformed. Using no input."});addOutput(newoutput,{type:"err",content:"Input is malformed. Using no input."});input=[]}doInterpret(getNewCode(),input,function(data){addOutput(newoutput,data)});doInterpret(getOriginalCode(),input,function(data){addOutput(origoutput,data)});evt.stopPropagation();return false}function onResetBtn(evt){setTextbox(getOriginalCode());origheader.style.display="none";newheader.style.display="none";setOutput(origoutput,"");setOutput(newoutput,"")}function escape(s){return s.toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}window.alert=function(){};window.prompt=function(){};function doInterpret(code,input,cb){var workerCode=interpret.toString()+";function stdout(s){ self.postMessage( {'type': 'out', 'content': s} ); }"+" function stderr(s){ self.postMessage( {'type': 'err', 'content': s} ); }"+" function kill(){ self.close(); }"+" self.addEventListener('message', function(msg){ interpret(msg.data.code, msg.data.input); });";var interpreter=new Worker(URL.createObjectURL(new Blob([workerCode])));interpreter.addEventListener("message",function(msg){cb(msg.data)});interpreter.postMessage({"code":code,"input":input});setTimeout(function(){interpreter.terminate()},1E4)}setTimeout(function(){getOriginalCode();textbox.addEventListener("input",onTextboxChange);testbtn.addEventListener("click",onTestBtn);resetbtn.addEventListener("click",onResetBtn);setTextbox(getOriginalCode())},100);function interpret(code,input){_=undefined;window={};alert=function(s){stdout(s)};window.alert=alert;console.log=alert;prompt=function(s){if(input.length<1)stderr("not enough input");else{var nextInput=input[0];input=input.slice(1);return nextInput.toString()}};window.prompt=prompt;(function(){try{_=undefined;eval(code);if(typeof evalResult=="disabled_function_evaluation"){var callResult=evalResult.apply(this,input);if(typeof callResult!="undefined")stdout(callResult)}}catch(e){stderr(e.message)}})()};</script>

一个更好的解释即将到来。同时,请随时在@jrich聊天中对我进行任何评论/提问/批评。


啊,好吧,
Downgoat '16

4
使用this代替window
Mama Fun Roll

3
+1表示将生命的意义包含在源代码中
Cyoce
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.