2012-12-12 55 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;線)。這裏的修改浪潮將停止。

就是這樣,我們有兩個程序可以打印自己或每個其他,根據命令行參數。

我鼓勵你真正做了這一切。