Ziel dieser Herausforderung ist es, (eventuell) jedes mögliche Stopp-Programm in einer Sprache Ihrer Wahl auszugeben . Das mag zunächst unmöglich klingen, aber Sie können dies mit einer sehr sorgfältigen Auswahl der Ausführungsreihenfolge erreichen.
Unten sehen Sie ein ASCII-Diagramm, um dies zu veranschaulichen. Lassen Sie die Spalten eine Nummerierung jedes möglichen Programms darstellen (jedes Programm ist eine endliche Anzahl von Symbolen aus einem endlichen Alphabet). Es sei jede Zeile ein einzelner Schritt bei der Ausführung dieses Programms. Eine X
Darstellung der Ausführung, die von diesem Programm zu diesem Zeitpunkt ausgeführt wurde.
step# p1 p2 p3 p4 p5 p6
1 X X X X X X
2 X X X X X
3 X X X X
4 X X X X
5 X X X
6 X X
7 X X
8 X X
9 X X
∞ X X
Wie Sie sehen, halten die Programme 2 und 4 nicht an. Wenn Sie sie einzeln ausführen, bleibt Ihr Controller in der Endlosschleife von Programm 2 stecken und gibt niemals Programme ab 3 aus.
Stattdessen verwenden Sie einen Verzahnungsansatz . Die Buchstaben stellen eine mögliche Ausführungsreihenfolge für die ersten 26 Schritte dar. Die *
s sind Stellen, an denen das Programm angehalten und ausgegeben wurde. Die .
s sind Schritte, die noch nicht ausgeführt wurden.
step# p1 p2 p3 p4 p5 p6
1 A C F J N R V
2 B E I M Q * Z
3 D H * P U
4 G L T Y
5 K O X
6 * S .
7 W .
8 . .
9 . .
∞ . .
Anforderungen an die Zielsprache
Die Zielsprache (die parallel gedolmetscht wird) muss Turing-vollständig sein. Ansonsten kann es sich um jede Sprache handeln, die Turing-vollständig ist, einschließlich Turing-vollständiger Untergruppen von viel größeren Sprachen. Sie können auch zyklische Tag-Systemregeln interpretieren. Sie können auch eine zu testende Sprache erstellen, sofern Sie nachweisen können, warum Turing vollständig ist.
Wenn Sie beispielsweise Brainfuck testen möchten, ist es am besten, nur die []-+<>
Teilmenge zu testen , da die Eingabe nicht unterstützt wird und die Ausgabe einfach weggeworfen wird (siehe unten).
Wenn es um das "Controller" -Programm (auf dem Sie Golf spielen) geht, gibt es keine besonderen Anforderungen. Es gelten die normalen Sprachbeschränkungen.
So erstellen Sie eine unendliche Liste von Programmen
Die Mehrheit der Programmiersprachen kann als eine Reihe von Symbolen aus einem endlichen Alphabet dargestellt werden. In diesem Fall ist es relativ einfach, eine Liste aller möglichen Programme in aufsteigender Reihenfolge aufzulisten. Das von Ihnen verwendete Alphabet sollte für die Anforderungen der Zielsprache repräsentativ sein . In den meisten Fällen ist dies druckbares ASCII. Wenn Ihre Sprache zusätzlich Unicode unterstützt, sollten Sie nicht jede mögliche Kombination von Unicode-Zeichen testen, sondern nur ASCII. Wenn Ihre Sprache nur verwendet []-+<>
, testen Sie die verschiedenen Kombinationen von "Kommentar" -ASCII-Zeichen nicht. Sprachen wie APL hätten ihre eigenen speziellen Alphabete.
Wenn Ihre Sprache nicht alphabetisch beschrieben werden kann, wie z. B. Fractran oder Turing Machines, gibt es andere gleichermaßen gültige Methoden, um eine Liste aller möglichen gültigen Programme zu erstellen.
Interpretation einer ständig wachsenden Liste von Programmen
Der Schlüssel zu dieser Herausforderung besteht darin, einen parallelen Interpreter für eine wachsende Liste von Programmen zu schreiben. Hierfür gibt es einige grundlegende Schritte:
- Fügen Sie der Liste eine endliche Anzahl von Programmen hinzu
- Interpretieren Sie jedes Programm auf der Liste für einen begrenzten Zeitraum einzeln. Dies kann erreicht werden, indem für jeden Befehl ein Schritt ausgeführt wird. Speichern Sie alle Zustände.
- Entfernen Sie alle terminierenden / fehlerauslösenden Programme aus der Liste
- Die sauber gestoppten * Programme ausgeben
- Fügen Sie der Liste weitere Programme hinzu
- Simulieren Sie nacheinander jedes Programm und nehmen Sie die Ausführung älterer Programme dort auf, wo sie aufgehört haben
- Entfernen Sie alle terminierenden / fehlerauslösenden Programme aus der Liste
- Die sauber gestoppten * Programme ausgeben
- wiederholen
* Sie sollten nur Programme ausgeben, die sauber anhalten. Dies bedeutet, dass während der Ausführung keine Syntaxfehler oder nicht erfassten Ausnahmen aufgetreten sind. Programme, die zur Eingabe auffordern, sollten ebenfalls beendet werden, ohne sie auszugeben. Wenn ein Programm eine Ausgabe erzeugt, sollten Sie es nicht beenden, sondern einfach die Ausgabe wegwerfen.
Weitere Regeln
- Sie dürfen keine neuen Threads erzeugen, um die getesteten Programme zu enthalten, da dies die Parallelisierungsarbeit auf das Host-Betriebssystem / andere Software verlagert.
- Bearbeiten: Um potenzielle zukünftige Lücken zu schließen, dürfen Sie keinen
eval
Teil des Codes des getesteten Programms (oder einer verwandten Funktion) . Sie könneneval
einen Codeblock aus dem Interpretercode erstellen. (Die BF-in-Python-Antwort ist nach diesen Regeln weiterhin gültig.) - Das ist Code-Golf
- Die Sprache, in der Sie Ihren Beitrag verfassen, muss nicht mit der Sprache übereinstimmen, die Sie testen / ausgeben.
- Sie sollten davon ausgehen, dass Ihr verfügbarer Speicher unbegrenzt ist.
- Wenn Sie die Turing-Vollständigkeit nachweisen, können Sie davon ausgehen, dass die Eingabe fest im Programm codiert ist und die Ausgabe aus dem internen Status des Programms gelesen werden kann.
- Wenn Ihr Programm sich selbst ausgibt, ist es wahrscheinlich falsch oder polyglott.
quelle
"If your program outputs itself, it is probably wrong or a polyglot."
Antworten:
subleq OISC in Python,
317269 Byteshttps://esolangs.org/wiki/Subleq
Ein subleq-Programm ist eine erweiterbare Liste von ganzen Zahlen (p) und ein Befehlszeiger (i). Diese Subleq-Variante verwendet eine relative Adressierung, die laut Wiki-Diskussionsseite erforderlich ist, um die Vollständigkeit mit begrenzten Werten zu gewährleisten. Bei jedem Häkchen wird die Operation
p[i+p[i+1]]-=p[i+p[i]]
ausgeführti+=p[i+2]
, andernfalls, wenn das Operationsergebnis <= 0 wari+=3
. Wenn ich jemals negativ ist, stoppt das Programm.Diese Implementierung testet jedes Programm, dessen Anfangszustand aus einstelligen nicht negativen ganzen Zahlen (0-9) mit einem Anfangsanweisungszeiger von 0 besteht.
Die Ausgabe ist aus Golfgründen umgekehrt. Die obige Spezifikation könnte in umgekehrter Reihenfolge angepasst werden, würde dann aber nicht mit dem in der Implementierung verwendeten Code übereinstimmen, sodass ich sie nicht so beschrieben habe.
BEARBEITEN: Das erste Programm, das ein einfaches, unbegrenztes Wachstum aufweist, ist 14283, das den Wert an Speicherstelle 6 dekrementiert und alle drei Ticks eine explizite 0 (im Gegensatz zur impliziten 0 in jeder Zelle) in die nächste negative Zelle schreibt.
quelle
Bitweises zyklisches Tag in CJam,
98878477 ByteDa dies eine Endlosschleife ist, können Sie dies nicht direkt im Online-Interpreter testen. Allerdings ist hier eine alternative Version , die die Anzahl der Iterationen von STDIN liest für Dich zu spielen , um. Zum Testen des vollständigen Programms benötigen Sie den Java-Interpreter .
BCT ist eine minimalistische Variante von Cyclic Tag Systems . Ein Programm wird durch zwei binäre Zeichenfolgen definiert: eine (zyklische) Anweisungsliste und einen Anfangszustand. Um das Drucken der Programme zu vereinfachen, habe ich meine eigene Notation definiert: Jede der Zeichenfolgen wird als ein Array von Ganzzahlen im CJam-Stil angegeben, und das gesamte Programm ist
[[...]]
zIch lasse auch leere Anfangszustände oder leere Anweisungslisten nicht zu.
Anweisungen in BCT werden wie folgt interpretiert:
0
, entfernen Sie das führende Bit aus dem aktuellen Status.1
, lesen Sie ein weiteres Bit aus der Anweisungsliste und nennen Sie esX
. Wenn das führende Bit des aktuellen Status ist1
, hängen Sie esX
an den aktuellen Status an, andernfalls tun Sie nichts.Wenn der aktuelle Status jemals leer wird, wird das Programm angehalten.
Die ersten Stoppprogramme sind
Wenn Sie mehr sehen möchten, lesen Sie die Version in dem Online-Interpreter, den ich oben verlinkt habe.
Erläuterung
So funktioniert der Code. Um den Überblick über die Verzahnung zu behalten, haben wir immer ein Array auf dem Stapel, das alle Programme enthält. Jedes Programm ist ein Paar einer internen Darstellung des Programmcodes (ähnlich
[[0 1 0] [1 0]]
) sowie des aktuellen Status des Programms. Wir werden nur die letztere verwenden, um die Berechnung durchzuführen, aber wir müssen uns die erstere merken, um das Programm zu drucken, sobald es anhält. Diese Programmliste wird einfach mit einem leeren Array initialisiertL
.Der Rest des Codes ist eine Endlosschleife,
{...1}g
die dieser Liste zunächst ein oder mehrere Programme hinzufügt und für jedes Programm einen Schritt berechnet. Programme, die anhalten, werden gedruckt und aus der Liste entfernt.Ich zähle die Programme durch Aufzählen einer Binärzahl auf. Die führende Ziffer wird entfernt, um sicherzustellen, dass wir auch alle Programme mit führenden Nullen erhalten können. Für jede solche verkürzte Binärdarstellung schiebe ich ein Programm für jede mögliche Aufteilung zwischen Anweisungen und Anfangszustand. Befindet sich der Zähler aktuell auf
42
, ist seine Binärdarstellung101010
. Wir werden das Führen los1
und schieben alle nicht leeren Teilungen:Da wir keine leeren Anweisungen oder Zustände wollen, starten wir den Zähler bei 4, was ergibt
[[[0] [0]]]
. Diese Aufzählung erfolgt mit folgendem Code:Der Rest des Codes ordnet der Programmliste einen Block zu, der einen Schritt der BCT-Berechnung für die zweite Hälfte dieser Paare ausführt und das Programm entfernt, wenn es anhält:
quelle
Brainfuck in Python, 567 Bytes
Eine relativ einfache Lösung, da Brainfuck kaum die schwierigste Sprache ist, für die ein Dolmetscher geschrieben werden kann.
Bei dieser Implementierung von Brainfuck darf der Datenzeiger ab 0 nur einen positiven Wert annehmen (wird als Fehler gewertet, wenn versucht wird, nach links von 0 zu springen). Die Datenzellen können Werte von 0 bis 255 annehmen und umbrechen. Die 5 gültigen Anweisungen sind
><+[]
(-
ist aufgrund der Verpackung nicht erforderlich).Ich denke, die Ausgabe ist jetzt in Ordnung, es ist jedoch schwierig, sicherzugehen, dass alle möglichen Lösungen gedruckt werden, sodass mir möglicherweise einige fehlen.
Die ersten paar Ergebnisse:
Und eine Liste der ersten 2000: http://pastebin.com/KQG8PVJn
Und zum Schluss eine Liste der ersten 2000 Ausgaben mit
[]
darin: http://pastebin.com/iHWwJprs(alle anderen sind trivial, solange sie gültig sind)
Beachten Sie, dass die Ausgabe nicht in einer sortierten Reihenfolge erfolgt, obwohl dies bei vielen von ihnen der Fall sein kann, da die länger dauernden Programme später gedruckt werden.
quelle
[-]
als auch das[+]
sollte auf jeden Fall erscheinen, da der Inhalt der Schleife einfach übersprungen wird (kein Umbruch erforderlich).[-]
und[+]
war ein Fehler, der jetzt behoben werden sollte und ich habe mit den Einstellungen aktualisiert.
? Es ist nicht notwendig, eine Turing-vollständige Teilmenge von BF zu erstellen, und die Ausgabe sollte sowieso ignoriert werden. Da Sie die Zellenwerte umschließen, brauchen Sie meines Erachtens nur eines von-
und+
.Schrägstriche in Python,
640498 Byteshttps://esolangs.org/wiki////
Ein Schrägstrich-Programm ist eine Zeichenfolge, die in diesem Interpreter auf die Zeichen '/' und '\' beschränkt ist. In dieser Implementierung ist / '1' und \ '0', um unter Verwendung von Pythons bin (x) etwas Golf zu spielen. Wenn der Interpreter auf ein \ stößt, wird das nächste Zeichen ausgegeben und beide Zeichen werden entfernt. Wenn es auf ein / stößt, sucht es nach Such- und Ersetzungsmustern als / search / replace /, wobei es maskierte Zeichen in die Muster einschließt (\\ steht für \ und \ / steht für /). Diese Ersetzungsoperation wird dann wiederholt an der Zeichenfolge ausgeführt, bis die Suchzeichenfolge nicht mehr vorhanden ist, und dann wird die Interpretation von vorne fortgesetzt. Das Programm wird angehalten, wenn es leer ist. Ein Programm wird abgebrochen, wenn eine nicht geschlossene Menge von / Mustern oder ein \ ohne Zeichen dahinter steht.
quelle
Treehugger in Java,
1.2991.2571.2511.2071.2031.2011.1931.189 Bytesquelle
Brachylog → Korrespondenzproblem posten , 10 Bytes
Probieren Sie es online!
Funktion, die als Generator alle möglichen Post-Korrespondenz-Probleme generiert, für die brachiale Lösungen möglicherweise nicht mehr funktionieren. (Brute-Forcing-Lösungen für das Post-Korrespondenz-Problem sind bekanntermaßen eine Turing-Complete-Operation.) Die TIO-Verknüpfung enthält einen Header, der einen Generator in ein vollständiges Programm umwandelt und jede Ausgabe sofort druckt, wenn sie generiert wird (also wenn TIO beendet wird) Da das Programm mehr als 60 Sekunden Ausführungszeit in Anspruch nimmt, ist die bisher erzeugte Ausgabe sichtbar.
Hierbei wird eine Formulierung des Problems verwendet, bei der die Zeichenfolgen als Ziffernfolgen angegeben werden, führende Nullen nur für sich
0
selbst zulässig sind , Lösungen für das Problem mit führenden Nullen nicht akzeptiert werden und eine Ziffernfolge als Zahl dargestellt werden kann oder minus der Zahl. Dies hat natürlich keine Auswirkung auf die Vollständigkeit der Sprache (da für die Verwendung der Ziffer Null überhaupt kein Post-Korrespondenz-Problem erforderlich ist).Dieses Programm generiert alle möglichen Lösungen für Probleme und arbeitet dann rückwärts, um die ursprünglichen Programme zu finden, die von ihnen gelöst wurden. Als solches kann ein einzelnes Programm viele Male ausgegeben werden. Es ist unklar, ob dies die Antwort ungültig macht oder nicht. Beachten Sie, dass alle angehaltenen Programme mindestens einmal ausgegeben werden (in der Tat unendlich oft, da jedes Programm, das Lösungen enthält, unendlich viele Lösungen hat), und dass nicht angehaltene Programme niemals ausgegeben werden.
Erläuterung
quelle
"Lila ohne E / A" in Ceylon, 662
Lila ist eine sich selbst modifizierende Ein-Instruktions-Sprache, die hier interpretiert werden sollte . Als Ein- und Ausgabe für diese Aufgabe nicht relevant ist, entfernte ich die
o
Bedeutung des Symbols aus dem Dolmetscher, so dass die (potentiell) gültigen Symbole sind nura
,b
,A
,B
,i
und1
(der letzte nur zum Lesen, nicht zum Schreiben).Da Purple sich jedoch selbst modifiziert (und seinen Quellcode als Daten verwendet), sind möglicherweise auch Programme nützlich, die andere Zeichen als diese enthalten. Daher habe ich mich dafür entschieden, alle druckbaren ASCII-Zeichen (ohne Leerzeichen) im Code zuzulassen (möglicherweise auch andere) nützlich, aber nicht so einfach zu drucken).
(Sie können den Interpreter so ändern, dass er stattdessen eine Zeichenfolge zulässiger Zeichen als Befehlszeilenargument verwendet - wechseln Sie die
a
unten definierte Kommentarzeile . Die Länge wird dann zu 686 Byte.)Mein "paralleler" Interpreter erzeugt daher alle endlichen Zeichenfolgen aus diesen Zeichen (in zunehmender Länge und lexikografischer Reihenfolge) und probiert jede einzelne aus.
Purple stoppt immer dann fehlerfrei, wenn der Befehl, der zur Ausführung vom Band gelesen werden soll, ungültig ist - daher gibt es keine ungültigen und viele, viele haltende Programme. (Die meisten halten bereits im ersten Schritt an, nur einige der Programme mit der Länge 3 kommen zum zweiten Schritt (und halten dann an), die ersten, die nicht anhalten, haben die Länge 6.
Ich denke, das allererste Non-Stop-Programm in der Reihenfolge, die mein Interpreter ausprobiert, ist das
aaaiaa
, das im ersten Schritt das setzta
Register auf 0 setzt (was es bereits war), und der zweite und jeder folgende Schritt setzt den Befehlszeiger zurück auf 0. veranlassen, dass esiaa
erneut ausgeführt wird.Ich habe einen Teil des Codes, der für meinen Interpreter von "Standard" Purple geschrieben wurde, wieder verwendet , , aber aufgrund des Wegfalls von Eingabe und Ausgabe wird mein paralleler Interpreter sogar etwas kürzer, während die zusätzliche Logik zum gleichzeitigen Ausführen mehrerer Programme enthalten ist.
Hier ist eine kommentierte und formatierte Version:
quelle
SK-Kombinator-Kalkül in Haskell , 249 Bytes
Probieren Sie es online!
Wie es funktioniert
Die Call-by-Value-Bewertungsregeln für die SK-Kombinatorrechnung lauten wie folgt:
(a) S xyz ≤ xz ( yz ) für x , y , z in normaler Form;
(b) K xy ↦ x für x , y in normaler Form;
(c) xy ≤ x ' y , wenn x ≤ x ' ist;
(d) xy ↦ xy 'für x in normaler Form, wenn y ↦ y' .
Da wir nur daran interessiert sind, das Verhalten zu stoppen, erweitern wir die Sprache geringfügig, indem wir ein Symbol H einfügen, das nicht in normaler Form vorliegt, für das jedoch alle normalen Formen „auswerten“:
(a) S xyz ≤ xz ( yz ), z x , y , z in normaler Form;
(b ′) K x H ≤ x für x in normaler Form;
(c) xy ≤ x ' y , wenn x ≤ x ' ist;
(d) xy ≤ xy 'für x in normaler Form, wenn y ≤ y' ist ;
(e) SH;
(f) K ≤ H;
(g) SH ≤ H;
(h) KH ≤ H;
(i) SHH ↦ H.
Wir betrachten jede Anwendung H x als Laufzeitfehler und behandeln sie als Endlosschleife. Wir ordnen Auswertungen so an, dass durch (e) - (i) kein H erzeugt wird, außer in einem Kontext, in dem es auftreten wird ignoriert (oberste Ebene, beliebiges K x ☐, beliebiges ignoriertes K☐, beliebiges ignoriertes S x x für x in normaler Form, beliebiges ignoriertes S☐H). Auf diese Weise beeinflussen wir nicht das Stoppverhalten der üblichen Begriffe, denen H fehlt.
Die Vorteile dieser modifizierten Regeln sind, dass jeder normalisierbare Term einen eindeutigen Bewertungspfad zu H hat und dass jeder Term eine endliche Anzahl möglicher Vorbilder unter ↦ hat. Anstatt also den Schwalbenschwanz-Ansatz zu verwenden, können wir alle umgekehrten Auswertungspfade von H weitaus effizienter als bisher durchsuchen.
n
prüft, ob ein Begriff in normaler Form vorliegt,f
findet alle möglichen Vorbilder eines Begriffs undl
ist eine träge unendliche Liste normalisierbarer Begriffe, die bei der Breitensuche von H erstellt wurden.quelle