Strahlengehärtetes Quine

39

Wie Sie (hoffentlich) wissen sollten, ist eine strahlungsgehärtete Quine eine Quine, mit der Sie ein beliebiges Zeichen aus der ursprünglichen, vormodifizierten Quelle entfernen und dennoch drucken können. Die Sache ist, mit den meisten von diesen können Sie nur ein Zeichen entfernen; sonst bricht alles zusammen. Hier kommt das ins Spiel; Ihr Ziel ist es, eine strahlenharte Quine zu bauen, die so viele Zeichen wie möglich entfernt. Jede Sprache, die den Regeln entspricht, ist in Ordnung.

Regeln

  • Das Programm muss mindestens ein Zeichen lang sein
  • Die verwendete Sprache muss vollständig sein (Sprachen wie HQ9 + sind daher nicht geeignet)
  • Alle anderen Regeln, die für normale Quines gelten, gelten auch hier.
  • Die Lösung mit dem geringsten , program_length^(2/n)in dem jeder Satz von genau nZeichen kann , während immer noch die ursprüngliche Quellcode gewinnt Druck entfernt werden.
takra
quelle
1
Ich versuche, eine Lösung zu finden Subleq. Ich denke, es wäre ideal für diese Art von Herausforderung!
Verbunden.
Martin Ender
Vielleicht den Namen ändern, da dies nicht mit einem durch Strahlung gehärteten Quin identisch ist? Vielleicht „Strahlungs- Beweis quine“?
Cyoce
@Cyoce Der einzige Unterschied, den ich feststellen kann, ist, dass diese Herausforderung für eine beliebige Anzahl von Umzügen gilt, während die meisten (wenn nicht alle) strahlengehärteten Quinen nur eine zulassen.
Takra
Ruby-Lösung aus der berühmten "Mame". github.com/mame/radiation-hardened-quine
mbomb007

Antworten:

57

Perl, 1116 - 1124 Bytes, n = 3, Score = 1124 ^ (2/3) oder ungefähr 108,1

Update : Ich habe jetzt überprüft, dass dies mit n = 3 über Brute Force funktioniert (was ein paar Tage gedauert hat); Mit einem Programm dieser Komplexität ist es schwierig, die Strahlungsbeständigkeit von Hand zu überprüfen (und ich habe in einer früheren Version einen Fehler gemacht, weshalb die Byteanzahl gestiegen ist). Update beenden

Ich empfehle, stderr an einen Ort umzuleiten, an dem Sie es nicht sehen. Dieses Programm gibt eine Menge Warnungen über zweifelhafte Syntax aus, auch wenn Sie keine Zeichen daraus löschen.

Möglicherweise kann das Programm gekürzt werden. Daran zu arbeiten ist ziemlich mühsam und macht es leicht, mögliche Mikrooptimierungen zu übersehen. Ich war hauptsächlich bestrebt, die Anzahl der löschbaren Zeichen so hoch wie möglich zu halten (da dies der wirklich herausfordernde Teil des Programms ist) und behandelte den Tiebreak als etwas, auf das ich gerne zielte, aber als etwas, das ich nicht setzen würde lächerlicher Optimierungsaufwand (aufgrund der Tatsache, dass es sehr leicht ist, den Strahlungswiderstand aus Versehen zu brechen).

Das Programm

Hinweis: _Unmittelbar vor jedem der vier Vorkommen von steht ein literales Steuerzeichen (ASCII 31) -+. Ich denke nicht, dass es korrekt in StackOverflow kopiert und eingefügt wurde, daher müssen Sie es erneut hinzufügen, bevor Sie das Programm ausführen.

eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;

Die Erklärung

Dieses Programm besteht ganz klar aus vier identischen kleineren Programmen, die zusammen verkettet sind. Die Grundidee ist, dass jede Kopie des Programms überprüft, ob es zu stark beschädigt wurde, um ausgeführt zu werden oder nicht. Wenn dies der Fall ist, wird nichts unternommen (außer möglicherweise Warnungen auszusprechen) und die nächste Kopie ausgeführt. Wenn dies nicht der Fall ist (dh keine Löschungen oder das Zeichen, das gelöscht wurde, hat keinen Einfluss auf die Funktionsweise des Programms), erledigt es seine Kleinigkeit (druckt den Quellcode des gesamten Programms aus; wobei jeder Teil eine Kodierung des gesamten Quellcodes enthält) und dann beendet wird (um zu verhindern, dass andere unbeschädigte Kopien den Quellcode erneut ausdrucken und so das Quine ruinieren, indem zu viel Text gedruckt wird).

Jedes Teil besteht wiederum aus zwei Teilen, die praktisch unabhängig voneinander funktionieren. ein äußerer Wrapper und ein interner Code. Als solche können wir sie separat betrachten.

Außenverpackung

Der äußere Umbruch besteht im Grunde genommen aus eval<+eval<+eval< ... >####>####...>###(plus ein paar Semikolons und Zeilenumbrüchen, deren Zweck ziemlich offensichtlich sein sollte), um sicherzustellen, dass die Teile des Programms getrennt bleiben, unabhängig davon, ob einige der Semikolons oder die Zeilenumbrüche vor ihnen gelöscht werden ). Das mag ziemlich einfach aussehen, ist aber in vielerlei Hinsicht subtil und der Grund, warum ich Perl für diese Herausforderung ausgewählt habe.

Schauen wir uns zunächst an, wie der Wrapper in einer unbeschädigten Kopie des Programms funktioniert. evalAnalysiert als integrierte Funktion, die ein Argument akzeptiert. Da ein Streit erwartet wird, handelt es sich +hier um einen Unary +(der Perl-Golfern inzwischen sehr vertraut ist; sie kommen überraschend oft als nützlich heraus). Wir erwarten immer noch ein Argument (wir haben gerade einen unären Operator gesehen), daher wird der <nächste als Beginn des <>Operators interpretiert (der keine Präfix- oder Postfix-Argumente akzeptiert und daher an der Operandenposition verwendet werden kann).

<>ist ein ziemlich komischer Operator. Der übliche Zweck besteht darin, Dateihandles zu lesen und den Namen des Dateihandles in spitze Klammern zu setzen. Wenn der Ausdruck als Dateiname nicht gültig ist, führt er alternativ einen Globbing-Vorgang aus (im Grunde derselbe Prozess, den UNIX-Shells verwenden, um vom Benutzer eingegebenen Text in eine Folge von Befehlszeilenargumenten zu übersetzen). Viel ältere Versionen von Perl werden tatsächlich verwendet die Shell dafür, aber heutzutage handhabt Perl das Globbing intern). Die beabsichtigte Verwendung ist daher in etwa so <*.c>, wie dies normalerweise bei einer Liste der Fall ist ("foo.c", "bar.c"). In einem skalaren Kontext (wie dem Argument zueval), gibt es nur den ersten Eintrag zurück, den es beim ersten Ausführen findet (das Äquivalent des ersten Arguments), und würde andere Einträge bei hypothetischen zukünftigen Läufen zurückgeben, die niemals vorkommen.

Heutzutage verarbeiten Shells häufig Befehlszeilenargumente. Wenn Sie so etwas wie -rohne Argumente angeben, wird es nur wörtlich an das Programm übergeben, unabhängig davon, ob es eine Datei mit diesem Namen gibt oder nicht. Perl verhält sich genauso, solange wir sicherstellen, dass zwischen dem <und dem Matching keine speziellen Zeichen für die Shell oder für Perl vorhanden sind >, können wir dies effektiv wie eine wirklich umständliche Form von String-Literalen verwenden. Noch besser ist, dass Perls Parser für zitatähnliche Operatoren zwangsweise dazu neigt, Klammern auch in Kontexten wie diesem zuzuordnen, in denen dies keinen Sinn macht, damit wir <>sicher nisten können (was die Entdeckung ist, die für dieses Programm erforderlich ist). Der Hauptnachteil all dieser verschachtelten Elemente <>besteht darin, dass sie dem Inhalt der Datei entkommen<>ist fast unmöglich; Es scheint, als ob es zwei Schichten mit jeweils einem Ausrutscher gibt. Um <>also etwas auf der Innenseite aller drei Schichten zu entkommen, müssen 63 Backslashes vorangestellt werden. Ich entschied, dass, obwohl die Codegröße bei diesem Problem nur eine untergeordnete Rolle spielt, es sich mit ziemlicher Sicherheit nicht lohnte, diese Art von Strafe für meine Punktzahl zu zahlen, und entschloss mich daher, den Rest des Programms ohne Verwendung der beleidigenden Zeichen zu schreiben.

Was passiert also, wenn Teile des Wrappers gelöscht werden?

  • Deletionen in dem Wort evalführen dazu, dass es sich in ein Barewort verwandelt , eine Zeichenfolge ohne Bedeutung. Perl mag diese nicht, aber es behandelt sie so, als wären sie von Anführungszeichen umgeben. so eal<+eval<+...wird interpretiert als"eal" < +eval<+.... Dies hat keine Auswirkung auf die Funktionsweise des Programms, da es im Grunde genommen nur das Ergebnis der stark verschachtelten Auswertungen (die wir sowieso nicht verwenden) nimmt, in eine Ganzzahl umwandelt und einige sinnlose Vergleiche anstellt. (Diese Art von Dingen verursacht eine Menge Spam-Warnungen, da dies unter normalen Umständen offensichtlich nicht sinnvoll ist. Wir verwenden sie nur, um Löschungen zu absorbieren.) Dies ändert die Anzahl der benötigten schließenden spitzen Klammern (weil die öffnende Klammer) wird jetzt stattdessen als Vergleichsoperator interpretiert), aber die Kette von Kommentaren am Ende stellt sicher, dass die Zeichenfolge sicher endet, unabhängig davon, wie oft sie verschachtelt ist. (Es gibt hier mehr #Zeichen als unbedingt erforderlich. Ich habe es so geschrieben, wie ich es getan habe, um das Programm komprimierbarer zu machen, sodass ich weniger Daten zum Speichern des Quines verwenden kann.)
  • Wenn a <gelöscht wird, wird der Code jetzt analysiert als eval(eval<...>). Die sekundäre Funktion außerhalb evalhat keine Auswirkung, da die Programme, die wir auswerten, nichts zurückgeben, was echte Auswirkungen als Programm hat Ausnahme, die evalzur Rückgabe einer Nullzeichenfolge oder exitzur Vermeidung einer Rückgabe führt).
  • Wenn ein +Code gelöscht wird, hat dies keine unmittelbare Auswirkung, wenn der nebenstehende Code intakt ist. unary +hat keine Auswirkung auf das Programm. (Der Grund, warum die Originale vorhanden +sind, besteht darin, dass sie zur Reparatur von Schäden beitragen. Sie erhöhen die Anzahl der Situationen, in denen <sie als unärer <>und nicht als relationaler Operator interpretiert werden. Dies bedeutet, dass Sie mehr Löschvorgänge benötigen, um ein ungültiges Programm zu erstellen.)

Der Wrapper kann durch genügend Löschvorgänge beschädigt werden. Sie müssen jedoch eine Reihe von Löschvorgängen ausführen, um etwas zu erzeugen, das nicht analysiert werden kann. Mit vier Löschungen können Sie dies tun:

eal<evl<eval+<...

und in Perl ist der Vergleichsoperator nicht <assoziativ, und daher wird ein Syntaxfehler angezeigt (derselbe, den Sie auch erhalten würden 1<2<3). Daher ist die Obergrenze für das geschriebene Programm n = 3. Das Hinzufügen weiterer unärer +s scheint eine vielversprechende Möglichkeit zu sein, um die Anzahl zu erhöhen. Da dies jedoch zu einer zunehmenden Wahrscheinlichkeit führen würde, dass auch das Innere des Wrappers beschädigt wird, kann die Überprüfung der Funktionsfähigkeit der neuen Version des Programms sehr schwierig sein.

Der Grund, warum der Wrapper so wertvoll ist, besteht darin, dass evalin Perl Ausnahmen abgefangen werden, z. B. die Ausnahme, die beim Kompilieren eines Syntaxfehlers auftritt. Da es evalsich um ein Zeichenfolgenliteral handelt, erfolgt die Kompilierung der Zeichenfolge zur Laufzeit. Wenn das Literal nicht kompiliert werden kann, wird die resultierende Ausnahme abgefangen. Dies führt evaldazu, dass eine Nullzeichenfolge zurückgegeben und der Fehlerindikator gesetzt wird. Dies $@wird jedoch auch nie überprüft (außer durch gelegentliches Ausführen der zurückgegebenen Nullzeichenfolge in einigen mutierten Versionen des Programms). Entscheidend ist, dass, wenn etwas mit dem Code im Inneren passieren sollteWenn der Wrapper einen Syntaxfehler verursacht, führt der Wrapper lediglich dazu, dass der Code nichts unternimmt (und das Programm wird weiter ausgeführt, um eine unbeschädigte Kopie von sich selbst zu finden). Daher muss der interne Code nicht annähernd so strahlungssicher sein wie der Wrapper. Alles, was uns interessiert, ist, dass wenn es beschädigt wird, es entweder identisch mit der unbeschädigten Version des Programms agiert oder abstürzt ( evalum die Ausnahme abzufangen und fortzufahren) oder normal beendet wird, ohne etwas zu drucken.

In der Hülle

Der Code im Wrapper sieht im Grunde so aus (wieder gibt es ein Control _, das Stack Exchange nicht sofort vor dem anzeigt -+):

eval+(q(...)=~y=A-Z=-+;-AZz-~=r)

Dieser Code ist vollständig mit glob-sicheren Zeichen geschrieben. Er soll ein neues Alphabet aus Interpunktionszeichen hinzufügen, das es ermöglicht, ein echtes Programm zu schreiben, indem ein String-Literal transliteriert und ausgewertet wird (wir können 'oder nicht "als Anführungszeichen verwenden) marks, aber q(... )ist auch eine gültige Möglichkeit, in Perl einen String zu bilden. (Der Grund für das nicht druckbare Zeichen ist, dass wir etwas in das Leerzeichen ohne ein Leerzeichen im Programm umwandeln müssen. Daher bilden wir einen Bereich, der mit ASCII 31 beginnt, und erfassen das Leerzeichen als zweites Element des Bereichs.) Natürlich, wenn wir einige Zeichen über Umschrift sind produzieren, müssen wir Zeichen opfern , sie zu transkribieren ausAber Großbuchstaben sind nicht sehr nützlich und es ist viel einfacher, ohne Zugriff auf diese zu schreiben, als ohne Zugriff auf Interpunktionszeichen.

Hier ist das Alphabet mit Interpunktionszeichen, die als Ergebnis des Globus verfügbar werden (die obere Zeile zeigt die Codierung, die untere Zeile das Zeichen, das codiert wird):

BCDEFGHIJKLMNOPQRSTUVWXYZ
 ! "# $% & '() * +; <=>? @ AZz {|} ~ 

Vor allem haben wir eine Reihe von Interpunktionszeichen, die nicht glob-sicher sind, aber beim Schreiben von Perl-Programmen zusammen mit dem Leerzeichen nützlich sind. Ich habe auch zwei Großbuchstaben gespeichert, das Literal Aund Z(die nicht für sich selbst, sondern für Tund codieren U, da dies Asowohl als Endpunkt für den oberen als auch für den unteren Bereich benötigt wurde). Dies ermöglicht es uns, die Transliterationsanweisung selbst unter Verwendung des neuen codierten Zeichensatzes zu schreiben (obwohl Großbuchstaben nicht so nützlich sind, sind sie nützlich, um Änderungen an den Großbuchstaben festzulegen). Die bemerkenswertesten Zeichen, die wir nicht zur Verfügung haben, sind [, \und ], aber keine werden benötigt (als ich eine neue Zeile in der Ausgabe brauchte, habe ich sie mit der impliziten Zeile von erzeugtsayanstatt schreiben zu müssen \n; chr 10hätte auch geklappt ist aber ausführlicher).

Wie üblich müssen wir uns Gedanken machen, was passiert, wenn das Innere des Wrappers außerhalb des String-Literal beschädigt wird. Ein korrupter evalverhindert, dass etwas läuft; Damit sind wir einverstanden. Wenn die Anführungszeichen beschädigt werden, ist das Innere der Zeichenfolge ungültig, und der Wrapper fängt sie ab (und die zahlreichen Subtraktionen für Zeichenfolgen bedeuten, dass sie selbst dann nichts bewirken würden, wenn Sie sie als gültige Perl-Zeichenfolge festlegen würden ist ein akzeptables Ergebnis). Schäden an der Umschrift, wenn es nicht ein Syntaxfehler ist, wird mangle die Zeichenfolge ausgewertet wird, in der Regel verursacht es einen Syntaxfehler zu werden; Ich bin nicht zu 100% sicher, dass es keine Fälle gibt, in denen dies bricht, aber ich bin mir im Moment sicher, dass es einfach genug sein sollte, es zu beheben, wenn es solche Fälle gibt.

Das verschlüsselte Programm

Wenn wir in das String-Literal schauen, die von mir verwendete Codierung umkehren und Leerzeichen hinzufügen, um die Lesbarkeit zu verbessern, erhalten wir Folgendes (stellen Sie sich erneut einen Kontroll-Unterstrich vor dem vor -+, der wie folgt codiert ist A):

$o=q<
  length$o  ==181 || zzzz((()));
  do {
    chop ($t = "eval+<"x4);
    $r = '=-+;-AZz-~=';
    $s = '$o=q<' . $o . '>;eval$o';
    eval '$s=~y' . $r . 'A-Z=';
    say "$t(q($s)=~y=A-Z${r}r)" . "####>"x6;
    say ";" for 1..4
  } for 1..4;
  exit>;
eval $o

Menschen, die an Quines gewöhnt sind, werden diese allgemeine Struktur erkennen. Der wichtigste Teil ist zu Beginn, wo wir überprüfen, ob $ o unbeschädigt ist. wenn Zeichen gelöscht wurden, wird seine Länge nicht überein 181, so dass wir laufen , zzzz((()))das, wenn es nicht ein Syntaxfehler ist auf nicht angepasste Klammern wird ein Laufzeitfehler, auch wenn Sie alle drei Zeichen löschen, weil keiner von zzzz, zzz, zz, und zist eine Funktion, und es gibt keine Möglichkeit, das Parsen als eine andere Funktion zu verhindern, als das Löschen (((und Verursachen eines offensichtlichen Syntaxfehlers. Der Scheck selbst ist außerdem unempfindlich gegen Beschädigungen. Das ||kann beschädigt werden, |aber das führt dazu, dass der zzzz((()))Anruf bedingungslos ausgeführt wird. Wenn Sie Variablen oder Konstanten beschädigen, führt dies zu einer Nichtübereinstimmung, da Sie Folgendes vergleichen 0:180, 179, 178Für die Gleichstellung zu einem gewissen Teil der Ziffern 181; Wenn Sie eins entfernen, =führt dies zu einem Analysefehler, und zwei führen =zwangsläufig dazu, dass die LHS entweder als Ganzzahl 0 oder als Null-Zeichenfolge ausgewertet wird, die beide falsch sind.

Update : Diese Überprüfung war in einer früheren Version des Programms etwas falsch, daher musste ich sie bearbeiten, um das Problem zu beheben. Die vorherige Version sah nach der Dekodierung so aus:

length$o==179||zzzz((()))

und es war möglich, die ersten drei Satzzeichen zu löschen, um dies zu erhalten:

lengtho179||zzz((()))

lengtho179ein Barwort zu sein, ist wahr und bricht den Scheck. Ich habe dies durch Hinzufügen von zwei zusätzlichen BZeichen (die Leerzeichen codieren) behoben , was bedeutet, dass die neueste Version des Quine dies tut:

length$o  ==181||zzzz((()))

Jetzt ist es unmöglich, sowohl die =Zeichen als auch das $Zeichen zu verbergen , ohne einen Syntaxfehler zu erzeugen. (Ich hatte zwei Räume hinzufügen , anstatt ein , weil eine Länge von 180einem wörtlichen setzen würde 0Charakter in die Quelle, die in diesem Zusammenhang auf ganzzahlige-Vergleich Null mit einem Bareword missbraucht werden könnte, was erfolgreich ist .) End - Update

Sobald die Längenprüfung bestanden ist, wissen wir, dass die Kopie unbeschädigt ist, zumindest was die Löschung von Zeichen betrifft. Von daher ist das Quining einfach (das Ersetzen von Satzzeichen aufgrund einer beschädigten Dekodierungstabelle würde bei dieser Prüfung nicht erfasst , aber ich habe bereits über Brute-Forcing , dass keine drei Deletionen von bestätigten nur vermutlich die meisten von ihnen Ursache Syntaxfehler), die Dekodierungstabelle brechen die quine. Wir haben $obereits eine Variable, also müssen wir nur die äußeren Wrapper fest (mit einigem Komprimierungsgrad; ich habe den Teil der Frage nicht ganz übersprungen ). Ein Trick ist, dass wir den Großteil der Codierungstabelle in speichern$r; Entweder können wir es buchstäblich drucken, um den Codierungstabellenabschnitt des inneren Wrappers zu generieren, oder wir können Code um ihn herum verketten und evalden Decodierungsprozess in umgekehrter Reihenfolge ausführen (um herauszufinden, wie die codierte Version von $ o lautet) (nur die decodierte Version ist zu diesem Zeitpunkt verfügbar).

Wenn wir eine intakte Kopie wären und somit das gesamte Originalprogramm ausgeben könnten, rufen wir exitauf, um zu verhindern, dass die anderen Kopien ebenfalls versuchen, das Programm auszudrucken.

Überprüfungsskript

Nicht sehr hübsch, aber es zu posten, weil jemand gefragt hat. Ich habe dies mehrere Male mit einer Vielzahl von Einstellungen ausgeführt (normalerweise geändert $minund $maxauf verschiedene Bereiche von Interesse überprüft). Es war kein vollautomatischer Prozess. Es hat die Tendenz, aufgrund der hohen CPU-Belastung an anderer Stelle nicht mehr zu laufen. In diesem Fall habe ich nur $minden ersten Wert geändert , der $xnicht vollständig überprüft wurde, und das Skript weiter ausgeführt (um sicherzustellen, dass alle Programme im Bereich schließlich überprüft wurden). Ich habe nur Löschungen von der ersten Kopie des Programms überprüft, da es ziemlich offensichtlich ist, dass Löschungen von den anderen Kopien nicht mehr können.

use 5.010;
use IPC::Run qw/run/;
undef $/;
my $program = <>;
my $min = 1;
my $max = (length $program) / 4 - 3;
for my $x ($min .. $max) {
    for my $y ($x .. $max) {
        for my $z ($y .. $max) {
            print "$x, $y, $z\n";
            my $p = $program;
            substr $p, $x, 1, "";
            substr $p, $y, 1, "";
            substr $p, $z, 1, "";
            alarm 4;
            run [$^X, '-M5.010'], '<', \$p, '>', \my $out, '2>', \my $err;
            if ($out ne $program) {
                print "Failed deleting at $x, $y, $z\n";
                print "Output: {{{\n$out}}}\n";
                exit;
            }
        }
    }
}

say "All OK!";

quelle
3
Das OP ist etwas mehrdeutig; aber ich dachte, die Punktzahl wäre (1116 * 1116) / 3.
Greg Martin
@ GregMartin: (1116 * 1116) / 3 ist 415152, daher würde dieser Eintrag unter diesen Umständen immer noch gewinnen. Ich glaube jedoch nicht, dass das OP dies bedeuten kann, da es kaum einen Anreiz bieten würde, die Entfernung mehrerer Zeichen zu handhaben. Diese Quine kann kürzer als die Hälfte der Länge sein, wenn Sie nur eine Zeichenentfernung benötigen. das würde mir eine effektive ÷ 4 für die Punktzahl geben, wenn wir es so interpretieren, was die ÷ 3, die ich von n = 3 erhalte, aufwiegen würde und somit bedeuten würde, dass die weniger interessanten n = 1 Einträge tatsächlich eine bessere Punktzahl sind.
2
Ich machte die Wertung klarer. Wie auch immer, das ist absolut unglaublich; Ich hätte nicht gedacht, dass irgendjemand n> 1
bekommt.
1
Es sagt etwas über Perl aus, dass es einfacher ist, ein Programm ohne Buchstaben als ohne Interpunktion zu schreiben
Robert Fraser
35

Befunge-98 , 884, n = 14, Punktzahl 2,636

f00f00f00f00f00f00f00f00f00f00f00f00f00f00f0xxxxxxxxxxxxxxx"""""""""""""""fffffffffffffff'''''''''''''''000000000000000\\\\\\\\\\\\\\\'''''''''''''''000000000000000\\\\\\\\\\\\\\\'''''''''''''''fffffffffffffff\\\\\\\\\\\\\\\111111111111111---------------:::::::::::::::!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!000000000000000aaaaaaaaaaaaaaa---------------bbbbbbbbbbbbbbb---------------***************jjjjjjjjjjjjjjj$$$$$$$$$$$$$$$'''''''''''''''+++++++++++++++kkkkkkkkkkkkkkk,,,,,,,,,,,,,,,333333333333333kkkkkkkkkkkkkkk$$$$$$$$$$$$$$$000000000000000{{{{{{{{{{{{{{{'''''''''''''''888888888888888uuuuuuuuuuuuuuu'''''''''''''''!!!!!!!!!!!!!!!111111111111111+++++++++++++++'''''''''''''''xxxxxxxxxxxxxxx###############;;;;;;;;;;;;;;;:::::::::::::::!!!!!!!!!!!!!!!kkkkkkkkkkkkkkk@@@@@@@@@@@@@@@dddddddddddddddkkkkkkkkkkkkkkk:::::::::::::::eeeeeeeeeeeeeeekkkkkkkkkkkkkkk,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;

Probieren Sie es online!

Dies funktioniert nicht nur, wenn Sie genau 14 Zeichen entfernen, sondern auch, wenn Sie einen beliebigen Betrag von bis zu 14 Zeichen entfernen .

n = 14mag wie eine sehr willkürliche Wahl erscheinen, aber die Technik, die ich verwendet habe, kann tatsächlich nur für strahlenhärtende Ordnungen von 1 bis 14 verwendet werden, aber nicht leicht darüber hinaus (es ist möglich, aber ich habe keine Ahnung, wie). Die Bestell-1-Quine ist lediglich 73 Byte groß (obwohl sie einige Golftricks verwendet, die für größere nicht gelten n):

200 20 xx""''ÈÈ..aa22**..33kk$$00{{''!!uu''!!11++''xx##;;::!!kk@@::,,,,;;

Erläuterung

Als ich an dieser Antwort arbeitete, stellte ich fest, dass es (2,0)mit dem folgenden Snippet möglich ist, das Delta des Befehlszeigers unter strahlungsgehärteten Bedingungen auf einzustellen :

20020xx

Lesen Sie diese Antwort, um herauszufinden, warum dies funktioniert. Ich fand das nur mit ein wenig Handarbeit, aber dies warf die Frage auf, ob es ähnliche Muster gibt, die robust sind, wenn mehrere Zeichen entfernt werden. Also schrieb ich ein kurzes Mathematica-Skript, um diese mit brachialer Gewalt zu suchen:

n = 14;
m = 4;
Print @ FromDigits @ {
      m + 1, 0, 
      ## & @@ ((m + 1) IntegerDigits[#, 2, n - 4]),
      m + 1, 0
} & /@ Select[
   Range[0, 2^(n - 4) - 1], 
   AllTrue[
     Subsets[{
         m + 1, 0, 
         ## & @@ ((m + 1) IntegerDigits[#, 2, n - 4]),
         m + 1, 0
       }, 
       {n - m, n - 1}
     ] //. {a___, _, m + 1} | {a___, 0, _} :> {a}, 
     MatchQ@{___, m + 1, 0}
  ] &
];

Dies ergab sehr schnell ein Muster. Um einen entsprechenden Code - Schnipsel zu erhalten, die für die Entfernung von bis funktioniert nZeichen, die Sie verwenden können , (m0x){n}m0wo mist n+1und xentweder moder 0. Für die Entfernung von bis zu zwei Zeichen würden also alle folgenden Funktionen funktionieren:

30030030
30030330
30330030
30330330

Ich bin mir sicher, dass es möglich ist, dies zu beweisen, aber ich habe es einfach auf nbis zu überprüft 7. Dies funktioniert natürlich nur, solange wir n+1eine einzelne Ziffer darstellen können, und die größte dieser Ziffern in Befunge 98 ist fdie Ziffer 15. Deshalb ist mein Ansatz auf beschränkt n = 14. Wenn jemand einen Weg findet, das Delta zuverlässig zu vergrößern n+1, ist es wahrscheinlich möglich, die Ordnung dieses strahlungsgehärteten Quins auf unbestimmte Zeit zu erhöhen.

Schauen wir uns den eigentlichen Code an. Grundsätzlich gibt es zwei Teile. Zuerst setzen wir das Delta auf, (15,0)wie ich gerade erwähnte:

f00f00f00f00f00f00f00f00f00f00f00f00f00f00f0xxxxxxxxxxxxxxx

Und der Rest des Codes hat jeden Befehl 15 Mal wiederholt und druckt die Quelle. Wenn wir die Wiederholung entfernen, sieht es so aus:

"f'0\'0\'f\1-:!!0a-b-*j$'+k,3k$0{'8u'!1+'x#;:!k@dk:ek,;

Das "ist ein Standard - 2D - quining Technik: es String - Modus startet, schiebt alle Zeichen (außer sich selbst) auf den Stapel und Enden String - Modus wieder nach Umwickeln. Dies hilft uns, alle Codepunkte der zweiten Hälfte zu erhalten, aber es wird uns nichts Nützliches aus der ersten Hälfte bringen, weil es während des gesamten f00f00...f0Bits nur zwei Zeichen aufzeichnet (die entweder foder 0abhängig davon, welche Zeichen gelöscht werden, sein können ). Da dieser Teil jedoch nicht aus Zeichen besteht, die 15 Mal wiederholt werden, müssen Sie ihn trotzdem separat drucken.

In dem unmodifizierten quine, die Länge der Saite bequeme, bevor das "ist -1 (mod 15). Dies garantiert, dass unabhängig von der Anzahl der Zeichen (bis zu 14), die wir entfernen, die Anzahl der dort aufgezeichneten Zeichen immer 3 beträgt (eins xund zwei von fund 0). Dies gilt tatsächlich für jede Strahlungsordnung bis zu 14.

Wir beginnen jetzt mit dem Drucken des f00f00...f0Teils:

f'0\'0\'f\1-:!!0a-b-*j$'+k,

f          Push 15, a loop counter.
'0\'0\'f\  Put "00f" underneath the loop counter.
1-         Decrement the loop counter.
:!!        Copy it, and turn it into a 1 if it's positive.
0a-b-      Push -21.
*          Multiply by 0 if the loop counter is zero, or by 1 otherwise.
j          Jump that many steps. If the value was 0, this is a no-op and
           the loop ends. Otherwise, this brings us back after the f.
$          Pop the loop counter (which is now 0).
'+k,       Print the top of the stack 43 times, which gives us all of
           the "f00f00...f0" and leaves one "0" on top of the stack.

Das nächste 3k$verwirft einfach das 0sowie die drei Zeichen, die von "Beginn des Programms an vorbeigeschoben wurden. Der Stapel enthält jetzt nur die Zeichen nach dem "sowie einige Junk-Dateien unter dem Original, f00f00...f0je nachdem, welche Zeichen gelöscht wurden.

Jetzt müssen wir nur noch den oberen Teil des Stapels umkehren (der die verbleibenden Zeichen enthält) und jeweils 15 Mal drucken.

0{     Start a new, empty stack. This pushes two zeros onto the original stack.
'8u    Move the top 56 values from the original stack to the new one, which
       is the 54 characters after the " as well as those two zeros. This is
       implemented as pop-push loop, so it reverses the order of those elements.
'!1+   Push a " by incrementing a !.
'x     Push an x. Now we've got all the characters that are repeated 15 times.
#;     Enter a loop. This is a standard technique for Befunge-98: the ; is
       a bit like a comment character, that ignores everything until the next
       ;, but we jump over the first one with #, so that from now on only
       the code inside will be executed (over and over).
  :!     Copy the top of the stack, and compute logical NOT (1 if 0, 0 otherwise).
  k@     Terminate the program that many times (i.e. when the top of the
         stack is zero).
  dk:    Make 14 copies of the top of the stack.
  ek,    Print 15 characters from the top of the stack.
;

Und das ist es. :)

Martin Ender
quelle
16

JavaScript (ES6), 927 Byte, n = 1, Score = 859329

Hinweis: Verwenden Sie keine REPL (wie eine Browserkonsole), um dies auszuführen.

Dies wurde geschrieben, bevor die Codelänge ein Faktor war, sodass noch kein Golf gespielt wird.

Das war sehr schwierig und verdient eine gründliche Erklärung. Was ich später schreiben werde, nachdem ich diese Herausforderung etwas genauer untersucht habe!

etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;
setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

hinweis: es gibt eine nachgestellte newline

Grundsätzlich ist die erste Zeile sorgfältig aufgebaut, um alle 'Rechtschreibfehler' setTimeoutin gültige Funktionen umzubenennen. Wenn ein Zeichen aus einem der setTimeouts entfernt wird, tritt kein Fehler im Code auf und die unbeschädigte Version kann ausgeführt werden. Es ist auch so geschrieben, dass, wenn ein Zeichen aus der ersten Zeile entfernt wird, kein Fehler auftritt und der Rest des Codes unbeeinträchtigt ausgeführt werden kann.

Der zweite und dritte Block sind genau gleichwertig. Wenn einer vollständig ausgeführt wird, wird die _Variable so festgelegt, dass der andere weiß, dass der Quine nicht dupliziert wird. Wenn einer dieser Blöcke fehlerfrei ist, hat dies keine Auswirkungen auf den anderen Block, da er asynchron mit aufgerufen wurde setTimeout. Der Fehler wird dazu führen, dass er _nicht gesetzt wird, so dass der andere Block erfolgreich quiniert wird. Der Hauptcode befindet sich in einer Zeichenfolge, die in jedem Block auf Länge überprüft wird, um sicherzustellen, dass keine Entfernungen vorgenommen wurden.

Vorlagenzeichenfolgen in der nächsten Zeile mit einigen Kommentaren am Ende der Vorlagenzeichenfolgen schützen den Code vor Fehlern, wenn einer der die Vorlagenzeichenfolge bildenden Backticks entfernt wird. Wenn das letzte Backtick entfernt wird, wird die Vorlagenzeichenfolge durch das Backtick im Kommentar beendet. Wenn das Start-Backtick entfernt wird, wird setTimeout als nicht zugewiesene Funktion (no-op) ausgewertet und der Code wird wie gewohnt ohne setTimeout ausgeführt. Das abschließende Backtick wird durch einen weiteren Kommentar aufgehoben.


Was sagst du? Du willst es ausprobieren? Sag nichts mehr!

Ganzseitenmodus empfohlen.

Ignorieren Sie das Eingabefeld, dieses Snippet nimmt keine Eingabe entgegen.

Versuchen Sie, ein beliebiges Zeichen aus dem Code zu entfernen!

Glaubst du es nicht? Normaler Code wird immer noch funktionieren (aber er wird nicht leiser ...) Versuchen Sie etwas wie console.log(5)!

Hinweis: Das Snippet musste geringfügig geändert werden, um die REPL-Funktion zu deaktivieren. Daher habe ich mehrere Ausgabefunktionen nur für diese Antwort entfernt.

etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;
setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`
<!--                               Try the test suite below!                              --><strong id="bytecount" style="display:inline; font-size:32px; font-family:Helvetica"></strong><strong id="bytediff" style="display:inline; margin-left:10px; font-size:32px; font-family:Helvetica; color:lightgray"></strong><br><br><pre style="margin:0">Code:</pre><textarea id="textbox" style="margin-top:5px; margin-bottom:5px"></textarea><br><pre style="margin:0">Input:</pre><textarea id="inputbox" style="margin-top:5px; margin-bottom:5px"></textarea><br><button id="testbtn">Test!</button><button id="resetbtn">Reset</button><br><p><strong id="origheader" style="font-family:Helvetica; display:none">Original Code Output:</strong><p><div id="origoutput" style="margin-left:15px"></div><p><strong id="newheader" style="font-family:Helvetica; display:none">New Code Output:</strong><p><div id="newoutput" style="margin-left:15px"></div><script type="text/javascript" id="golfsnippet">var bytecount=document.getElementById("bytecount");var bytediff=document.getElementById("bytediff");var textbox=document.getElementById("textbox");var inputbox=document.getElementById("inputbox");var testbtn=document.getElementById("testbtn");var resetbtn=document.getElementById("resetbtn");var origheader=document.getElementById("origheader");var newheader=document.getElementById("newheader");var origoutput=document.getElementById("origoutput");var newoutput=document.getElementById("newoutput");textbox.style.width=inputbox.style.width=window.innerWidth-50+"px";var _originalCode=null;function getOriginalCode(){if(_originalCode!=null)return _originalCode;var allScripts=document.getElementsByTagName("script");for(var i=0;i<allScripts.length;i++){var script=allScripts[i];if(script.id!="golfsnippet"){originalCode=script.textContent.trim();return originalCode}}}function getNewCode(){return textbox.value.trim()}function getInput(){try{var inputText=inputbox.value.trim();var input=eval("["+inputText+"]");return input}catch(e){return null}}function setTextbox(s){textbox.value=s;onTextboxChange()}function setOutput(output,s){output.innerHTML=s}function addOutput(output,data){output.innerHTML='<pre style="background-color:'+(data.type=="err"?"lightcoral":"lightgray")+'">'+escape(data.content)+"</pre>"}function getByteCount(s){return(new Blob([s],{encoding:"UTF-8",type:"text/plain;charset=UTF-8"})).size}function onTextboxChange(){var newLength=getByteCount(getNewCode());var oldLength=getByteCount(getOriginalCode());bytecount.innerHTML=newLength+" bytes";var diff=newLength-oldLength;if(diff>0){bytediff.innerHTML="(+"+diff+")";bytediff.style.color="lightcoral"}else if(diff<0){bytediff.innerHTML="("+diff+")";bytediff.style.color="lightgreen"}else{bytediff.innerHTML="("+diff+")";bytediff.style.color="lightgray"}}function onTestBtn(evt){origheader.style.display="inline";newheader.style.display="inline";setOutput(newoutput,"");setOutput(origoutput,"");var input=getInput();if(input===null){addOutput(origoutput,{type:"err",content:"Input is malformed. Using no input."});addOutput(newoutput,{type:"err",content:"Input is malformed. Using no input."});input=[]}doInterpret(getNewCode(),input,function(data){addOutput(newoutput,data)});doInterpret(getOriginalCode(),input,function(data){addOutput(origoutput,data)});evt.stopPropagation();return false}function onResetBtn(evt){setTextbox(getOriginalCode());origheader.style.display="none";newheader.style.display="none";setOutput(origoutput,"");setOutput(newoutput,"")}function escape(s){return s.toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}window.alert=function(){};window.prompt=function(){};function doInterpret(code,input,cb){var workerCode=interpret.toString()+";function stdout(s){ self.postMessage( {'type': 'out', 'content': s} ); }"+" function stderr(s){ self.postMessage( {'type': 'err', 'content': s} ); }"+" function kill(){ self.close(); }"+" self.addEventListener('message', function(msg){ interpret(msg.data.code, msg.data.input); });";var interpreter=new Worker(URL.createObjectURL(new Blob([workerCode])));interpreter.addEventListener("message",function(msg){cb(msg.data)});interpreter.postMessage({"code":code,"input":input});setTimeout(function(){interpreter.terminate()},1E4)}setTimeout(function(){getOriginalCode();textbox.addEventListener("input",onTextboxChange);testbtn.addEventListener("click",onTestBtn);resetbtn.addEventListener("click",onResetBtn);setTextbox(getOriginalCode())},100);function interpret(code,input){_=undefined;window={};alert=function(s){stdout(s)};window.alert=alert;console.log=alert;prompt=function(s){if(input.length<1)stderr("not enough input");else{var nextInput=input[0];input=input.slice(1);return nextInput.toString()}};window.prompt=prompt;(function(){try{_=undefined;eval(code);if(typeof evalResult=="disabled_function_evaluation"){var callResult=evalResult.apply(this,input);if(typeof callResult!="undefined")stdout(callResult)}}catch(e){stderr(e.message)}})()};</script>

Eine bessere Erklärung wird folgen. In der Zwischenzeit kannst du mich gerne im Chat @jrich anrufen, wenn du Kommentare / Fragen / Kritik hast!

jrich
quelle
ah okay, whoops: |
Downgoat
4
Verwenden Sie thisanstelle von window.
Mama Fun Roll
3
+1 für die Aufnahme des Sinns des Lebens in Ihren Quellcode
Cyoce