Ihre Herausforderung ist einfach. Schreiben Sie zwei Programme, die keine Zeichen gemeinsam haben, die sich gegenseitig ausgeben.
Beispiel
Zwei Programme P und Q schließen sich gegenseitig aus, wenn:
- P gibt Q aus
- Q gibt P aus
- Es gibt kein Zeichen c, das sowohl zu P als auch zu Q gehört
- Jedes Programm P und Q sind richtige Quines
- Dies zählt leere Quines und Quines, die ihren eigenen (oder den des anderen) Quellcode als ungültig lesen .
Weitere Regeln
- Die kürzeste kombinierte Länge dieser Programme gewinnt. Das heißt, Größe ( P ) + Größe ( Q ) ist Ihre Punktzahl, und die niedrigste Punktzahl gewinnt.
- Beide Programme sind in derselben Sprache
- Jedes Programm kann ein vollständiges Programm oder eine vollständige Funktion sein und muss nicht identisch sein.
- Beispielsweise kann P ein vollständiges Programm sein und Q kann eine Funktion sein.
Nachprüfung
Diese Versuchen Sie es online! Hier können Sie überprüfen, ob sich zwei Programme gegenseitig ausschließen. Die Eingaben werden in die ersten beiden Argumente eingefügt.
code-challenge
quine
Conor O'Brien
quelle
quelle
Antworten:
> <> , Ergebnis: 41 + 41 = 82
Edit: beide enthielten eine 3. Behoben
und
Probieren Sie es online! (Vertauschen Sie die Zeilen, um die andere Ausgabe zu erhalten.) Diesmal mit Bestätigung!
><>
ist eine besonders schwierige Sprache, da es nur einen Weg gibt, Zeichen auszugeben, den Befehlo
. Glücklicherweise können wir den Befehl p uto
verwenden, um während der Ausführung einen Code in den Quellcode einzufügen, wie in meiner Antwort Programmierung in einer unberührten Welt .Dieser hat eine Menge Versuch und Irrtum gekostet. Ich habe mit den beiden sich gegenseitig ausschließenden Programmen begonnen:
und
Jeder transformiert sich und seine Daten um N, der erste subtrahiert und der zweite addiert. Dies gibt es dann umgekehrt aus. Der Punkt ist , dass die Daten nach jedem Programm ist das andere Programm in umgekehrter Richtung, verschoben durch N. (
X
wird die Zellnummer , wo das Programm die Anforderungen zu setzeno
und Y ist die Zelle , in der der Zeiger auf der Schleife zurück.?
Ist , wo daso
ist gesetzt) .Beide folgen derselben Struktur, die auf unterschiedliche Weise dargestellt wird. Sie führen ein Zeichenfolgenliteral über den gesamten Code aus und fügen es dem Stapel hinzu. Sie erstellen den von ihnen verwendeten String-Literal-Befehl neu und platzieren ihn unten im Stapel. Sie durchlaufen den Stapel, addieren / subtrahieren N zu jedem Zeichen und drucken sie.
Das erste Programm verwendet
'
als String-Literal und das einfachd3*}
zu erstellende den Wert 39 und schiebt ihn an den unteren Rand des Stapels. Der zweite verwendet"
als String das Literal mit der gleichen Funktion. Esr
wird der Stapelg
umgedreht, das Zeichen in Zelle 0,0 gesetzt und der Stapel erneut umgekehrt. Es setzt danng
den Wert in Zelle 4,0 (g
) und addiert 8 dazu, um den Werto
in X zu erhalten.Beide Programme verwenden eine andere Schleifenmethode. Das erste Programm verwendet den Befehl überspringen (
!
), um nur die Hälfte der Anweisungen auszuführen, während Sie nach links gehen, die Richtung umkehren und die andere Hälfte ausführen. Der zweite Befehl verwendet den Sprungbefehl (.
), um zum Anfang der Schleife in Zelle Y zurückzuspringen. Beide werden ausgeführt, bis keine Elemente mehr auf dem Stapel und die Programmfehler vorhanden sind.Ich hatte eine Reihe von Problemen mit den meisten niedrigeren Werten von N, weil das Verschieben eines Zeichens es in ein anderes für dieses Programm wesentliches Zeichen (und daher nicht als Daten für das andere Programm verwendet werden kann) oder in zwei Zeichen aus dem verwandeln würde zwei Programme würden sich in den gleichen Charakter verwandeln. Beispielsweise:
+
+1 =,
=-
-1.
+2 =0
*
=-
-3g
+4 =k
=o
-4etc.
Irgendwann bekam ich 10 (
a
), wo ich diese Probleme vermeiden konnte. Es könnte eine kürzere Version geben, in der die Verschiebungen umgekehrt sind und das erste Programm N addiert, während das zweite es subtrahiert. Dies könnte jedoch schlimmer sein, da sich das erste Programm im Allgemeinen am unteren Ende der ASCII-Skala befindet. Daher ist das Subtrahieren besser, um Konflikte zu vermeiden.quelle
Forth (64-Bit-Little-Endian-Gforth) , 428 + 637 = 1065 Bytes
Probieren Sie es online!
Überprüfungsskript
Vielen Dank an @ Nathaniel für die Idee, Forth zu verwenden - er erinnerte mich in den Kommentaren daran, dass bei Forth nicht zwischen Groß- und Kleinschreibung unterschieden wird . Dann gab es Stimmungsschwankungen - ich habe Gründe gefunden, warum dies nicht funktioniert, gefolgt von immer wieder neuen Lösungen für diese Probleme. Während ich mein Indoor-Trainingsrad wie einen übergroßen und unförmigen Zappel-Spinner drehte (Sie müssen nur ein Ende des Lenkers greifen und ihn ein wenig neigen).
Vor dem Schreiben dieser Programme habe ich ausgearbeitet, welche Zeichen von welchem Programm verwendet werden können. Insbesondere kann das zweite Programm nur Großbuchstaben, Dezimalstellen, Tabulatoren und Kommas verwenden. Dies würde bedeuten, dass das erste Programm nur Kleinbuchstaben enthält, aber ich habe einige Großbuchstaben für die ASCII-Werte verwendet.
Da Tabulatoren unhandlich sind, werde ich stattdessen Leerzeichen in der Erklärung verwenden.
Das erste Programm hat die Form
s" code"code
- dass"
startet ein String-Literal, das dann von der zweiten Kopie des Codes verarbeitet wird - ein Standard-Quine-Framework. Anstatt jedoch einen eigenen Quellcode auszugeben, wird das andere Programm erstellt, das wie folgt aussieht:HERE
64-bit-number-literal ,
length-of-the-string
115 EMIT 34 EMIT 9 EMIT 2DUP TYPE 34 EMIT TYPE
Dies verwendet den Datenraum von Forth.
HERE
Gibt den Zeiger an das Ende des aktuell zugewiesenen Datenbereichs zurück und,
hängt eine Zelle an, die mit einer Nummer gefüllt ist. Daher werden die ersten drei Aufzählungspunkte als String-Literal angezeigt, das mit erstellt wurdes"
. So beenden Sie das zweite Programm:EMIT
gibt ein Zeichen mit seinem ASCII-Wert aus.115 EMIT
druckt einen Kleinbuchstabens
34 EMIT
druckt das Anführungszeichen"
9 EMIT
druckt eine Registerkarte2DUP
dupliziert die beiden obersten Elemente auf dem Stapel( a b -- a b a b )
, hier ist es der Zeiger auf und die Länge des StringsTYPE
Gibt eine Zeichenfolge aus, um die erste Kopie des Codes auszugeben34 EMIT
druckt das abschließende Zitat"
und schließlichTYPE
gibt die zweite Kopie des Codes ausMal sehen, wie das erste Programm funktioniert. In vielen Fällen haben Zahlen vermieden werden, was die erfolgt über
'x
gforth Syntax - Erweiterung für Zeichenliterale, und manchmal den ASCII - Wert des Raumes subtrahieren, die unter Verwendung erhalten werden kannbl
:Abschließend möchte ich sagen, dass ich es mit versucht habe
EVALUATE
, aber das zweite Programm wird größer als die beiden oben dargestellten. Wie auch immer, hier ist es:Wenn du es schaffst, so viel Golf zu spielen, dass meine
s" ..."...
Herangehensweise übertroffen wird , dann poste es als deine eigene Antwort.quelle
Perl,
(311 + 630 = 941 Bytes)190 + 198 = 388 BytesBeide Programme drucken auf Standardausgabe.
Das erste Perl-Programm enthält meist druckbare ASCII-Zeichen und Zeilenumbrüche und endet in genau einer Zeile, die beiden Buchstaben ÿ stehen jedoch für das Nicht-ASCII-Byte \ xFF:
Das zweite enthält hauptsächlich Nicht-ASCII-Bytes, einschließlich mehrerer High-Control-Zeichen, die in diesem Beitrag durch Sterne ersetzt werden, und überhaupt keine Zeilenumbrüche:
Ein Hexdump des ersten Programms mit
xxd
ist:Und ein Hexdump des zweiten Programms ist:
Im zweiten Programm ist die in Anführungszeichen gesetzte Zeichenfolge (189 Bytes lang, durch Tilden begrenzt) das gesamte erste Programm mit Ausnahme der letzten Newline, die nur durch bitweise Ergänzung jedes Bytes codiert wird. Das zweite Programm dekodiert einfach die Zeichenfolge, indem es jedes der Bytes ergänzt, was der
~
Operator in Perl ausführt. Das Programm gibt den dekodierten String gefolgt von einer neuen Zeile aus (diesay
Methode fügt eine neue Zeile hinzu).Bei dieser Konstruktion verwendet der Decoder des zweiten Programms nur sechs verschiedene ASCII-Zeichen, so dass das erste Programm praktisch beliebig sein kann, solange es nur ASCII-Zeichen enthält und diese sechs Zeichen ausschließt. Es ist nicht schwer, ein Perl-Programm zu schreiben, ohne diese fünf Zeichen zu verwenden. Die eigentliche Quine-Logik befindet sich also im ersten Programm.
Im ersten Programm verwendet die Quine-Logik ein 11 Wörter langes Wörterbuch
@f
und setzt die Ausgabe dieser Wörter zusammen. Das erste Wort wiederholt den größten Teil des Quellcodes des ersten Programms. Der Rest der Wörter sind bestimmte Einzelzeichen. Beispielsweise ist Wort 5 eine Tilde, die das Trennzeichen für das Zwei-Zeichenfolgen-Literal im zweiten Programm ist. Die Liste der Zahlen in Klammern gibt an, welche Wörter in welcher Reihenfolge gedruckt werden sollen. Dies ist eine ziemlich gewöhnliche allgemeine Konstruktionsmethode für Quines. In diesem Fall besteht die einzige Verdrehung darin, dass die ersten Wörter des Wörterbuchs mit ihren Bytes bitweise komplementiert gedruckt werden.quelle
Haskell , 306 + 624 = 930 Bytes
Programm 1: Eine anonyme Funktion, die ein Dummy-Argument verwendet und eine Zeichenfolge zurückgibt.
Probieren Sie es online!
Programm 2:
q[[40,...]]
Am Ende steht eine anonyme Funktion, die ein Dummy-Argument verwendet und einen String zurückgibt.Probieren Sie es online!
Zeichensatz 1 (einschließlich Leerzeichen):
Zeichensatz 2 (einschließlich Zeilenvorschub):
Da nur Satz 1 Nicht-ASCII-Zeichen enthält, sind ihre UTF-8-Bytes auch nicht verbunden.
Wie es funktioniert
Programm 1 wird im Allgemeinen mit Lambda-Ausdrücken, Leerzeichen und Klammern, der freien Verwendung integrierter alphanumerischer Funktionen und den Quine-Daten als String-Literale am Ende geschrieben.
a
oderb
, die gültige Escape-Sequenzen bilden, die durchlaufenshow
.a
,b
undc
sind die einzigen Kleinbuchstaben , deren ASCII - Codes sind weniger als 100, eine Ziffer in der numerischen Codierung von Programm 2 verwendet zu speichern.Programm 2 wird im Allgemeinen mit Funktionsgleichungen der obersten Ebene (mit Ausnahme der letzten anonymen), Zeichenliteralen und Dezimalzahlen, Listen- / Bereichssyntax und Operatoren sowie den Quinedaten als Liste von Listen mit
Int
s am Ende geschrieben.Exemplarische Vorgehensweise, Programm 1
b
undc
sind die Werte der String-Literale für Programm 2 bzw. 1, die als letzte Argumente für den Lambda-Ausdruck angegeben werden.()
ist ein Scheinargument, das ausschließlich der PPCG-Regel entspricht, dass das Programm eine Funktion definieren soll.foldr(\a->map pred)b(show()>>c)
Dekodiert die Zeichenfolgeb
in den Kerncode von Programm 2, indem siemap pred
so oft angewendet wird, wie es der Länge vonshow()>>c == c++c
oder entspricht182
.tail(show c)
konvertiert die Zeichenfolgec
in den Kerncode von Programm 1, wobei ein abschließendes Anführungszeichen angehängt wird.:pure b
kombiniert dies in einer Liste mit der Zeichenfolgeb
.map(map fromEnum)$
konvertiert die Zeichenfolgen in Listen mit Codepunkten.`mappend`show(...)
serialisiert die resultierende Liste der Listen und hängt sie schließlich an den Kerncode von Programm 2 an.Exemplarische Vorgehensweise, Programm 2
z~z=[[['@','0'..]!!4..]!!z]
ist eine Funktion, die Codepunkte zurück in Zeichen konvertiert (zum Schreiben erforderlich, da nicht alle Zeichen intoEnum
verfügbar sind.)z
. Der Laziness-Marker~
hat in dieser Position keine Auswirkung, vermeidet jedoch ein Leerzeichen.['@','0'..]
ist ein Rückwärtsschrittlistenbereich, der mit dem ASCII-Code 64 beginnt und bei jedem Schritt um 16 nach unten springt.!!4
man sich darauf bezieht , erhält man einen\NUL
Charakter.[ ..]
Bereich einschließen, erhalten Sie eine Liste aller Zeichen, die!!z
indiziert werden.z
über Listen unter Verwendung=<<
der nicht verfügbarenmap
und<$>
.q[x,q]_=z=<<x++q++[34,34]++x
ist ein Funktionskonstruktionsprogramm 1 aus der Quinedatenliste.x
sind die Daten für den Kern von Programm 1 (einschließlich eines abschließenden doppelten Anführungszeichens) und die innerenq
sind die verschleierten Daten für den Kern von Programm 2._
ist ein weiteres Scheinargument, das ausschließlich dazu dient, die abschließende anonyme Funktion zu einer Funktion statt nur einer Zeichenfolge zu machen.x++q++[34,34]++x
Verkettet die Teile, einschließlich zweier doppelter Anführungszeichen mit ASCII-Code 34.z=<<
Erstellt Programm 1 durch Mappingz
über die Verkettung, um von Codepunkten in Zeichen zu konvertieren.q[[40,...]]
ist eine anonyme Funktion, dieq
mit den Quine-Daten kombiniert wird .quelle
Jelly ,
128 90 87 86 85 7916 + 32 = 48 BytesProbieren Sie es online!
Probieren Sie es online!
Das erste Programm führt Folgendes aus:
Dies belässt die Zeichenfolgen
79,7806,8318,7885,7769,338,115
undỌṘ
als die beiden Argumente der Kette und sie werden implizit verkettet und am Ende gedruckt.Das zweite Programm berechnet das
chr
(Ọ
) der Liste der zurückgegebenen ZahlenOṾ⁾ọṙŒs
.Ṙ
druckt“OṾ⁾ọṙŒs”
(mit Anführungszeichen) und gibt die Eingabe zurück, wobei“OṾ⁾ọṙŒs”OṾ⁾ọṙŒs
die vollständige Ausgabe erhalten bleibt.quelle
Gol> <> ,
23 + 23 = 4622 + 22 = 4420 + 20 = 40 BytesProbieren Sie es online!
Probieren Sie es online!
Überprüfen Sie es online!
Wie sie arbeiten
Nach Jo Kings> <> Antwort . Da es viel mehr alternative Befehle für Ausgabe und Wiederholung gab, war
g
oder nicht erforderlichp
, und die beiden Hauptkörper wurden viel kürzer.Ein weiterer Hauptunterschied ist, dass ich die Quote des Gegners direkt oben im Stapel erzeuge. Auf diese Weise war es etwas einfacher, die Invariante von beizubehalten
quote + my code + opponent code(reversed and shifted)
.quelle