Quine (tietokoneohjelma)

Wikipedia
Loikkaa: valikkoon, hakuun

Quine on tietokoneohjelma (eräs metaohjelmoinnin muoto), joka tuottaa oman lähdekoodinsa ainoana tulosteenaan ilman ulkoisia syötteitä. Tietokoneharrastajat pyrkivät silloin tällöin huvikseen luomaan lyhimmän mahdollisen quinen millä tahansa ohjelmointikielellä.

Yleensä ohjelmia, jotka yksinkertaisesti avaavat lähdekooditiedoston ja tulostavat sen sisällön (kuten ensimmäinen BASIC-esimerkki alla), pidetään huijauksena.

Lisäksi quinea, joka ei sisällä koodia, ei lasketa sellaiseksi. Monissa ohjelmointikielissä "nollaohjelman" suorittaminen tuottaa tulosteena koodin (eli ei mitään). Tyhjä ohjelma voitti kerran palkinnon "pahimmasta sääntöjen kiertämisestä" Obfuscated C-kilpailussa.

Quinet on nimetty filosofi Willard Van Orman Quinen mukaan, joka tutki laajalti epäsuoraa itseviittausta.

Esimerkkiquine BASIC-kielellä[muokkaa | muokkaa wikitekstiä]

10 LIST

Tätä quinea voidaan pitää "huijauksena", sillä se lukee oman lähdekoodinsa. Tässä toinen esimerkki:

10 C=": PRINT CHR(49)+CHR(48)+CHR(32)+CHR(67)+CHR(61)+CHR(34)+C+CHR(34)+C":
PRINT CHR(49)+CHR(48)+CHR(32)+CHR(67)+CHR(61)+CHR(34)+C+CHR(34)+C

Selkeämpi versio C64 basicilla:

10 READ A$:PRINT 10 A$:PRINT 20 "DATA" A$
20 DATA READ A$:PRINT 10 A$:PRINT 20 "DATA" A$

Esimerkkiquine Befunge-kielellä[muokkaa | muokkaa wikitekstiä]

Alla esimerkkiquine Befunge-kielellä:

<>>#"652**:,2+:,,75*,89+2*,>:#,_89+2*,@"

Esimerkkiquine Brainfuck-kielellä[muokkaa | muokkaa wikitekstiä]

(Huom. Tämän pitäisi olla yksi yhtenäinen rivi koodia, mutta se on rivitetty lukemisen "helpottamiseksi". Tulosteessa rivinvaihtoja ei ole.)

->++>+++>+>+>+++>>>>>>>>>>>>>>>>>>>>>>+>+>++>+++>++>>+++>+>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>+>+>>+++>>>>+++>>>+++>+>>>>>>>++>+++>+++>+>+++>+>>+++>>>+++>+>++>+++>
>>+>+>+>+>++>+++>+>+>>+++>>>>>>>+>+>>>+>+>++>+++>+++>+>>+++>+++>+>+++>+>++>+++>+
+>>+>+>++>+++>+>+>>+++>>>+++>+>>>++>+++>+++>+>>+++>>>+++>+>+++>+>>+++>>+++>>+[[>
>+[>]+>+[<]<-]>>[>]<+<+++[<]<<+]>+[>>]+++>+[+[<++++++++++++++++>-]<++++++++++.<]

Esimerkkiquineja C-kielellä[muokkaa | muokkaa wikitekstiä]

#include<stdio.h>
char*i="\\#include<stdio.h>",n='\n',q='"',*p=
"%s%cchar*i=%c%c%s%c,n='%cn',q='%c',*p=%c%c%s%c,*m=%c%c%s%c%c;%s%c",*m=
"int main(){return!printf(p,i+1,n,q,*i,i,q,*i,q,n,q,p,q,n,q,m,q,n,m,n);}"
;int main(){return!printf(p,i+1,n,q,*i,i,q,*i,q,n,q,p,q,n,q,m,q,n,m,n);}

Toinen (Tämän kuuluisi olla yksi rivi, ja olettaa, että käytössä on ASCII-merkistöä käyttävä kone):

extern printf(char*,...);main(){char*a="extern printf(char*,...);
main(){char*a=%c%s%c;printf(a,34,a,34,10);}%c";printf(a,34,a,34,10);}

tai, vielä lyhyemmin (vaikka ei ISO C89-standardin mukaista koodia, lisäksi kumpikaan koodi ei täytä uudempaa ISO C99-standardia):

main(){char*a="main(){char*a=%c%s%c;printf(a,34,a,34);}";printf(a,34,a,34);}

Tämä versio ei ole ASCII-riippuvainen ja käyttää C:n esikäsittelijää lainausmerkkien ja escape-merkkien tuottamiseen:

#define T(a) main(){printf(a,#a);}
T("#define T(a) main(){printf(a,#a);}\nT(%s)\n")

Kuten yllä mainittiin, nolla-pituinen ohjelma on teknisesti quine, jos se voidaan kääntää ohjelmatiedostoksi, joka ei tee mitään (ts. tulostaa nolla merkkiä vakiotulosteeseen). Tämä on mahdollista C:ssä virittelemällä Makefileä hieman (sillä oletuksena ei luotaisi suoritettavaa tiedostoa).

Esimerkkiquine C++ -kielellä[muokkaa | muokkaa wikitekstiä]

(Huom: rivinvaihtoja lisätty lukemisen helpottamiseksi)

#include <iostream>
int main(){const char c=',',dq='"',q[]="'",*s[]={"#include <iostream>",
"int main(){const char c=',',dq='","',q[]=",",*s[]={","};std::cout<<s[0]<<std::endl<<s[1]<<dq<<s[2]
<<dq<<q<<dq<<s[3]<<dq<<s[0]<<dq<<c<<dq<<s[1]<<dq<<c<<dq<<s[2]<<dq<<c<<dq<<s[3]<<dq<<c<<dq<<s[4]<<dq
<<s[4]<<std::endl;}"};std::cout<<s[0]<<std::endl<<s[1]<<dq<<s[2]<<dq<<q<<dq<<s[3]<<dq<<s[0]<<dq<<c
<<dq<<s[1]<<dq<<c<<dq<<s[2]<<dq<<c<<dq<<s[3]<<dq<<c<<dq<<s[4]<<dq<<s[4]<<std::endl;}

Esimerkkiquine C#-kielellä[muokkaa | muokkaa wikitekstiä]

(Huom: rivinvaihtoja lisätty lukemisen helpottamiseksi)

using System;
namespace quine
{
  class Program
  {
    [STAThread]
    static void Main(string[] args)
    {
      string s = "using System;{0}namespace quine{0}{2}{0}{1}class Program{0}
{1}{2}{0}{1}{1}[STAThread]{0}{1}{1}static void Main(string[] args){0}{1}{1}{2}{0}{1}{1}{1}
string s = {4}{6}{4};{0}{1}{1}{1}Console.Write(s, Environment.NewLine, {4}{5}t{4}, {4}{2}
{4}, {4}{3}{4}, {4}{5}{4}{4}, {4}{5}{5}{4}, s);{0}{1}{1}{3}{0}{1}{3}{0}{3}";
      Console.Write(s, Environment.NewLine, "\t", "{", "}", "\"", "\\", s);
    }
  }
}

Yksinkertaisempi versio, joka tulostaa myös rivinvaihdot:

class Q
{
    static void Main()
    {
        string s = @"class Q
{0}
    static void Main()
    {0}
        string s = @{2}{3}{2};
        System.Console.Write(s, '{0}', '{1}', '{2}', s);
    {1}
{1}";
        System.Console.Write(s, '{', '}', '"', s);
    }
}

Sama ilman muotoiluja (poista rivinvaihdot):

class Q{static void Main(){string s="class Q{0}static void 
Main(){0}string s={2}{3}{2};System.Console.Write(s,'{0}',
'{1}','{2}',s);{1}{1}";System.Console.Write(s,'{','}','"',s);}}


Esimerkkiquine Dc-laskimelle[muokkaa | muokkaa wikitekstiä]

[91PP[dx]93PP]dx


Esimerkkiquine DOSin eräajotiedostona[muokkaa | muokkaa wikitekstiä]

 @echo off
 %1 %2
 call %0 goto e %%
 call %0 goto e %%3 echo.%%4
 echo :f
 goto f
 :e
 echo.%4@echo off
 echo.%4%31 %32
 echo.%4call %30 goto e %3%3
 echo.%4call %30 goto e %3%33 echo.%3%34
 echo.%4echo :f
 echo.%4goto f
 echo.%4:e
 :f

Esimerkkiquine Haskell-kielellä[muokkaa | muokkaa wikitekstiä]

 main=putStr$q++show q;q="main=putStr$q++show q;q="

Esimerkkiquine HQ9+-kielellä[muokkaa | muokkaa wikitekstiä]

Q

(Huom. Tätä voidaan pitää huijauksena, sillä 'Q'-komento tulostaa ohjelman lähdekoodin.)

Esimerkkiquine Javascript-kielellä käyttäen XMLHTTP:tä[muokkaa | muokkaa wikitekstiä]

<html><body><pre id="code">.</pre></body><script type="text/javascript">
        var aflac = (window.ActiveXObject)?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();
        aflac.onreadystatechange = aflacStateChange;
        aflac.open("GET", location.href, true); aflac.send("");     
        function aflacStateChange() {if (aflac.readyState == 4) {addCode(aflac.responseText);}} 
        function addCode(text) {document.getElementById("code").firstChild.nodeValue = text;}
</script></html>

(Tätäkin voidaan pitää huijauksena, sillä lähdekoodi pyydetään palvelimelta ja näytetään sellaisenaan)

Esimerkkiquine Java-kielellä[muokkaa | muokkaa wikitekstiä]

(Huom. rivinvaihdot lisätty koodiin)

class Q{public static void main(String[]a){char q=34;String t="class Q{public static void main(String[]a){char 
q=34;String t=;System.out.println(t.substring(0,62)+q+t+q+t.substring(62));}}";System.out.println(t.substring
(0,62)+q+t+q+t.substring(62));}}

Esimerkkiquine Lisp-kielellä[muokkaa | muokkaa wikitekstiä]

   (funcall (lambda (x) 
              (append x (list (list 'quote x))))
            '(funcall (lambda (x) 
                         (append x (list (list 'quote x))))))

Lyhyempi:

:X

Esimerkkiquine MATLAB-kielellä[muokkaa | muokkaa wikitekstiä]

a='a=%c%s%c;a=sprintf(a,39,a,39);disp(a);';a=sprintf(a,39,a,39);disp(a);


Esimerkkiquine OCaml-kielellä[muokkaa | muokkaa wikitekstiä]

(fun s → Printf.printf "%s %S ;;" s s) "(fun s → Printf.printf \"%s %S ;;\" s s)" ;;

Esimerkkiquine Pascal-kielellä[muokkaa | muokkaa wikitekstiä]

const a='const a=';b='begin write(a,#39,a,#39#59#98#61#39,b,#39#59#10,b) end.';
begin write(a,#39,a,#39#59#98#61#39,b,#39#59#10,b) end.

Toinen esimerkki (Borland Pascal ja Free Pascal):

const a='const a=;begin write(copy(a,1,8),#39,a,#39,copy(a,9,99)) end.';begin write(copy(a,1,8),#39,a,#39,copy(a,9,99)) end.

Kolmas esimerkki (Borland Pascal ja Free Pascal):

const a:string='const a:string=;begin insert(#39+a+#39,a,16);write(a) end.';begin insert(#39+a+#39,a,16);write(a) end.


Esimerkkiquine Perl-kielellä[muokkaa | muokkaa wikitekstiä]

$_=q{$_=q{Q};s/Q/$_/;print};s/Q/$_/;print

Toinen esimerkki:

$_=q{print"\$_=q{$_};eval"};eval

shell/Perl-yhdistelmä:

perl -le '$n=q{perl -le a$n=q{$x};($_=$n)=~s/\141/\47/g;s/\$x/$n/;printa};($_=$n)=~s/\141/\47/g;s/\$x/$n/;print'

Tämä quine huijaa käyttämällä erityistä DATA-tiedostokahvaa lähdekoodin hakemiseksi:

seek DATA, 0, 0; print 
__DATA__


Esimerkkiquine PHP-kielellä[muokkaa | muokkaa wikitekstiä]

 <?
 $a='chr(60).chr(63).chr(10).chr(36).chr(97).chr(61).chr(39).$a.chr(39).chr(59).chr(10)."echo $a;".chr(10).chr(63).chr(62)';
 echo chr(60).chr(63).chr(10).chr(36).chr(97).chr(61).chr(39).$a.chr(39).chr(59).chr(10)."echo $a;".chr(10).chr(63).chr(62);
 ?>
 
 <?
 $a='<?
 $a=2;
 echo str_replace(1+1,chr(39).$a.chr(39),$a);
 ?>';
 echo str_replace(1+1,chr(39).$a.chr(39),$a);
 ?>

Toinen esimerkki:

<?php $c='echo \'<?php $c=\\\'\'.addslashes($c).\'\\\';eval($c) ?>\';';eval($c) ?>

Kolmas esimerkki: (voidaan pitää huijauksena)

<? print file_get_contents(".".$PHP_SELF); ?>

Huom: Esimerkki edellyttää vähintään PHP 4.3-versiota.

Esimerkkiquine PL/I-kielellä[muokkaa | muokkaa wikitekstiä]

(Huom: Tämä pienin mahdollinen PL/I-quine kääntyy käyttämällä OS PL/I V2.3.0-kääntäjää, mutta vaatii vasemman marginaalin asetukseksi 1 sekä COMPILE-option ohittaakseen huomattavan määrän virheilmoituksia ja varoituksia...)

  %dcl z%z='put edit';proc options(main;q=''''put list(m;do i=1,2;z(q)skip;do j=
  1to 78c=substr(m(i),j;if c=q z(c;z(c;end;z(q',';dcl(c,q)char,m(2)char(99)init(
  '%dcl z%z=''put edit'';proc options(main;q=''''''''put list(m;do i=1,2;z(q)skip;do j=',
  '1to 78c=substr(m(i),j;if c=q z(c;z(c;end;z(q'','';dcl(c,q)char,m(2)char(99)init(',

Esimerkkiquine PostScript-kielellä[muokkaa | muokkaa wikitekstiä]

 (dup == {dup cvx exec} pop 8 12 getinterval =)
 dup cvx exec


Esimerkkiquine Python-kielellä[muokkaa | muokkaa wikitekstiä]

a='a=%s;print a%%`a`';print a%`a`

Neljä merkkiä lyhyempi muunnos:

a='a=%r;print a%%a';print a%a

Toinen esimerkki:

b='\\';g='"';p='%';s="b='%s%s';g='%s';p='%s';s=%s%s%s;print s%s(b,b,g,p,g,s,g,p)";print s%(b,b,g,p,g,s,g,p)

Sekä kolmas esimerkki jonka 61 viimeistä merkkiä ovat samat kuin edellisessä (vain sen osoittamiseksi, että usean muuttujan samanaikainen määrittely ei säästä kirjoittamista):

b,g,p,s='\\','"','%',"b,g,p,s='%s%s','%s','%s',%s%s%s;print s%s(b,b,g,p,g,s,g,p)";print s%(b,b,g,p,g,s,g,p)

Vielä yksi, joka on hieman luettavampi ja hauskemman näköinen:

i = r'"i = r\'" + i + "\'\nprint " + i'
print "i = r\'" + i + "\'\nprint " + i

Esimerkkiquine Ruby-kielellä[muokkaa | muokkaa wikitekstiä]

puts <<2*2,2
puts <<2*2,2
2

Toinen, hieman vaikeammin luettava esimerkki:

_="puts'_='+_.inspect+';'+_";puts'_='+_.inspect+';'+_

Esimerkkiquine Scheme-kielellä[muokkaa | muokkaa wikitekstiä]

   ((lambda (x)
           (list x (list (quote quote) x)))
       (quote
           (lambda (x)
               (list x (list (quote quote) x)))))


Esimerkkiquine TCL-kielellä[muokkaa | muokkaa wikitekstiä]

 puts [join [split "puts \[a{a}]" a] {join [split "puts \[a{a}]" a] }]


Esimerkkiquine VBScript-kielellä[muokkaa | muokkaa wikitekstiä]

a="a="":b=left(a,3):c=mid(a,3):msgbox(b+b+c+c)":b=left(a,3):c=mid(a,3):msgbox(b+b+c+c)


Esimerkkiquine Visual FoxPro-kielellä[muokkaa | muokkaa wikitekstiä]

 CLEAR
 SET TALK OFF
 SET TEXTMERGE ON
 \CLEAR
 \SET TALK OFF
 \SET TEXTMERGE ON

Esimerkkiquine konekielellä (MS-DOSin COM-tiedosto)[muokkaa | muokkaa wikitekstiä]

Alla olevilla merkeillä on samat merkkikoodit kuin quinen tulostamilla. Ne saattavat kuitenkin näyttää tässä erilaisilta muotoilun vuoksi. Jos ohjelman avaa perustekstinkäsittelyohjelmassa kuten MS-DOS Edit, merkit näkyvät kuten ne tulostuvat, todistaen, että kyseessä on quine:

 ´@»�&#x00;¹�&#x00;º��Í!´@Í!ô@»�&#x00;¹�&#x00;º��Í!´@Í!Ã

Yllä oleva teksti on tulos, joka saadaan, kun tietokone käsittelee komennot merkkeinä. Alla on komennot heksadesimaalinumeroina. Niiden ja heksaeditorin avulla voidaan luoda suoritettava COM-tiedosto.

 b4 40 bb 01 00 b9 12 00 ba 12 01 cd 21 b4 40 cd 21 c3 b4 40 bb 01 00 b9 12 00 ba 12 01 cd 21 b4 40 cd 21 c3

Paljon lyhyempi versio ohjelmasta:

 b4 09 ba 00 01 cd 21 c3 24

mutta tätä voidaan pitää huijauksena, sillä se lukee oman koodinsa.

Katso myös[muokkaa | muokkaa wikitekstiä]