Tipps zum Schreiben von Quines


30

EIN ist ein Programm, das eine Ausgabe erzeugt, die mit dem Quellcode des Programms identisch ist. Auf dieser Website kümmern wir uns im Allgemeinen nur um die richtigen Quines (zum Zeitpunkt des Schreibens ist die aktuelle Definition "ein Teil der Ausgabe wird von einem anderen Teil des Programms codiert").

Welchen Rat haben Sie zum Schreiben geeigneter Quines oder Programme mit quineähnlichen Eigenschaften? Wie üblich sollte jeder Tipp in einer anderen Antwort sein.

tips  quine 

Antworten:


14

Verwenden Sie evaldiese Option , um die Notwendigkeit zu verringern, Code zu kopieren

Für die meisten Quines sind zwei Kopien des Codes erforderlich. eine, die ausgeführt werden soll, eine als Daten. Dies kann dazu führen, dass sich die Länge des Quellcodes verdoppelt, die Wartung schwieriger wird und sich die Punktzahl verschlechtert, wenn Sie das Quine für einen Wettbewerb schreiben .

Das Zusammenführen der beiden Kopien bedeutet, dass eine Information für zwei Zwecke verwendet werden muss. Der Versuch, Ihren Code als Daten zu behandeln, ist häufig nicht möglich und wird in der Regel als Betrug betrachtet, wenn dies der Fall ist. Das Behandeln von Daten als Code kann jedoch in vielen Sprachen über die Verwendung eines eingebauten Codes erfolgen, der normalerweise als "Code" bezeichnet wird eval. Als solches besteht Ihr Quine im Grunde darin, den Hauptteil Ihres Quine in einer Variablen zu speichern (so dass Sie mehr als einmal darauf verweisen können) und diese Variable dann auszuwerten.

Hier ist ein Beispiel, wie dies funktioniert (das Beispiel ist in Python geschrieben, aber in vielen anderen Sprachen funktioniert etwas Ähnliches):

d='print("d="+repr(d)+"\\neval(d)")'
eval(d)

2
@QPaysTaxes: Ich möchte meinen Code hier so lesbar und wartbar machen, wie es die Siegbedingung zulässt. Leider ist dies in der Regel immer noch nicht von ASCII-Zeilenrauschen (oder nur von normalem Zeilenrauschen, wenn ich Jelly verwende) von Personen zu unterscheiden, die nicht an die Sprache gewöhnt sind.

14

Nutzen Sie die Formatierung von Zeichenfolgen

Eine der einfachsten Möglichkeiten, eine Quine zu erstellen, besteht darin, eine Zeichenfolge zu definieren und die Zeichenfolge dann mit der Formatierung der Zeichenfolge in sich selbst einzufügen.

s='s=%r;print s%%s';print s%s

In diesem Beispiel für Python quine deklarieren wir einen String mit dem ersten Teil, der gleich dem ist, was vor dem String s=steht. Anschließend lassen wir den String mit der Formatierung einfügen %rund setzen schließlich das, was nach dem String kommt, um ihn zu drucken und zu formatieren . Der abschließende Zeilenumbruch liegt daranprint eine nachfolgende Newline gedruckt wird.

Die Vorlage in Python sieht also wirklich so aus:

<A>'<A>%r<B>'<B>

So erweitern Sie die vorhandene Quine mit mehr Code:

<more A>s='<more A>s=%r;print s%%s<more B>';print s%s<more B>

9

Stringifizierte Funktionen

In mehreren Sprachen speichern Funktionsobjekte (oder gleichwertige Konstrukte) implizit ihren Quellcode und geben ihn zurück, wenn er in einen String konvertiert wird. Dies ermöglicht kompakte Quines ohne Verwendung einer String-Auswertung . Ein bemerkenswertes Beispiel für eine solche Sprache ist JavaScript:

function f(){console.log(f+"f()")}f()

Dieser Code definiert und ruft eine Funktion auf f, die beim Aufruf ihren eigenen Quellcode ausgibt, gefolgt von einem Aufruf an sich selbst. Der einzige Teil des Programms, der dupliziert werden muss, ist der Funktionsaufruf f(). Natürlich kann der Funktionskörper eine beliebige "Nutzlast" von Code enthalten, die auch ausgeführt wird, wenn die Funktion aufgerufen wird.


Eine kompaktere Version desselben Tricks funktioniert in den Golfsprachen GolfScript :

{".~"}.~

und CJam :

{"_~"}_~

Jede dieser Quines definiert zunächst einen anonymen Codeblock (in geschweiften Klammern), der sich ähnlich wie ein Funktionsobjekt in JavaScript verhält: Er kann ausgeführt werden und gibt, wenn er stringiert ist, seinen Quellcode zurück. Der Rest des Codes ( .~in GolfScript oder _~in CJam) führt dann den Block aus, während eine Kopie davon auf dem Stapel verbleibt. Der Code innerhalb des Blocks legt dann eine Zeichenfolge auf den Stapel, die den Code außerhalb des Blocks wiederholt. Wenn der Interpreter beendet wird, wird automatisch alles auf dem Stapel verbliebene aufgereiht und gedruckt. Wie im JavaScript-Beispiel könnten diese Codeblöcke auch dazu gebracht werden, eine beliebige Nutzlast von zusätzlichem Code zu transportieren und auszuführen, ohne ihn duplizieren zu müssen.


9

Verwenden Sie Zeichenfolgenbegrenzer, die ohne Escapezeichen verschachtelt werden

Oft ist einer der schwierigsten Teile beim Schreiben einer Quine das Entkommen. Dies wird in fast jedem Quine benötigt; Das Problem ist, dass Sie Daten irgendwie speichern und den Code replizieren müssen, der die Daten in der Ausgabe des Quines speichert. Dieser Code enthält eine maskierte Form der Daten, sodass das Programm eine maskierte Form sieht und Sie diese erneut maskieren müssen.

Der einfachste Weg, um den Schritt des Auslöschens zu handhaben, besteht darin, dass sich die maskierten und nicht maskierten Formen der Daten nur durch das Vorhandensein oder Fehlen von Zeichenfolgenbegrenzern unterscheiden. Beim Escaping müssen Sie also einfach ein neues Paar von Zeichenfolgenbegrenzern um die Zeichenfolge hinzufügen. Leider kann dies eindeutig nur funktionieren, wenn die Zeichenkettenbegrenzer selbst ohne Escapezeichen in den Daten ausgedrückt werden können.

Perl ist ein gutes Beispiel für eine Sprache, in der dieser Trick funktioniert. Obwohl es sich bei den üblichen Zeichenkettenbegrenzern um "…"oder handelt '…', handelt es sich um die seltener verwendeten q(…)Nester, so dass diese Art von Quine geschrieben werden kann:

$_=q($_=q(0);s/\d/$_/;print);s/\d/$_/;print

Dies ist ein Code + Daten quine. s///ist eine reguläre Zeichenfolge-Ersetzungsoperation; Wir verwenden 0als Marker und passen ihn innerhalb des regulären Ausdrucks als \d("beliebige Ziffer") an, um zu vermeiden, dass der Marker mehrmals verwendet wird (obwohl wir ihn als weitere Optimierung auch nur noch 0einmal hätten verwenden können, da Perl s///nur das erste Vorkommen durch ersetzt Standard). Beachten Sie, dass hier kein expliziter Escape-Schritt erforderlich ist, da die q(…)Begrenzer nur wörtlich in die Datenzeichenfolge eingeschlossen werden können.


8

Code + Datenquines

Die allgemeinste Struktur für eine Quine sieht ungefähr so ​​aus:

data = " eine ausgeblendete Version des gesamten Programms,
        mit dieser Zeichenfolge mit einem Marker ersetzt "
program = data.replace (
  Ein Ausdruck, der als Marker ausgewertet wird, ihn aber nicht erwähnt ,
  entkommen (Daten)
Druckprogramm;

Diese Struktur kann verwendet werden, um in den meisten Sprachen eine (ziemlich naive) Quine zu schreiben. Auf den meisten Scoring-Systemen kann es jedoch schlecht abschneiden, da Sie das gesamte Programm zweimal schreiben müssen. Die meisten Quine-Strukturen können jedoch als Optimierungen dieser betrachtet werden.

Dies hat einige Feinheiten. In einigen Sprachen ist es am schwierigsten, diesen Vorgang auszuführen, den Escape-Code zu schreiben. In vielen Sprachen ist es schwierig, den Marker zu produzieren, ohne seinen Namen zu erwähnen. und in einigen esoterischen Sprachen müssen Sie Ihre eigene Art von String-Literal erfinden. Alle drei Operationen verursachen jedoch nicht allzu viele Probleme.

Zum Beispiel können wir ein Python-Quine schreiben, das aus einem String herauskommt repr, und als Marker den 2-Zeichen-Sequenz- x"String verwenden (der darstellbar ist "x\"", dh nicht die Sequenz x"in der String-Darstellung des Strings selbst verwendet):

d='d=x"\nprint(str.replace(d,"x\\"",repr(d)))'
print(str.replace(d,"x\"",repr(d)))

2
Es kann erwähnenswert sein (möglicherweise in einer anderen Antwort), dass das Einfügen der Zeichenfolge an der Position eines Markers in Esolangs oft teuer ist, und es kann sich lohnen, den Code so zu strukturieren, dass die Zeichenfolge selbst das erste oder das letzte ist (möglicherweise getrennt von Das Ende besteht aus ein oder zwei Zeichen, die Sie fest codieren können, damit Sie wissen, wohin es gehen muss.
Martin Ender

@MartinEnder: Ich stimme zu, dass das erwähnenswert ist, aber es ist wahrscheinlich eine andere Antwort (anstatt eines Kommentars oder einer Änderung in dieser Antwort). Die meisten Quine-Tipps sind Änderungen an dieser allgemeinen Struktur, daher wollte ich sie zuerst als eigenen Tipp herausbringen, da viele Leute keine Ahnung haben, wo sie mit dem Schreiben eines Quine beginnen sollen.

Eine Alternative zu einem Marker ist die Verwendung von zwei Zeichenketten, die ich für Glass gemacht habe .
Ørjan Johansen

4

Wrapping-Quellcode ausnutzen

In einigen wenigen Sprachen (meistens 2D-Sprachen) kann der Quellcode umgebrochen werden. Unter bestimmten Umständen (z. B. in Befunge-98, wenn Ihr Programm ein Einzeiler ist) gelangen Sie nach Ablauf des Programms zurück zum Programmanfang. Diese Art von nichtlinearem Verhalten bedeutet, dass Sie Code schreiben können, der sich gleichzeitig innerhalb und außerhalb eines String-Literal befindet. Ein nicht passender "String (oder was auch immer der String-Begrenzer ist) gibt Ihnen effektiv einen String, der den gesamten Rest des Programms enthält (mit Ausnahme des eigentlichen Strings ").

Ein Problem bei der Verwendung dieses Tricks besteht darin, dass Sie die Zeichenfolge aus der Sicht von "anstatt vom Start des Programms (wie gewünscht) erhalten. Daher ist es wahrscheinlich am einfachsten, das Programm so neu anzuordnen, dass es "am Anfang oder Ende angezeigt wird. Dies bedeutet häufig, dass Sie Ihr Programm in mehrere Teile aufteilen und alle interessanten / ungewöhnlichen Befehle zur Ablaufsteuerung in Ihrer Sprache verwenden müssen (in den meisten Sprachen, in denen sich Zeichenfolgenliterale im Programm befinden, ist eine gute Auswahl vorhanden).

Ein gutes Beispiel ist @ Justins Befunge-98-Quine :

<@,+1!',k9"

Das nicht passende "am Ende des Programms umschließt das gesamte Programm mit einem String-Literal. <Alles, was wir tun müssen, ist, das Programm ( 9k) und dann das doppelte Anführungszeichen ( '!1+,) und (von rechts nach links ) auszugeben Ausfahrt ( @). Dies erspart die Notwendigkeit von zwei Kopien des Programms (eine als Code, eine als Daten); Die beiden Kopien sind das gleiche Stück Code, nur unterschiedlich interpretiert.


4

Erinnern Sie sich an die Struktur eines Quine

Ich stelle mir Quines lieber als drei Teile als als zwei vor:

  • Teil 1: Erstellen Sie eine Datendarstellung der Teile 2 und 3.
  • Teil 2: Verwenden Sie die Daten, um Teil 1 algorithmisch auszudrucken.
  • Teil 3: Dekodieren Sie die Darstellung, um die Teile 2 und 3 zu drucken.

Dies kann das Nachdenken über Quines erleichtern. Hier ist ein Python-Quine, wobei jede Zeile einem Teil entspricht:

s = "print(\"s = \" + repr(s))\nprint(s)"
print("s = " + repr(s))
print(s)

Manchmal verwenden Sie ein evaloder ähnliches, um Duplikate zu entfernen, aber im Allgemeinen habe ich festgestellt, dass dies beim Schreiben einfacher Quines hilfreich ist.

Schauen wir uns zwei verschiedene Underload-Quines an. Das ist das erste:

(:aSS):aSS

Der erste Teil ist (:aSS), der die Datendarstellung generiert. Das zweite ist :aS, was druckt (:aSS). Der dritte Teil ist S, der druckt :aSS.

Hier ist die zweite Quine:

(:aS(:^)S):^

Das scheint zunächst nicht zu passen. Aber wenn Sie die Quine erweitern, erhalten Sie:

(:aS(:^)S):aS(:^)S

Jetzt (:aS(:^)S)ist Teil 1, :aSist Teil 2 und (:^)Sist Teil 3.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.