Quine indurito per radiazione


39

Come dovresti (si spera) sapere, un quine indurito per radiazione è un quine da cui puoi rimuovere qualsiasi carattere e stampare comunque la sua fonte originale e pre-modificata. Il fatto è che con la maggior parte di questi puoi rimuovere solo un personaggio; altrimenti tutto si rompe. È qui che entra in gioco; il tuo obiettivo è quello di costruire un quine temprato dalle radiazioni che possa prendere il maggior numero possibile di rimozioni di personaggi. Qualsiasi lingua conforme alle regole va bene.

Regole

  • Il programma deve contenere almeno un carattere
  • La lingua utilizzata deve essere completa (quindi lingue come HQ9 + non si qualificano)
  • Tutte le altre regole che si applicano ai quines normali si applicano anche qui.
  • Vince la soluzione con il minimo program_length^(2/n)in cui è possibile rimuovere qualsiasi set di ncaratteri esatti mentre si continua a stampare il codice sorgente originale.

1
Sto cercando di trovare una soluzione Subleq. Penso che sarebbe l'ideale per questo tipo di sfida!


Forse cambi il nome, dato che questo non è lo stesso di un quine indurito per radiazione? Forse " quine a prova di radiazione "?
Cyoce,

@Cyoce L'unica differenza che posso dire è che questa sfida è per qualsiasi numero di rimozioni, mentre la maggior parte (se non tutte) altre quine temprate dalle radiazioni ne consentono solo una.
Takra,

Soluzione rubina dal famoso "mame". github.com/mame/radiation-hardened-quine
mbomb007,

Risposte:


57

Perl, 1116 1124 byte, n = 3, punteggio = 1124 ^ (2/3) o circa 108,1

Aggiornamento : ora ho verificato che funziona con n = 3 tramite forza bruta (che ha richiesto un paio di giorni); con un programma così complesso, è difficile verificare manualmente la resistenza alle radiazioni (e ho fatto un errore in una versione precedente, motivo per cui il conteggio dei byte è aumentato). Termina aggiornamento

Consiglio di reindirizzare stderr da qualche parte per non vederlo; questo programma produce un sacco di avvertimenti sulla sintassi dubbia anche quando non si eliminano i caratteri da esso.

È possibile che il programma possa essere abbreviato. Lavorare su questo è abbastanza doloroso, rendendo facile perdere possibili micro-ottimizzazioni. Miravo principalmente a ottenere il numero di personaggi eliminabili il più alto possibile (perché questa è la parte davvero impegnativa del programma) e ho trattato il tiebreak del come qualcosa che era bello puntare ma come qualcosa che non avrei messo ridicolo sforzo di ottimizzazione (sulla base del fatto che è molto facile rompere la resistenza alle radiazioni per caso).

Il programma

Nota: c'è un letterale Control- _character (ASCII 31) immediatamente prima di ciascuna delle quattro occorrenze di -+. Non credo che sia stato copiato e incollato correttamente su StackOverflow, quindi dovrai aggiungerlo nuovamente prima di eseguire il programma.

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)####>####>####>####>####>####>
;
;
;
;

La spiegazione

Questo programma è, chiaramente, composto da quattro programmi identici più piccoli concatenati insieme. L'idea di base è che ogni copia del programma verificherà se è stata danneggiata troppo male per l'esecuzione o meno; se lo è stato, non farà nulla (tranne che eventualmente sputare avvisi) e consentirà l'esecuzione della copia successiva; se non lo è stato (ovvero nessuna eliminazione, o il carattere che è stato eliminato è stato uno che non fa alcuna differenza per il funzionamento del programma), farà la sua parte (stampare il codice sorgente del programma completo; questo è un vero quine, con ciascuna parte contenente una codifica dell'intero codice sorgente) e quindi uscire (impedendo a qualsiasi altra copia non danneggiata di stampare nuovamente il codice sorgente e rovinando così la riga stampando troppo testo).

Ogni parte è a sua volta composta da due parti che sono effettivamente funzionalmente indipendenti; un wrapper esterno e un codice interno. Pertanto, possiamo considerarli separatamente.

Involucro esterno

Il wrapper esterno è, fondamentalmente, eval<+eval<+eval< ... >####>####...>###(più un gruppo di punti e virgola e di nuove righe il cui scopo dovrebbe essere piuttosto ovvio; è garantire che le parti del programma rimangano separate indipendentemente dal fatto che alcuni punti e virgola o le nuove righe prima di loro, vengano eliminati ). Potrebbe sembrare abbastanza semplice, ma è sottile in vari modi e il motivo per cui ho scelto Perl per questa sfida.

Innanzitutto, vediamo come funziona il wrapper in una copia non danneggiata del programma. evalanalizza come una funzione integrata, che accetta un argomento. Poiché è atteso un argomento, +ecco un unario +(che ormai sarà molto familiare ai golfisti del Perl; si rivelano utili sorprendentemente spesso). Stiamo ancora aspettando un argomento (abbiamo appena visto un operatore unario), quindi quello <che viene dopo viene interpretato come l'inizio <>dell'operatore (che non accetta argomenti prefisso o postfisso, e quindi può essere utilizzato in posizione di operando).

<>è un operatore abbastanza strano. Il suo solito scopo è quello di leggere filehandle, e si posiziona il nome filehandle all'interno le parentesi angolari. In alternativa, se l'espressione non è valida come nome di filehandle, fa globbing (fondamentalmente, lo stesso processo utilizzato dalle shell UNIX per tradurre il testo immesso dall'utente in una sequenza di argomenti della riga di comando; in realtà sono state utilizzate versioni molto più vecchie di Perl il guscio per questo, ma al giorno d'oggi Perl gestisce i globbing internamente). L'uso previsto, pertanto, è sulla falsariga di <*.c>, che in genere restituisce un elenco simile ("foo.c", "bar.c"). In un contesto scalare (come l'argomento aeval), restituisce solo la prima voce che trova la prima volta che viene eseguita (l'equivalente del primo argomento) e restituisce altre voci su ipotesi future esecuzioni che non si verificano mai.

Ora, le shell spesso gestiscono argomenti da riga di comando; se dai qualcosa del genere -rsenza argomenti, verrà semplicemente passato al programma alla lettera, indipendentemente dal fatto che esista o meno un file con quel nome. Perl agisce allo stesso modo, quindi finché ci assicuriamo che non ci siano caratteri speciali per la shell o per il Perl tra la <e la corrispondenza >, possiamo effettivamente usarlo come una forma davvero imbarazzante di stringa letterale. Ancora meglio, il parser di Perl per operatori simili a virgolette ha una tendenza compulsiva a far combaciare parentesi anche in contesti come questo dove non ha senso, quindi possiamo nidificare in <>sicurezza (che è la scoperta necessaria affinché questo programma sia possibile). Il principale svantaggio di tutti questi nidificati <>è che sfuggire al contenuto di<>è quasi impossibile; sembra che ci siano due livelli di non-escape con ciascuno <>, quindi per sfuggire a qualcosa all'interno di tutti e tre, deve essere preceduto da 63 barre rovesciate. Ho deciso che anche se la dimensione del codice è solo una considerazione secondaria in questo problema, quasi sicuramente non valeva la pena pagare questo tipo di penalità per il mio punteggio, quindi ho deciso di scrivere il resto del programma senza usare i caratteri offensivi.

Cosa succede se parti del wrapper vengono eliminate?

  • Le eliminazioni nella parola fanno evalsì che si trasformi in una parola nuda , una stringa senza significato. Al Perl non piacciono questi, ma li tratta come se fossero circondati da virgolette; quindi eal<+eval<+...viene interpretato come"eal" < +eval<+.... Questo non ha alcun effetto sul funzionamento del programma, perché fondamentalmente sta solo prendendo il risultato dagli evalidi fortemente annidati (che non usiamo comunque), lanciandolo su un numero intero e facendo inutili confronti su di esso. (Questo genere di cose provoca molti avvisi di spam in quanto chiaramente non è una cosa utile da fare in circostanze normali; lo stiamo solo usando per assorbire le eliminazioni.) Questo cambia il numero di parentesi angolari di chiusura di cui abbiamo bisogno (perché la parentesi aperta viene ora interpretato come un operatore di confronto), ma la catena di commenti alla fine assicura che la stringa finisca in modo sicuro, indipendentemente da quante volte è nidificata. (Ci sono più #segni di quelli strettamente necessari qui; l'ho scritto come ho fatto per rendere il programma più comprimibile, permettendomi di usare meno dati per memorizzare i quine.)
  • Se un <viene eliminato, il codice ora analizza come eval(eval<...>). Il secondario, esterno, non evalha alcun effetto, perché i programmi che stiamo valutando non restituiscono nulla che abbia effetti reali come programma (se ritornano normalmente, è normalmente una stringa nulla o una parola nuda; più comunemente ritornano via eccezione, che causa la evalrestituzione di una stringa nulla o l'utilizzo exitper evitare la restituzione).
  • Se +viene eliminato, ciò non ha effetto immediato se il codice adiacente è intatto; unario +non ha alcun effetto sul programma. (Il motivo degli originali +è quello di aiutare a riparare i danni; aumentano il numero di situazioni in cui <viene interpretato come unario <>piuttosto che come un operatore relazionale, il che significa che sono necessarie più eliminazioni per produrre un programma non valido.)

Il wrapper può essere danneggiato con abbastanza eliminazioni, ma è necessario eseguire una serie di eliminazioni per produrre qualcosa che non analizza. Con quattro eliminazioni, puoi farlo:

eal<evl<eval+<...

e in Perl, l'operatore relazionale <non è associativo e quindi si ottiene un errore di sintassi (lo stesso con cui si otterrebbe 1<2<3). Pertanto, il limite per il programma come scritto è n = 3. L'aggiunta di più unari +sembra un modo promettente per aumentarlo, ma poiché ciò renderebbe sempre più probabile che anche l'interno del wrapper possa rompersi, verificare che la nuova versione del programma funzioni potrebbe essere molto difficile.

Il motivo per cui il wrapper è così prezioso è che evalin Perl vengono rilevate eccezioni, come (ad esempio) l'eccezione che si ottiene quando si tenta di compilare un errore di sintassi. Poiché si evaltratta di una stringa letterale, la compilazione della stringa avviene in fase di esecuzione e se la letterale non riesce a compilare, l'eccezione risultante viene catturata. Ciò provoca la evalrestituzione di una stringa null e l'impostazione dell'indicatore di errore $@, ma non controlliamo mai neanche (tranne eseguendo occasionalmente la stringa null restituita in alcune versioni mutate del programma). Fondamentalmente, questo significa che se qualcosa dovesse accadere al codice all'internoil wrapper, causando un errore di sintassi, quindi il wrapper farà semplicemente in modo che il codice non faccia nulla (e il programma continuerà a essere eseguito nel tentativo di trovare una copia non danneggiata di se stesso). Pertanto, il codice interno non deve essere quasi a prova di radiazione come il wrapper; tutto ciò che ci interessa è che se danneggiato, agirà in modo identico alla versione non modificata del programma, altrimenti si arresta in modo anomalo (consentendo evaldi rilevare l'eccezione e continuare) o di uscire normalmente senza stampare nulla.

All'interno della confezione

Il codice all'interno del wrapper, fondamentalmente, assomiglia a questo (di nuovo, c'è un controllo _che Stack Exchange non mostrerà immediatamente prima del -+):

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

Questo codice è scritto interamente con caratteri glob-safe e il suo scopo è quello di aggiungere un nuovo alfabeto di segni di punteggiatura che consenta di scrivere un vero programma, attraverso la traslitterazione e la valutazione di una stringa letterale (non possiamo usare 'o "come citazione segni, ma q(... )è anche un modo valido per formare una stringa in Perl). (La ragione del carattere non stampabile è che dobbiamo traslitterare qualcosa nel carattere spaziale senza un carattere letterale nello spazio nel programma; quindi formiamo un intervallo a partire da ASCII 31 e catturiamo lo spazio come secondo elemento dell'intervallo.) ovviamente, se stiamo producendo alcuni personaggi tramite traslitterazione, dobbiamo sacrificare caratteri di traslitterare loro da, ma le lettere maiuscole non sono molto utili ed è molto più facile scrivere senza accesso a quelle che senza accesso ai segni di punteggiatura.

Ecco l'alfabeto dei segni di punteggiatura che diventano disponibili come risultato del glob (la riga superiore mostra la codifica, la riga inferiore il carattere che codifica):

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

In particolare, abbiamo un sacco di segni di punteggiatura che non sono globalmente sicuri ma sono utili nella scrittura di programmi Perl, insieme al carattere spaziale. Ho anche salvato due lettere maiuscole, il letterale Ae Z(che codificano non per se stessi, ma per Te U, perché Aera necessario come endpoint superiore e inferiore); questo ci consente di scrivere le stesse istruzioni di traslitterazione utilizzando il nuovo set di caratteri codificati (sebbene le lettere maiuscole non siano così utili, sono utili per specificare le modifiche alle lettere maiuscole). I personaggi più importanti che non sono disponibili sono [, \e ], ma nessuno è necessario (quando avevo bisogno di una nuova riga nell'output, l'ho prodotta usando la nuova riga implicita dasaypiuttosto che dover scrivere \n; chr 10avrebbe anche funzionato ma è più dettagliato).

Come al solito, dobbiamo preoccuparci di cosa succede se l'interno dell'involucro viene danneggiato all'esterno della stringa letterale. Un corrotto evalimpedirà l'esecuzione di qualsiasi cosa; stiamo bene con quello. Se le virgolette vengono danneggiate, l'interno della stringa non è valido Perl, e quindi il wrapper lo catturerà (e le numerose sottrazioni sulle stringhe significano che anche se tu potessi renderlo valido Perl, non farebbe nulla, il che è un risultato accettabile). Danni al traslitterazione, se non è un errore di sintassi, storpiare la stringa in corso di valutazione, tipicamente causando esso diventi un errore di sintassi; Non sono sicuro al 100% che non ci siano casi in cui questo si rompa, ma al momento lo sto forzando bruscamente per assicurarmene, e dovrebbe essere abbastanza facile da risolvere se ci sono.

Il programma codificato

Guardando all'interno della stringa letterale, invertendo la codifica che ho usato e aggiungendo spazi bianchi per renderla più leggibile, otteniamo questo (di nuovo, immagina un controllo-trattino basso prima di -+, che è codificato come 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

Le persone abituate ai quines riconosceranno questa struttura generale. La parte più cruciale è all'inizio, dove verifichiamo che $ o non sia danneggiato; se i caratteri sono stati cancellati, la sua lunghezza non corrisponde 181, quindi corriamo zzzz((()))il quale, se non è un errore di sintassi a causa di parentesi senza eguali, sarà un errore di runtime, anche se si elimina qualsiasi tre personaggi, perché nessuno di zzzz, zzz, zz, ed zè una funzione e non c'è modo di impedirne l'analisi come funzione se non quella di eliminare (((e causare un errore di sintassi ovvia. Anche il controllo stesso è immune ai danni; la ||possono essere danneggiati a |ma che causerà la zzzz((()))chiamata per eseguire senza condizioni; variabili o costanti dannose causeranno una discrepanza perché stai confrontando una delle 0,180, 179, 178Per l'uguaglianza a un sottoinsieme delle cifre di 181; e rimuoverne uno =causerà un errore di analisi e due =causeranno inevitabilmente che LHS valuti un numero intero 0 o una stringa nulla, entrambi falsi.

Aggiornamento : questo controllo era leggermente sbagliato in una versione precedente del programma, quindi ho dovuto modificarlo per risolvere il problema. La versione precedente era simile al seguente dopo la decodifica:

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

ed è stato possibile eliminare i primi tre segni di punteggiatura per ottenere questo:

lengtho179||zzz((()))

lengtho179, essendo una parola nuda, è veritiero e quindi interrompe il controllo. Ho risolto questo aggiungendo altri due Bcaratteri (che codificano i caratteri dello spazio), il che significa che l'ultima versione della quine fa questo:

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

Ora è impossibile nascondere sia i =segni che il $segno senza produrre un errore di sintassi. (Ho dovuto aggiungere due spazi anziché uno perché una lunghezza di 180avrebbe messo un 0carattere letterale nella fonte, che potrebbe essere abusato in questo contesto per confrontare zero intero con una parola nuda, che ha esito positivo.) Fine aggiornamento

Una volta superato il controllo di lunghezza, sappiamo che la copia non è danneggiata, almeno in termini di eliminazioni di caratteri da esso, quindi è tutto semplice smantellare da lì (sostituzioni di segni di punteggiatura a causa di una tabella di decodifica danneggiata non verrebbero colti da questo controllo , ma ho già verificato tramite brute-force che nessuna delezione dalla sola tabella di decodifica interrompe il quine; presumibilmente la maggior parte di essi causa errori di sintassi). Abbiamo $oin una variabile già, quindi tutto quello che dobbiamo fare è hardcode gli involucri esterni (con qualche piccolo grado di compressione, non ho saltare fuori il parte della domanda del tutto ). Un trucco è che memorizziamo la maggior parte della tabella di codifica$r; possiamo stamparlo letteralmente per generare la sezione della tabella di codifica del wrapper interno o concatenare un po 'di codice attorno ad esso e evalper eseguire il processo di decodifica al contrario (permettendoci di capire qual è la versione codificata di $ o , avendo solo la versione decodificata disponibile a questo punto).

Infine, se fossimo una copia intatta e quindi potessimo produrre l'intero programma originale, chiamiamo exitper evitare che anche le altre copie provino a stampare il programma.

Script di verifica

Non molto carino, ma pubblicandolo perché qualcuno ha chiesto. L'ho eseguito più volte con una varietà di impostazioni (in genere cambiando $mine $maxper verificare varie aree di interesse); non è stato un processo completamente automatizzato. Ha la tendenza a smettere di funzionare a causa del pesante carico della CPU altrove; quando ciò è accaduto, sono appena passato $minal primo valore $xche non è stato completamente controllato e ho continuato a eseguire lo script (assicurando così che tutti i programmi nell'intervallo siano stati controllati alla fine). Ho controllato solo le eliminazioni dalla prima copia del programma, perché è abbastanza ovvio che le eliminazioni dalle altre copie non possono fare di più.

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!";

3
L'OP è un po 'ambiguo; ma ho pensato che il punteggio sarebbe stato (1116 * 1116) / 3.
Greg Martin,

@GregMartin: (1116 * 1116) / 3 è 415152, quindi questa voce vincerebbe comunque in quelle circostanze. Tuttavia, non penso che l'OP possa significare questo perché darebbe pochissimo incentivo per essere in grado di gestire la rimozione di più personaggi. Questo quine può essere inferiore alla metà della lunghezza se ne hai bisogno solo per gestire la rimozione di un personaggio; ciò mi darebbe un efficace ÷ 4 sul punteggio se lo interpretassimo in questo modo, il che supererebbe il ÷ 3 che ottengo da n = 3, e quindi significherebbe che le voci n = 1 meno interessanti hanno effettivamente un punteggio migliore.

2
Ho reso il punteggio più chiaro. Comunque, questo è assolutamente incredibile; non pensavo che nessuno avrebbe avuto n> 1.
takra il

1
Dice qualcosa su Perl che è più facile scrivere un programma senza lettere che senza punteggiatura
Robert Fraser

35

Befunge-98 , 884, n = 14, punteggio ≈ 2.636

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

Provalo online!

Questo non funziona solo quando rimuovi esattamente 14 caratteri, ma anche quando rimuovi qualsiasi importo fino a 14 caratteri.

n = 14può sembrare una scelta molto arbitraria, ma la tecnica che ho usato può in effetti essere utilizzata solo per gli ordini di indurimento delle radiazioni da 1 a 14, ma non facilmente oltre (potrebbe essere possibile ma non ho idea di come). Il quine order-1 è di soli 73 byte (sebbene utilizzi alcuni trucchi da golf che non si applicano a dimensioni maggiori n):

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

Spiegazione

Quando stavo lavorando su questa risposta ho scoperto che è possibile impostare il delta del puntatore dell'istruzione su (2,0)in condizioni di indurimento da radiazione con il seguente frammento:

20020xx

Vedi quella risposta per perché funziona. Ho trovato questo solo con un po 'di armeggi a mano, ma questo ha sollevato la questione se ci sono modelli simili che sono robusti sotto la rimozione di più personaggi. Quindi ho scritto una breve sceneggiatura di Mathematica per cercarli con la forza bruta:

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}
  ] &
];

Questo ha rivelato molto rapidamente uno schema. Per ottenere uno snippet corrispondente che funziona per la rimozione di un massimo di ncaratteri, è possibile utilizzare (m0x){n}m0dove si mtrova n+1ed xè o mo 0. Quindi tutti i seguenti funzionerebbero per la rimozione di un massimo di due caratteri:

30030030
30030330
30330030
30330330

Sono sicuro che è possibile provarlo, ma ho semplicemente verificato nfino a 7. Naturalmente, questo funziona solo fino a quando possiamo rappresentare n+1come una singola cifra e la più grande di tali cifre in Befunge 98 è quella fche rappresenta 15. Ecco perché il mio approccio è limitato n = 14. Se qualcuno trova un modo per impostare il delta in modo affidabile su un valore più grande n+1, sarebbe probabilmente possibile aumentare indefinitamente l'ordine di questo quine indurito dalle radiazioni.

Diamo un'occhiata al codice reale. Ci sono sostanzialmente due parti. Innanzitutto impostiamo il delta (15,0)come ho appena detto:

f00f00f00f00f00f00f00f00f00f00f00f00f00f00f0xxxxxxxxxxxxxxx

E il resto del codice ha ripetuto ogni comando 15 volte e stampa l'origine. Se rimuoviamo la ripetizione, è simile al seguente:

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

Si "tratta di una tecnica di quining 2D standard: avvia la modalità stringa, inserisce tutti i caratteri (tranne se stesso) nello stack e termina di nuovo la modalità stringa dopo averla avvolta. Questo ci aiuta a ottenere tutti i punti di codice della seconda metà, ma non riuscirà a ottenere qualcosa di utile dalla prima metà, perché durante tutto il f00f00...f0bit registrerà solo due caratteri (che possono essere uno fo 0secondo quali caratteri vengono eliminati ). Ma dal momento che quella parte non è composta da personaggi che vengono ripetuti 15 volte, dovremo comunque stamparli separatamente.

Più convenientemente, nel quine non modificato, la lunghezza della stringa prima di "è -1 (mod 15). Ciò garantisce che, indipendentemente da quanti caratteri (fino a 14) rimuoviamo, il numero di caratteri registrati sia sempre 3 (uno xe due di fe 0). Questo è vero per qualsiasi ordine di radiazione fino a 14.

Ora iniziamo stampando la f00f00...f0parte:

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.

Il prossimo 3k$semplicemente elimina 0sia i tre personaggi che sono stati spinti "dall'inizio del programma. Lo stack ora contiene solo i caratteri dopo il "nonché alcuni junk sotto l'originale a f00f00...f0seconda di quali personaggi sono stati eliminati.

Ora abbiamo solo bisogno di invertire la parte superiore della pila (contenente i personaggi rimanenti) e stampare ognuno di essi 15 volte.

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.
;

E questo è tutto. :)


16

JavaScript (ES6), 927 byte, n = 1, punteggio = 859329

nota: non utilizzare un REPL (come una console del browser) per eseguire questo.

Questo è stato scritto prima che la lunghezza del codice fosse un fattore, quindi non è ancora giocata a golf.

Questo è stato molto difficile e merita una spiegazione approfondita. Che scriverò più tardi, dopo aver esplorato un po 'di più questa sfida!

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)//`///`

nota: c'è una nuova riga finale

Fondamentalmente, la prima riga è costruita con cura per rinominare tutti gli "errori di ortografia" setTimeoutin funzioni valide, in modo che se un carattere viene rimosso da una delle setTimeouts il codice non si guasterà e la versione incolume può essere eseguita. È inoltre scritto in modo tale che se un carattere viene rimosso dalla prima riga, non si verificherà alcun errore e il resto del codice potrà essere eseguito senza modifiche.

Il secondo e il terzo blocco sono esattamente equivalenti. Se uno viene eseguito fino al completamento, imposta la _variabile in modo che l'altro sappia di non duplicare il quine. Se uno di questi blocchi si guasta, non influisce sull'altro blocco perché è stato chiamato in modo asincrono setTimeout. L'errore farà sì che _non venga impostato, quindi l'altro blocco si chiuderà correttamente. Il codice principale è in una stringa, che viene controllata per la lunghezza in ciascun blocco per assicurarsi che non ci siano rimozioni.

Le stringhe di modello sulla riga successiva con alcuni commenti alla fine delle stringhe di modello proteggono il codice da errori se uno dei backtick che formano la stringa di modello viene rimosso. Se il backtick finale viene rimosso, la stringa del modello viene terminata dal backtick nel commento. Se il backtick iniziale viene rimosso, setTimeout viene valutato come una funzione non assegnata (no-op) e il codice viene eseguito normalmente, senza setTimeout. Il backtick finale viene annullato da un altro commento.


Che cosa dici? Vuoi provarlo? Non dire più niente!

Modalità a pagina intera consigliata.

Ignora la casella di input, questo snippet non accetta input.

Prova a rimuovere un carattere qualsiasi dal codice!

Non ci credi? Il codice normale continuerà a funzionare (ma non si esaurirà ...) Prova qualcosa di simile console.log(5)!

nota: lo snippet ha dovuto essere leggermente modificato per disabilitare la funzione REPL, quindi ho rimosso più funzionalità di output solo per questa risposta.

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>

Una spiegazione migliore è imminente. Nel frattempo sentitevi liberi di chiamarmi in chat @jrich con commenti / domande / critiche!


ah va bene, whoops: |
Downgoat,

4
Usa thisinvece di window.
Mama Fun Roll,

3
+1 per includere il significato della vita nel tuo codice sorgente
Cyoce,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.