如何编写复杂的多qu?

时间:2012-12-12 23:06:10

标签: language-agnostic quine

我将多quine定义为:

  

n 不同编程语言中的一组 n 程序,这样,当没有输入时,它们中的每一个都输出其确切的源代码,并在给出时< em> n 作为输入,输出* n *程序的源代码。

这不要与循环程序序列相混淆,其中每个程序输出下一个程序的源代码,直到输出第一个程序。在这种情况下,每个程序都不是一个quine,这打破了这一点。这些循环集虽然是 n 高值的有趣脑筋急转弯,但实现起来却非常简单。

复杂,在本例中,表示“对于 n 的值大于或等于 2”。我认为n = 2的解决方案在这种情况下足够复杂。但是, n 的所有值的一般解决方案(读取:策略)是目标。

我理解如何编写“简单”的quines,但是我似乎无法理解复杂的多边形,这让我很着迷。我的一部分希望除了程序员心中的剪切巧妙之外没有解决方案 - 尽管我认为这不太可能。

1 个答案:

答案 0 :(得分:4)

没有什么特别的东西,多语种的quines,多quines,你的名字。它们都可以自动编写。

这里,举例来说,C ++中的标准,冗长,不优雅,低效的quine。然而,它有其所有的缺点,很容易修改,以做我们想要的。

#include <iostream>
#include <string>
#include <cstdlib>

std::string show (const std::string& in) {
    std::string res = "\"";
    for (std::string::const_iterator it = in.begin(); it < in.end(); ++it) {
        switch (*it) {
            case '"':
            case '\\':
                res += '\\';
            default:
                res += *it;
        }
    }
    res += "\"";
    return res;
}

int main (int argc, char* argv[])
{
    std::string arr[] = { // beginning ends here
"#include <iostream>",
"#include <string>",
"#include <cstdlib>",
"",
"std::string show (const std::string& in) {",
"    std::string res = \"\\\"\";",
"    for (std::string::const_iterator it = in.begin(); it < in.end(); ++it) {",
"        switch (*it) {",
"            case '\"':",
"            case '\\\\':",
"                res += '\\\\';",
"            default:",
"                res += *it;",
"        }",
"    }",
"    res += \"\\\"\";",
"    return res;",
"}",
"",
"int main (int argc, char* argv[])",
"{",
"    std::string arr[] = { // beginning ends here",
"======",
"    };",
"    int n = argc == 1 ? 0 : std::atoi(argv[1]);",
"    if (n == 0) {",
"        int i, j;",
"        for (i = 0; arr[i] != \"======\"; ++i) std::cout << arr[i] << std::endl;",
"        for (j = 0; j < sizeof(arr)/sizeof(arr[0]); ++j) std::cout << show(arr[j]) << ',' << std::endl;",
"        for (++i; i < sizeof(arr)/sizeof(arr[0]); ++i) std::cout << arr[i] << std::endl;",
"    } else {",
"    }",
"}",
    };
    int n = argc == 1 ? 0 : std::atoi(argv[1]);
    if (n == 0) {
        int i, j;
        for (i = 0; arr[i] != "======"; ++i) std::cout << arr[i] << std::endl;
        for (j = 0; j < sizeof(arr)/sizeof(arr[0]); ++j) std::cout << show(arr[j]) << ',' << std::endl;
        for (++i; i < sizeof(arr)/sizeof(arr[0]); ++i) std::cout << arr[i] << std::endl;
    } else {
    }
}

正如您所看到的,程序的核心是一个名为show的小函数,它接受一个字符串并将其表示形式返回为C ++文字。整体结构如下:打印字符串数组的开始部分;通过show打印整个阵列;打印阵列的末尾部分。字符串数组是程序的副本,插入程序的中间。初始部分通过一个特殊的"====="字符串与最终部分分开,该字符串不是从程序中复制的(只打印一次,通过show)。

可以轻松插入任何其他操作,例如使用其他语言打印另一个quine。我已为此类操作插入了占位符。

现在将它转换为任何编程语言(例如FORTRAN)绝对是微不足道的。假设我们已经完成它,它由线L1,L2,......,LN组成。我们在占位符中插入这些语句:

std::cout << "L1" << std::endl;
std::cout << "L2" << std::endl;
...
std::cout << "LN" << std::endl;

我们相应地修改字符串数组。 Voilà,我们有一个可以自己打印的quine,以及FORTRAN中的quine,具体取决于命令行参数。

好的,FORTRAN quine怎么样?它只能打印自己,而不是C ++ quine。没问题,让我们将C ++ quine复制回FORTRAN quine。

但是C ++ quine已经包含了整个FORTRAN quine,两次

没问题,因为 FORTRAN quine已经可以自行打印了。因此,我们只需要将原始C ++行复制回FORTRAN。无需再次(或两次)在自身内复制FORTRAN。

我们只需稍微修改FORTRAN。当我们要求FORTRAN quine打印C ++ quine时,它应该打印所有C ++行以及所有FORTRAN行,两次:一次为Li并且一次为std::cout << "Li" << std::endl;,就像C ++ quine一样。然后我们回到C ++ quine(包括FORTRAN quine)。

我们还需要将这些FORTRAN修改带回C ++(即修改std::cout << "Li" << std::endl;行)。而修改浪潮就此停止。

就是这样,我们有两个程序可以自己打印或相互打印,具体取决于命令行参数。

我鼓励你真正做到这一切。