3

我将 multi-quine 定义为:

一组n种不同编程语言的程序,使得每个程序在没有输入时输出其确切的源代码,当给定n作为输入时,输出第 *n*th 程序的源代码。

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

在这种情况下,复数表示“对于大于或等于2的n值”。我相信在这种情况下,解决方案足够复杂。但是,目标是所有n值的通用解决方案(阅读:策略)。n = 2

我了解“简单”的 quines 是如何编写的,但是我似乎无法理解复杂的 multiquines,这让我着迷。我的一部分希望除了程序员头脑中的聪明才智之外没有其他解决方案——尽管我认为这不太可能。

4

1 回答 1

4

quines、多语言 quines、multi-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;

我们相应地修改字符串数组。瞧,我们有一个可以打印自己的 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 行,两次:一次 asLi和一次 as std::cout << "Li" << std::endl;,就像 C++ quine 一样。然后我们得到 C++ quine(包括 FORTRAN quine)。

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

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

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

于 2012-12-14T00:33:58.180 回答