2012-12-12 32 views
3

我定义的多喹为:如何编写复杂的多重quines?

一组Ñ方案Ñ不同的编程语言,使得它们中的每一个,给定的无输入时,输出它的确切的源代码,当给出n作为输入时,输出第* n *个程序的源代码。

这不是要与节目的圆形序列,其中每个程序输出下一个的源代码迷惑,直到所述第一程序已被输出。在这种情况下,每个程序都不是一个quine,这就使得这个问题失败了。这些循环集合,虽然是高价值的n的有趣的脑筋急转弯,但实现起来相当微不足道。

复杂的,在这种情况下,意思是“对于值为n大于或等于 2.”我相信n = 2的解决方案在这种情况下足够复杂。然而,针对所有n的值的一般解决方案(读取:策略)是目标。

我明白“简单”的奎因斯是怎么写的,但是我似乎无法摆脱复杂的多重奎因,这让我着迷。我希望除了程序员头脑中的剪切智慧之外,没有其他解决方案 - 尽管我认为这不太可能。

+0

得到这个答案的最好方法是去codegolf.SE,并要求人们尝试写一个multi-quine。设定的评价标准(像分钟(S/N),N> = 2),其中s是码大小,并等待答复。 :) –

+0

@Victor虽然这可能会得到一个解决方案,但我对丑陋,简短,混淆的多重quines不感兴趣。我不是在* *的解决方案,即使真的有兴趣,而是,* *如何创建一个解决方案。这就是为什么我把这里的问题,而不是codegolf,但我必须承认,我希望多一点的答案;) – Swadq

回答

4

在quines,多语种quines,multi-quines中,你没有什么特别的,你的名字。他们都可以自动写入。

举例来说,C++中的bog标准,冗长,不雅,低效的奎因。但是,它有其缺点,很容易修改以实现我们想要的功能。

#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),该字符串为"====="

很容易插入任何其他操作,例如用另一种语言打印另一个奎因。我为这样的行为插入了占位符。

现在,将它翻译成任何编程语言(比如说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++奎因。没问题,让我们将C++ quine复制回FORTRAN quine。

但是,C++奎因已经包含整个FORTRAN奎因,两次

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

我们只需要稍微修改FORTRAN。当我们问FORTRAN蒯打印C++奎因,它应该打印所有的C++线所有FORTRAN线,两次:一次作为Li,一次为std::cout << "Li" << std::endl;,就像C++奎因它。然后我们得到C++奎因(包括FORTRAN奎因)。

我们还需要进行这些修改FORTRAN回C++(即,修改std::cout << "Li" << std::endl;线)。这里的修改浪潮将停止。

就是这样,我们有两个程序可以打印自己或每个其他,根据命令行参数。

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